MongoDB
 sql >> Datenbank >  >> NoSQL >> MongoDB

Verbessern Sie die Aggregationsstruktur von MongoDB

​​

MongoDB hat kürzlich seine neue Aggregationsstruktur eingeführt. Diese Struktur bietet eine einfachere Lösung zur Berechnung aggregierter Werte, anstatt sich auf leistungsstarke Strukturen mit einer reduzierten Karte zu verlassen.

Mit nur wenigen einfachen Grundelementen können Sie Dokumente berechnen, gruppieren, formen und entwerfen, die in einer bestimmten MongoDB-Sammlung enthalten sind. Der Rest dieses Artikels beschreibt das Refactoring des Kartenreduktionsalgorithmus für eine optimale Nutzung der neuen MongoDB-Aggregationsplattform. Der vollständige Quellcode befindet sich im öffentlich zugänglichen Datablend GitHub-Repository.

1. MongoDB-Aggregationsstruktur

Die MongoDB-Aggregationsplattform basiert auf dem bekannten Linux-Pipeline-Konzept, bei dem die Ausgabe eines Befehls über einen Förderer übertragen oder umgeleitet wird, um als Eingabe für den nächsten Befehl verwendet zu werden . Im Fall von MongoDB werden mehrere Operatoren zu einem einzigen Förderer zusammengefasst, der für die Verarbeitung des Dokumentenflusses verantwortlich ist.

Einige Operatoren wie $match, $limit und $skip akzeptieren das Dokument als Eingabe und geben dasselbe Dokument aus, wenn ein bestimmter Satz von Kriterien erfüllt ist. Andere Operatoren wie $ project und $ unwind akzeptieren ein einzelnes Dokument als Eingabedaten und ändern sein Format oder bilden mehrere Dokumente basierend auf einer bestimmten Projektion.

Der Gruppenoperator $ akzeptiert schließlich mehrere Dokumente als Eingabedaten und gruppiert sie zu einem Dokument, indem er die entsprechenden Werte kombiniert. In einigen dieser Operatoren können Ausdrücke verwendet werden, um neue Werte zu berechnen oder Zeichenfolgenoperationen auszuführen.

Mehrere Operatoren werden zu einer einzigen Pipeline kombiniert, die für die Liste der Dokumente gilt. Das Conveyor selbst wird als MongoDB-Befehl ausgeführt, was zu einem einzigen MongoDB-Dokument führt, das ein Array aller Dokumente enthält, die am Ende des Conveyors ausgegeben wurden. Der nächste Absatz beschreibt im Detail den Refactoring-Algorithmus der molekularen Ähnlichkeit als Übermittler von Operatoren. Lesen Sie unbedingt die beiden vorherigen Artikel (erneut), um die Implementierungslogik vollständig zu verstehen.

2. Piping molekularer Ähnlichkeit

Wenn ein Förderer auf eine bestimmte Sammlung angewendet wird, werden alle in dieser Sammlung enthaltenen Dokumente als Eingabe an den ersten Bediener weitergeleitet. Es wird empfohlen, diese Liste so schnell wie möglich zu filtern, um die Anzahl der Dokumente zu begrenzen, die über die Pipeline übertragen werden. In unserem Fall bedeutet dies, dass das gesamte Dokument gefiltert wird, das niemals den angestrebten Tanimoto-Faktor erreichen wird.

Daher vergleichen wir in einem ersten Schritt alle Dokumente, bei denen die Anzahl der Fingerabdrücke innerhalb einer bestimmten Schwelle liegt. Wenn wir einen Tanimoto-Faktor von 0,8 mit einer Zielverbindung anstreben, die 40 eindeutige Fingerabdrücke enthält, sieht der Match-Operator $ so aus:

{"$match" :
{ "fingerprint_count" : {"$gte" : 32, "$lte" : 50}}.
}

Nur Verbindungen mit einer Anzahl von Fingerabdrücken von 32 bis 50 werden an den nächsten Pipeline-Betreiber übertragen. Um diese Filterung durchzuführen, kann der Match-Operator $ den Index verwenden, den wir für die Eigenschaft „fingerprint_count“ definiert haben. Um den Tanimoto-Koeffizienten zu berechnen, müssen wir die Anzahl gemeinsamer Fingerabdrücke zwischen einer bestimmten Eingangsverbindung und der Zielverbindung, auf die wir abzielen, berechnen.

