MongoDB наскоро представи своята нова структура за агрегиране. Тази структура предоставя по-просто решение за изчисляване на агрегирани стойности, вместо да се разчита на мощни структури с намалена карта.
Само с няколко прости примитиви, той ви позволява да изчислявате, групирате, оформяте и проектирате документи, които се съдържат в конкретна колекция MongoDB. Останалата част от тази статия описва преструктурирането на алгоритъма за намаляване на картата за оптимално използване на новата платформа за агрегиране на MongoDB. Пълният изходен код може да бъде намерен в публично достъпното хранилище Datablend GitHub.
1. Структура на агрегиране на MongoDB
Платформата за агрегиране на MongoDB се основава на добре познатата концепция на Linux Pipeline, при която изходът от една команда се предава през конвейер или се пренасочва, за да се използва като вход за следващата команда . В случая на MongoDB няколко оператора са комбинирани в един конвейер, който отговаря за обработката на документопотока.
Някои оператори като $ match, $ limit и $ пропускат приемането на документа като вход и извеждането на същия документ, ако е изпълнен определен набор от критерии. Други оператори, като $ project и $ unwind, приемат един документ като входни данни и променят формата му или формират няколко документа въз основа на определена проекция.
Операторът $ group накрая приема няколко документа като входни данни и ги групира в един документ чрез комбиниране на съответните стойности. В някои от тези оператори могат да се използват изрази за изчисляване на нови стойности или за извършване на низови операции.
Няколко оператора са обединени в един тръбопровод, който се отнася за списъка с документи. Самият конвейер се изпълнява като команда MongoDB, което води до един единствен документ на MongoDB, който съдържа масив от всички документи, излезли в края на конвейера. Следващият параграф описва подробно алгоритъма за рефакторинг на молекулярното сходство като конвейер от оператори. Не забравяйте да (пре)прочетете предишните две статии, за да разберете напълно логиката на внедряването.
2. Тръбопроводи с молекулярно сходство
Когато се прилага конвейер към конкретна колекция, всички документи, съдържащи се в тази колекция, се предават като вход на първия оператор. Препоръчително е да филтрирате този списък възможно най-бързо, за да ограничите броя на документите, които се прехвърлят по конвейера. В нашия случай това означава филтриране на целия документ, който никога няма да изпълни целевия фактор Tanimoto.
Ето защо, като първа стъпка, ние сравняваме всички документи, за които броят на пръстовите отпечатъци е в рамките на определен праг. Ако се насочим към фактор Tanimoto от 0,8 с целева връзка, съдържаща 40 уникални пръстови отпечатъка, операторът $ match ще изглежда така:
{"$match" :
{ "fingerprint_count" :{"$gte" :32, "$lte" :50}}.
}
Само връзки с брой пръстови отпечатъци от 32 до 50 ще бъдат прехвърлени към следващия оператор на тръбопровода. За да извърши това филтриране, операторът $ match може да използва индекса, който сме дефинирали за свойството fingerprint_count. За да изчислим коефициента на Танимото, трябва да изчислим броя на общите пръстови отпечатъци между определена входна връзка и целевата връзка, към която сме насочени.
За да работим на ниво пръстов отпечатък, използваме оператора $ unwind. $ unwind премахва елементите на масива един по един, връщайки потока от документи, в който посоченият масив е заменен с един от неговите елементи. В нашия случай прилагаме $ unwind към пръстови отпечатъци. Следователно всеки съставен документ ще доведе до n съставни документа, където n е броят на уникалните пръстови отпечатъци, съдържащи се в съставен документ.
{"$unwind" :"$fingerprints"}
За да изчислим броя на често срещаните пръстови отпечатъци, ще започнем с филтриране на всички документи, които нямат пръстови отпечатъци, които са в списъка с пръстови отпечатъци на целевата връзка. За да направим това, използваме отново оператора $ match, като този път филтрираме свойството на пръстов отпечатък, където се поддържат само документи, които съдържат пръстов отпечатък, който е в целевия списък с пръстови отпечатъци.
{"$match" :
{ "отпечатъци" :
{"$in" :[ 1960 , 15111 , 5186 , 5371 , 756 , 1015 , 1018 , 338 , 325 , 776 , 3900 , ..., 2473] код>
}
}
Тъй като съпоставяме само пръстовите отпечатъци, които са в списъка с целеви пръстови отпечатъци, изходът може да се използва за изчисляване на общия брой често срещани пръстови отпечатъци.
За да направим това, прилагаме оператора $ group към съставната връзка, въпреки че създаваме нов тип документ, съдържащ броя на съвпадащите пръстови отпечатъци (чрез сумиране на броя на срещанията), общия брой пръстови отпечатъци за входна връзка и усмивки.
{"$group" :
{ "_id" :"$compound_cid". ,
"fingerprintmatches" :{"$sum" :1} ,
"totalcount" :{ "$first" :"$fingerprint_count"} ,
"smiles" :{"$first" :"$smiles"}
}
}
Сега имаме всички параметри за изчисляване на коефициента на Танимото. За да направим това, ще използваме оператора $ project, който освен че копира съставното свойство id и усмивки, добавя и новоизчислено свойство на име Tanimoto.
{
„$project“
:
{
"_id"
:
1
,
"танимото"
:
{
„$divide“
:
[
"$fingerprintmatches."
,
{
„$subtract“
:
[
{
„$add“
:
[
40
,
„$totalcount“
]
}
,
„$fingerprintmatches.“
]
}
]
}
,
"усмивки"
:
1
}
}
Тъй като се интересуваме само от връзки, които имат целеви коефициент на Tanimoto от 0,8, ние използваме опционалния оператор $ match, за да филтрираме всички онези, които не достигат този коефициент.
{"$match" :
{ "tanimoto" :{ "$gte" :0.8}
}
Командата за пълния конвейер може да бъде намерена по-долу.
{"aggregate" :"compounds"} ,
"тръбопровод" :[
{"$match" :
{ "fingerprint_count" :{"$gte" :32, "$lte" :50} }
},
{"$unwind" :"$fingerprints"},
{"$match" :
{ "отпечатъци" :
{"$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"] }. ] } ,
"усмивки" :1
}
},
{"$match" :
{"tanimoto" :{"$gte" :0.05} }
} ]
}
Резултатът от този конвейер съдържа списък с връзки, които имат Tanimoto 0.8 или по-висока във връзка с конкретна целева връзка. Визуално представяне на този конвейер може да се намери по-долу:
3. Заключение
Новата структура за агрегиране на MongoDB предоставя набор от лесни за използване оператори, които позволяват на потребителите да изразяват по-кратко алгоритми от тип редукция на карти. Концепцията за конвейер под него предлага интуитивен начин за обработка на данни.
Не е изненадващо, че тази парадигма на тръбопровода е възприета от различни NoSQL подходи, включително Gremlin Framework Tinkerpop при внедряването и Cypher Neo4j при внедряването.
По отношение на производителността, решението за тръбопроводи е значително подобрение в прилагането на картите за намаляване.
Първоначално операторите се поддържат от платформата MongoDB, което води до значителни подобрения в производителността спрямо интерпретирания Javascript. Тъй като Aggregation Framework може да работи и в изолирана среда, тя лесно надвишава производителността на първоначалната ми реализация, особено когато броят на входните връзки е висок и целта на Tanimoto е ниска. Отлично представяне на командата MongoDB!