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

Optimisation des requêtes MongoDB

Ce que vous voulez, c'est un résultat de "recherche à facettes" dans lequel vous détenez les statistiques sur les termes correspondants dans l'ensemble de résultats actuel. Par la suite, bien qu'il existe des produits qui "semblent" faire tout le travail en une seule réponse, vous devez considérer que la plupart des moteurs de stockage génériques vont nécessiter plusieurs opérations.

Avec MongoDB, vous pouvez utiliser deux requêtes pour obtenir les résultats eux-mêmes et une autre pour obtenir les informations sur les facettes. Cela donnerait des résultats similaires aux résultats à facettes disponibles à partir de moteurs de recherche dédiés comme Solr ou ElasticSearch.

Mais pour le faire efficacement, vous souhaitez l'inclure dans votre document de manière à ce qu'il puisse être utilisé efficacement. Un formulaire très efficace pour ce que vous voulez consiste à utiliser un tableau de données tokenisées :

 {
     "otherData": "something",
     "facets": [
         "country:UK",
         "city:London-UK",
         "genre:Student"
     ]
 }

Ainsi, "factets" est un champ unique dans votre document et non à plusieurs endroits. Cela facilite l'indexation et les requêtes. Vous pouvez ensuite agréger efficacement vos résultats et obtenir les totaux pour chaque facette :

User.aggregate(
    [
        { "$unwind": "$facets" },
        { "$group": {
            "_id": "$facets",
            "count": { "$sum": 1 }
        }}
    ],
    function(err,results) {

    }
);

Ou plus idéalement avec quelques critères dans $match :

User.aggregate(
    [
        { "$match": { "facets": { "$in": ["genre:student"] } } },
        { "$unwind": "$facets" },
        { "$group": {
            "_id": "$facets",
            "count": { "$sum": 1 }
        }}
    ],
    function(err,results) {

    }
);

En fin de compte, donner une réponse comme :

{ "_id": "country:FR", "count": 50 },
{ "_id": "country:UK", "count": 300 },
{ "_id": "city:London-UK", "count": 150 },
{ "_id": "genre:Student": "count": 500 }

Une telle structure est facile à parcourir et à inspecter pour des éléments tels que le "pays" discret et la "ville" qui appartient à un "pays" car ces données sont simplement séparées de manière cohérente par un trait d'union "-".

Essayer de mélanger des documents dans des tableaux est une mauvaise idée. Il y a une limite de taille BSON de 16 Mo à respecter également, à partir de laquelle le mélange des résultats (surtout si vous essayez de conserver le contenu du document) finira très certainement par être dépassé dans la réponse.

Pour quelque chose d'aussi simple que d'obtenir le "nombre global" de résultats d'une telle requête, il suffit de résumer les éléments d'un type de facette particulier. Ou envoyez simplement vos mêmes arguments de requête à un .count() opération :

User.count({ "facets": { "$in": ["genre:Student"] } },function(err,count) {

});

Comme indiqué ici, en particulier lors de la mise en œuvre de la "pagination" des résultats, les rôles d'obtention du "Nombre de résultats", du "Nombre de facettes" et de la "Page de résultats" réelle sont tous délégués à des requêtes "séparées" au serveur.

Il n'y a rien de mal à soumettre chacune de ces requêtes au serveur en parallèle, puis à combiner une structure pour alimenter votre modèle ou votre application ressemblant beaucoup au résultat de recherche à facettes de l'un des produits de moteur de recherche qui offre ce type de réponse.

Conclusion

Mettez donc quelque chose dans votre document pour marquer les facettes en un seul endroit. Un tableau de chaînes tokenisées fonctionne bien à cette fin. Cela fonctionne également bien avec les formulaires de requête tels que $in et $all pour les conditions "ou" ou "et" sur les combinaisons de sélection de facettes.

N'essayez pas de mélanger les résultats ou d'imbriquer les ajouts juste pour correspondre à une structure hiérarchique perçue, mais plutôt parcourir les résultats reçus et utiliser des modèles simples dans les jetons. C'est très simple de

Exécutez des requêtes paginées pour le contenu en tant que requêtes distinctes pour les facettes ou les décomptes globaux. Essayer de pousser tout le contenu dans des tableaux, puis limiter juste pour obtenir des nombres n'a pas de sens. La même chose s'appliquerait à une solution RDBMS pour faire la même chose, où le résultat de la pagination compte et la page actuelle sont des opérations de requête distinctes.

Il y a plus d'informations écrites sur le blog MongoDB sur la recherche à facettes avec MongoDB qui explique également d'autres options. Il existe également des articles sur l'intégration avec des solutions de recherche externes utilisant mongoconnector ou d'autres approches.