MongoDB baru-baru ini memperkenalkan struktur agregasi barunya. Struktur ini memberikan solusi yang lebih sederhana untuk menghitung nilai agregat daripada mengandalkan struktur yang kuat dengan peta yang diperkecil.
Dengan hanya beberapa primitif sederhana, ini memungkinkan Anda untuk menghitung, mengelompokkan, membentuk, dan mendesain dokumen yang terdapat dalam koleksi MongoDB tertentu. Sisa artikel ini menjelaskan pemfaktoran ulang algoritme pengurangan peta untuk penggunaan platform agregasi MongoDB yang baru secara optimal. Kode sumber lengkap dapat ditemukan di repositori Datablend GitHub yang tersedia untuk umum.
1. Struktur agregasi MongoDB
Platform agregasi MongoDB didasarkan pada konsep Linux Pipeline yang terkenal di mana output dari satu perintah ditransmisikan melalui konveyor atau diarahkan untuk digunakan sebagai input untuk perintah berikutnya . Dalam kasus MongoDB beberapa operator digabungkan menjadi satu konveyor yang bertanggung jawab untuk memproses aliran dokumen.
Beberapa operator seperti $ match, $ limit dan $ skip menerima dokumen sebagai input dan output dokumen yang sama jika sekumpulan kriteria tertentu terpenuhi. Operator lain, seperti $ project dan $ unwind, menerima satu dokumen sebagai data input dan mengubah formatnya atau membentuk beberapa dokumen berdasarkan proyeksi tertentu.
Operator $group akhirnya menerima beberapa dokumen sebagai data masukan dan mengelompokkannya ke dalam satu dokumen dengan menggabungkan nilai-nilai yang sesuai. Ekspresi dapat digunakan di beberapa operator ini untuk menghitung nilai baru atau melakukan operasi string.
Beberapa operator digabungkan menjadi satu saluran, yang berlaku untuk daftar dokumen. Konveyor itu sendiri dijalankan sebagai Perintah MongoDB, yang menghasilkan dokumen MongoDB tunggal, yang berisi larik semua dokumen yang keluar di akhir konveyor. Paragraf berikutnya menjelaskan secara rinci algoritma refactoring kesamaan molekuler sebagai pembawa operator. Pastikan untuk (kembali) membaca dua artikel sebelumnya untuk memahami sepenuhnya logika implementasi.
2. Pemipaan kesamaan molekul
Saat menerapkan konveyor ke koleksi tertentu, semua dokumen yang terkandung dalam koleksi tersebut diteruskan sebagai input ke operator pertama. Disarankan agar Anda memfilter daftar ini secepat mungkin untuk membatasi jumlah dokumen yang ditransfer melalui jalur pipa. Dalam kasus kami, ini berarti menyaring seluruh dokumen yang tidak akan pernah memenuhi faktor target Tanimoto.
Oleh karena itu, sebagai langkah awal, kami membandingkan semua dokumen yang jumlah sidik jarinya berada dalam ambang batas tertentu. Jika kita menargetkan faktor Tanimoto sebesar 0,8 dengan koneksi target yang berisi 40 sidik jari unik, operator $ match akan terlihat seperti ini:
{"$match" :
{ "fingerprint_count" : {"$gte" : 32, "$lte" : 50}}.
}
Hanya koneksi dengan jumlah sidik jari dari 32 hingga 50 yang akan ditransfer ke operator pipeline berikutnya. Untuk melakukan pemfilteran ini, operator $ match dapat menggunakan indeks yang kita definisikan untuk properti fingerprint_count. Untuk menghitung koefisien Tanimoto, kita perlu menghitung jumlah sidik jari umum antara koneksi input tertentu dan koneksi target yang kita targetkan.
Untuk bekerja di tingkat sidik jari, kami menggunakan operator $ unwind. $ bersantai menghapus elemen array satu per satu, mengembalikan aliran dokumen di mana array yang ditentukan digantikan oleh salah satu elemennya. Dalam kasus kami, kami menerapkan $ bersantai ke sidik jari. Akibatnya, setiap dokumen komposit akan menghasilkan n dokumen komposit, di mana n adalah jumlah sidik jari unik yang terkandung dalam dokumen komposit.
{"$unwind" :"$fingerprints"}
Untuk menghitung jumlah sidik jari yang umum, kita akan mulai dengan memfilter semua dokumen yang tidak memiliki sidik jari yang ada di daftar sidik jari koneksi target. Untuk melakukan ini, kami menggunakan operator $ match lagi, kali ini memfilter properti sidik jari, di mana hanya dokumen yang berisi sidik jari yang ada dalam daftar sidik jari target yang didukung.
{"$match" :
{ "fingerprints" :
{"$in" : [ 1960 , 15111 , 5186 , 5371 , 756 , 1015 , 1018 , 338 , 325 , 776 , 3900 , ..., 2473] }
}
}
Karena kami hanya mencocokkan sidik jari yang ada di daftar sidik jari target, hasilnya dapat digunakan untuk menghitung jumlah total sidik jari yang umum.
Untuk melakukan ini, kami menerapkan operator $ group ke koneksi komposit, meskipun kami membuat jenis dokumen baru yang berisi jumlah sidik jari yang cocok (dengan menjumlahkan jumlah kemunculan), jumlah total sidik jari koneksi input, dan smiley.
{"$group" :
{ "_id" : "$compound_cid". ,
"fingerprintmatches" : {"$sum" : 1} ,
"totalcount" : { "$first" : "$fingerprint_count"} ,
"smiles" : {"$first" : "$smiles"}
}
}
Sekarang kita memiliki semua parameter untuk menghitung koefisien Tanimoto. Untuk melakukan ini, kita akan menggunakan operator $ project yang, selain menyalin properti komposit id dan smile, juga menambahkan properti yang baru dihitung bernama Tanimoto.
{
"$project"
:
{
"_id"
:
1
,
"tanimoto"
:
{
"$divide"
:
[
"$fingerprintmatches."
,
{
"$subtract"
:
[
{
"$add"
:
[
40
,
"$totalcount"
]
}
,
"$fingerprintmatches."
]
}
]
}
,
"smiles"
:
1
}
}
Karena kami hanya tertarik pada koneksi yang memiliki koefisien target Tanimoto 0,8, kami menggunakan operator pencocokan $ opsional untuk menyaring semua koneksi yang tidak mencapai koefisien ini.
{"$match" :
{ "tanimoto" : { "$gte" : 0.8}
}
Perintah dari pipeline lengkap dapat ditemukan di bawah.
{"aggregate" : "compounds"} ,
"pipeline" : [
{"$match" :
{ "fingerprint_count" : {"$gte" : 32, "$lte" : 50} }
},
{"$unwind" : "$fingerprints"},
{"$match" :
{ "fingerprints" :
{"$in" : [ 1960 , 15111 , 5186 , 5371 , 756 , 1015 , 1018 , 338 , 325 , 776 , 3900,... , 2473] }
}
},
{"$group" :
{ "_id" : "$compound_cid" ,
"fingerprintmatches" : {"$sum" : 1} ,
"totalcount" : { "$first" : "$fingerprint_count"} ,
"smiles" : {"$first" : "$smiles"}
}
},
{"$project" :
{ "_id" : 1 ,
"tanimoto" : {"$divide" : ["$fingerprintmatches"] , { "$subtract" : [ { "$add" : [ 89 , "$totalcount"]} , "$fingerprintmatches"] }. ] } ,
"smiles" : 1
}
},
{"$match" :
{"tanimoto" : {"$gte" : 0.05} }
} ]
}
Output dari pipeline ini berisi daftar koneksi yang memiliki Tanimoto 0.8 atau lebih tinggi dalam kaitannya dengan koneksi target tertentu. Representasi visual dari konveyor ini dapat ditemukan di bawah ini:
3. Kesimpulan
Struktur agregasi MongoDB yang baru menyediakan serangkaian operator yang mudah digunakan yang memungkinkan pengguna untuk mengekspresikan algoritme jenis pengurangan kartu secara lebih singkat. Konsep konveyor di bawahnya menawarkan cara intuitif untuk memproses data.
Tidak heran jika paradigma pipeline ini diadopsi oleh berbagai pendekatan NoSQL, termasuk Gremlin Framework Tinkerpop dalam implementasinya dan Cypher Neo4j dalam implementasinya.
Dalam hal kinerja, solusi perpipaan merupakan peningkatan yang signifikan dalam penerapan peta reduksi.
Operator pada awalnya didukung oleh platform MongoDB, yang mengarah pada peningkatan kinerja yang signifikan atas Javascript yang ditafsirkan. Karena Kerangka Agregasi juga dapat beroperasi di lingkungan yang terisolasi, dengan mudah melebihi kinerja implementasi awal saya, terutama ketika jumlah koneksi input tinggi dan target Tanimoto rendah. Kinerja luar biasa dari perintah MongoDB!