MongoDB
 sql >> Base de données >  >> NoSQL >> MongoDB

Améliorer la structure d'agrégation de MongoDB

​​

MongoDB a récemment présenté sa nouvelle structure d'agrégation. Cette structure offre une solution plus simple pour calculer des valeurs agrégées plutôt que de s'appuyer sur des structures puissantes avec une carte réduite.

Avec seulement quelques primitives simples, il vous permet de calculer, regrouper, façonner et concevoir des documents contenus dans une collection MongoDB particulière. Le reste de cet article décrit la refactorisation de l'algorithme de réduction de carte pour une utilisation optimale de la nouvelle plateforme d'agrégation MongoDB. Le code source complet se trouve dans le référentiel Datatablend GitHub accessible au public.

1. Structure d'agrégation MongoDB

La plate-forme d'agrégation MongoDB est basée sur le concept bien connu de pipeline Linux où la sortie d'une commande est transmise via un convoyeur ou redirigée pour être utilisée comme entrée pour la commande suivante . Dans le cas de MongoDB plusieurs opérateurs sont regroupés en un seul convoyeur qui se charge de traiter le flux de documents.

Certains opérateurs tels que $ match, $ limit et $ skip acceptent le document en entrée et sortent le même document si un certain ensemble de critères est rempli. D'autres opérateurs, tels que $ project et $ unwind, acceptent un seul document comme données d'entrée et modifient son format ou forment plusieurs documents en fonction d'une certaine projection.

L'opérateur de groupe $ accepte finalement plusieurs documents comme données d'entrée et les regroupe dans un seul document en combinant les valeurs correspondantes. Des expressions peuvent être utilisées dans certains de ces opérateurs pour calculer de nouvelles valeurs ou effectuer des opérations sur les chaînes.

Plusieurs opérateurs sont combinés en un seul pipeline, qui s'applique à la liste des documents. Le convoyeur lui-même est exécuté en tant que commande MongoDB, ce qui se traduit par un seul document MongoDB, qui contient un tableau de tous les documents sortis à la fin du convoyeur. Le paragraphe suivant décrit en détail l'algorithme de refactoring de similarité moléculaire en tant que convoyeur d'opérateurs. Assurez-vous de (re)lire les deux articles précédents pour bien comprendre la logique de mise en œuvre.

2. Tuyauterie de similarité moléculaire

Lors de l'application d'un convoyeur à une collection particulière, tous les documents contenus dans cette collection sont transmis en entrée au premier opérateur. Il est recommandé de filtrer cette liste le plus rapidement possible pour limiter le nombre de documents transférés via le pipeline. Dans notre cas, cela signifie filtrer l'intégralité du document qui ne respectera jamais le facteur Tanimoto cible.

Ainsi, dans un premier temps, nous comparons tous les documents pour lesquels le nombre d'empreintes digitales est inférieur à un certain seuil. Si nous ciblons un facteur Tanimoto de 0,8 avec une connexion cible contenant 40 empreintes digitales uniques, l'opérateur de correspondance $ ressemblera à ceci :

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

Seules les connexions avec un nombre d'empreintes digitales de 32 à 50 seront transférées au prochain opérateur de pipeline. Pour effectuer ce filtrage, l'opérateur $ match peut utiliser l'index que nous avons défini pour la propriété fingerprint_count. Pour calculer le coefficient de Tanimoto, nous devons calculer le nombre d'empreintes digitales communes entre une certaine connexion d'entrée et la connexion cible que nous ciblons.

Pour travailler au niveau des empreintes digitales, nous utilisons l'opérateur de déroulement $. $ unwind supprime les éléments du tableau un par un, renvoyant le flux de documents dans lequel le tableau spécifié est remplacé par l'un de ses éléments. Dans notre cas, nous appliquons $ unwind aux empreintes digitales. Par conséquent, chaque document composite se traduira par n documents composites, où n est le nombre d'empreintes digitales uniques contenues dans un document composite.

{"$unwind" :"$fingerprints"}

Pour calculer le nombre d'empreintes digitales communes, nous commencerons par filtrer tous les documents qui n'ont pas les empreintes digitales qui se trouvent sur la liste d'empreintes digitales de la connexion cible. Pour ce faire, nous utilisons à nouveau l'opérateur de correspondance $, cette fois en filtrant la propriété d'empreinte digitale, où seuls les documents contenant une empreinte digitale figurant dans la liste d'empreintes digitales cible sont pris en charge.

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

Étant donné que nous ne faisons correspondre que les empreintes digitales qui se trouvent dans la liste d'empreintes digitales cible, la sortie peut être utilisée pour calculer le nombre total d'empreintes digitales communes.

Pour ce faire, nous appliquons l'opérateur de groupe $ à la connexion composite, bien que nous créions un nouveau type de document contenant le nombre d'empreintes correspondantes (en additionnant le nombre d'occurrences), le nombre total d'empreintes de connexion d'entrée et les smileys.

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

Nous avons maintenant tous les paramètres pour calculer le coefficient de Tanimoto. Pour ce faire, nous allons utiliser l'opérateur de projet $ qui, en plus de copier la propriété composite id et smiles, ajoute également une propriété nouvellement calculée nommée Tanimoto.

{
"$project"
:

{
"_id"
:
1
,

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

"smiles"
:
1

}

}

Puisque nous ne nous intéressons qu'aux connexions qui ont un coefficient cible de Tanimoto de 0,8, nous utilisons l'opérateur optionnel $ match pour filtrer toutes celles qui n'atteignent pas ce coefficient.

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

La commande du pipeline complet se trouve ci-dessous.

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

La sortie de ce pipeline contient une liste de connexions qui ont Tanimoto 0.8 ou supérieur par rapport à une connexion cible particulière. Une représentation visuelle de ce convoyeur peut être trouvée ci-dessous :

3. Conclusion

La nouvelle structure d'agrégation MongoDB fournit un ensemble d'opérateurs faciles à utiliser qui permettent aux utilisateurs d'exprimer plus brièvement des algorithmes de type réduction de carte. Le concept de convoyeur en dessous offre une manière intuitive de traiter les données.

Sans surprise, ce paradigme de pipeline est adopté par diverses approches NoSQL, y compris Gremlin Framework Tinkerpop dans l'implémentation et Cypher Neo4j dans l'implémentation.

En termes de performances, la solution de tuyauterie est une amélioration significative dans la mise en œuvre des cartes de réduction.

Les opérateurs sont initialement pris en charge par la plate-forme MongoDB, ce qui entraîne des améliorations significatives des performances par rapport au Javascript interprété. Étant donné que le cadre d'agrégation peut également fonctionner dans un environnement isolé, il dépasse facilement les performances de mon implémentation d'origine, en particulier lorsque le nombre de connexions d'entrée est élevé et que la cible Tanimoto est faible. Excellentes performances de la commande MongoDB !

Agrégation | MongoDB | Tutoriel