Um auf Fingerabdruckebene zu arbeiten, verwenden wir den Unwind-Operator $. $ unwind entfernt die Array-Elemente eines nach dem anderen und gibt den Dokumentstrom zurück, in dem das angegebene Array durch eines seiner Elemente ersetzt wurde. In unserem Fall wenden wir $unwind auf Fingerabdrücke an. Folglich führt jedes zusammengesetzte Dokument zu n zusammengesetzten Dokumenten, wobei n die Anzahl der eindeutigen Fingerabdrücke ist, die in einem zusammengesetzten Dokument enthalten sind.

{"$unwind" :"$fingerprints"}

Um die Anzahl gemeinsamer Fingerabdrücke zu berechnen, filtern wir zunächst alle Dokumente, die nicht die Fingerabdrücke haben, die auf der Fingerabdruckliste der Zielverbindung stehen. Dazu verwenden wir erneut den $-Match-Operator, diesmal filtern wir die Fingerabdruck-Eigenschaft, wobei nur Dokumente unterstützt werden, die einen Fingerabdruck enthalten, der in der Ziel-Fingerabdruck-Liste enthalten ist.

{"$match" :
{ "fingerprints" :
{"$in" : [ 1960 , 15111 , 5186 , 5371 , 756 , 1015 , 1018 , 338 , 325 , 776 , 3900 , ..., 2473] }
}
}

Da wir nur die Fingerabdrücke abgleichen, die in der Zielfingerabdruckliste enthalten sind, kann die Ausgabe verwendet werden, um die Gesamtzahl gemeinsamer Fingerabdrücke zu berechnen.

Dazu wenden wir den Gruppenoperator $ auf die zusammengesetzte Verbindung an, obwohl wir einen neuen Dokumenttyp erstellen, der die Anzahl der übereinstimmenden Fingerabdrücke (durch Addieren der Anzahl der Vorkommen), die Gesamtzahl der Fingerabdrücke der Eingabeverbindung und Smileys enthält.

{"$group" :
{ "_id" : "$compound_cid". ,
"fingerprintmatches" : {"$sum" : 1} ,
"totalcount" : { "$first" : "$fingerprint_count"} ,
"smiles" : {"$first" : "$smiles"}
}
}

Jetzt haben wir alle Parameter, um den Tanimoto-Koeffizienten zu berechnen. Dazu verwenden wir den $-Projektoperator, der zusätzlich zum Kopieren der zusammengesetzten Eigenschaft id und smiles auch eine neu berechnete Eigenschaft namens Tanimoto hinzufügt.

{
"$project"
:

{
"_id"
:
1
,

"tanimoto"
:
{
"$divide"
:
[
"$fingerprintmatches."
,
{
"$subtract"
:
[
{
"$add"
:
[
40
,
"$totalcount"
]
}
,
"$fingerprintmatches."
]
}
]
}
,

"smiles"
:
1

}

}

Da wir nur an Verbindungen interessiert sind, die einen Tanimoto-Zielkoeffizienten von 0,8 haben, verwenden wir den optionalen Match-Operator $, um alle Verbindungen herauszufiltern, die diesen Koeffizienten nicht erreichen.

{"$match" :
{ "tanimoto" : { "$gte" : 0.8}
}

Der Befehl der kompletten Pipeline ist unten zu finden.

{"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} }
} ]
}

Die Ausgabe dieser Pipeline enthält eine Liste von Verbindungen, die Tanimoto 0.8 oder höher in Bezug auf eine bestimmte Zielverbindung haben. Eine visuelle Darstellung dieses Förderers finden Sie unten:

3. Fazit

Die neue MongoDB-Aggregationsstruktur bietet eine Reihe benutzerfreundlicher Operatoren, die es Benutzern ermöglichen, Algorithmen des Kartenreduktionstyps kürzer auszudrücken. Das Konzept eines Förderers darunter bietet eine intuitive Möglichkeit, Daten zu verarbeiten.

Es überrascht nicht, dass dieses Pipeline-Paradigma von verschiedenen NoSQL-Ansätzen übernommen wird, darunter Gremlin Framework Tinkerpop in der Implementierung und Cypher Neo4j in der Implementierung.

In Bezug auf die Leistung ist die Rohrleitungslösung eine deutliche Verbesserung bei der Umsetzung der Reduktionskarten.

Operatoren werden zunächst von der MongoDB-Plattform unterstützt, was zu erheblichen Leistungsverbesserungen gegenüber dem interpretierten Javascript führt. Da das Aggregation Framework auch in einer isolierten Umgebung betrieben werden kann, übertrifft es leicht die Leistung meiner ursprünglichen Implementierung, insbesondere wenn die Anzahl der Eingabeverbindungen hoch und das Tanimoto-Ziel niedrig ist. Ausgezeichnete Leistung des MongoDB-Befehls!

Aggregation | MongoDB | Anleitung