Implémenter la fonctionnalité d'auto-complétion à l'aide de MongoDB recherche
J'ai un MongoDB
collection de documents de la forme
{
"id": 42,
"title": "candy can",
"description": "canada candy canteen",
"brand": "cannister candid",
"manufacturer": "candle canvas"
}
Je besoin pour implémenter la fonctionnalité d'auto-complétion en fonction du terme de recherche par la mise en correspondance dans les champs à l'exception id
. Par exemple, si l'entrée terme est can
, alors je doit retourner tous les mots dans le document
{ hints: ["candy", "can", "canada", "canteen", ...]
J'ai regardé cette question mais il n'a pas aidé. J'ai aussi essayé de chercher comment faire regex
de recherche dans de multiples domaines et de l'extrait de correspondance des jetons ou de l'extraction de l'appariement des jetons dans un MongoDB text search
mais je ne trouve pas d'aide.
Ce haut lieu de répondre à cette question suggère (expression régulière avec de commencer-de-la chaîne de l'ancre) serait exactement ce que je vous recommande de le faire. Pourquoi, justement, n'est-ce pas à résoudre votre problème?
Mais il fonctionne quand on le recherche dans un seul domaine. Aussi, je n'ai pas de tableau pour la recherche, c'est une chaîne. Me conseillez-vous de marquer tous les champs que je veux correspondre, et de stocker ces jetons dans un tableau?
Que serait certainement à la plupart des requêtes de solution à l'amiable (pas très accueillante pour les mises à jour, tout de même)
Ce n'est vraiment sonner comme un cas d'utilisation pour la recherche de texte. Vous avez dit que vous n'avez pas trouvé quelque chose d'utile à ce sujet. Un bon début de référence pour la recherche en texte intégral est le Mongo DBA cours vidéo à ce sujet via youtube (youtube.com/...).
Avec la recherche de texte, j'ai besoin d'extraire le (partiellement) correspondant à jetons. Je ne pouvais pas trouver l'aide à ce sujet.
Mais il fonctionne quand on le recherche dans un seul domaine. Aussi, je n'ai pas de tableau pour la recherche, c'est une chaîne. Me conseillez-vous de marquer tous les champs que je veux correspondre, et de stocker ces jetons dans un tableau?
Que serait certainement à la plupart des requêtes de solution à l'amiable (pas très accueillante pour les mises à jour, tout de même)
Ce n'est vraiment sonner comme un cas d'utilisation pour la recherche de texte. Vous avez dit que vous n'avez pas trouvé quelque chose d'utile à ce sujet. Un bon début de référence pour la recherche en texte intégral est le Mongo DBA cours vidéo à ce sujet via youtube (youtube.com/...).
Avec la recherche de texte, j'ai besoin d'extraire le (partiellement) correspondant à jetons. Je ne pouvais pas trouver l'aide à ce sujet.
OriginalL'auteur ajay | 2015-04-27
Vous devez vous connecter pour publier un commentaire.
tl;dr
Il n'y a pas de solution facile pour ce que vous voulez, étant donné que les requêtes ne peuvent pas modifier les champs de leur retour. Il y a une solution (à l'aide de la ci-dessous mapReduce inline au lieu de faire une sortie d'une collection), mais, sauf pour les très petites bases de données, il n'est pas possible de le faire en temps réel.
Le problème
Comme l'écrit, une normale de requête ne peut pas vraiment modifier les champs, il renvoie. Mais il y a d'autres problèmes. Si vous voulez faire une regex de recherche dans les à mi-chemin décent de temps, vous aurez à index tous champs, qui aurait besoin d'un montant disproportionné de RAM pour de la fonctionnalité. Si vous n'avez pas d'index tous des champs, un regex de recherche serait la cause d'une collection de numérisation, ce qui signifie que chaque document devra être chargé à partir du disque, ce qui prendrait trop de temps pour l'auto-complétion pour être pratique. En outre, plusieurs utilisateurs simultanés demandant d'auto-complétion reviendrait à créer une grande charge sur le backend.
La solution
Le problème est assez similaire à j'ai déjà répondu: Nous avons besoin d'extraire tous les mots de plusieurs champs, supprimer la stop paroles et enregistrez le reste des mots avec un lien vers le document en question(s), le mot a été trouvé dans une collection. Maintenant, pour obtenir une liste d'auto-complétion, nous avons tout simplement requête de l'indexation de la liste de mots.
Étape 1: Utiliser une carte, à en réduire l'emploi d'extraire les mots
L'exécution de cette mapReduce contre votre exemple entraînerait
db.words
ressembler à ceci:Noter que les paroles individuelles sont les
_id
des documents. Le_id
champ est indexé automatiquement par MongoDB. Depuis indices sont essayé d'être conservé dans la mémoire vive, on peut faire quelques trucs à la fois d'accélérer l'auto-complétion et de réduire la charge sur le serveur.Étape 2: Requête pour l'autocomplétion
Pour l'autocomplétion, nous avons seulement besoin de mots, sans les liens vers les documents.
Puisque les mots sont indexés, nous utilisons un requête couverte – une requête répondu seulement à partir de l'index, qui réside habituellement dans la mémoire RAM.
À s en tenir à votre exemple, nous pourrions utiliser la requête suivante pour obtenir les candidats à l'auto-complétion:
qui nous donne le résultat
À l'aide de la
.explain()
méthode, on peut vérifier que cette requête utilise uniquement l'index.Note le
indexOnly:true
champ.Étape 3: la Requête du document,
Quoique nous n'en aurez à faire deux requêtes pour obtenir le document en lui-même, depuis que nous avons d'accélérer l'ensemble du processus, l'expérience utilisateur doit être assez bien.
Étape 3.1: Obtenir le document de la
words
collectionLorsque l'utilisateur sélectionne un choix de l'auto-complétion, nous devons nous interroger le document complet de mots dans l'ordre pour trouver les documents où le mot choisi pour l'auto-complétion est originaire de.
qui devrait aboutir à un document comme ceci:
Étape 3.2: Obtenir le document réel
Avec ce document, nous pouvons maintenant afficher une page avec les résultats de la recherche ou, comme dans ce cas, la redirection vers le document que vous pouvez obtenir par:
Notes
Bien que cette approche peut paraître compliqué au premier abord (le bien, le mapReduce est un peu), il est vrai assez facile sur le plan conceptuel. Fondamentalement, vous faites du commerce des résultats en temps réel (que vous n'aurez pas de toute façon à moins de dépenser une beaucoup de RAM) pour la vitesse. À mon humble avis, c'est une bonne affaire. Afin de rendre le coût assez élevé mapReduce la phase la plus efficace, la mise en œuvre de Différentiels mapReduce pourrait être une approche – l'amélioration de mon il est vrai piraté mapReduce pourrait bien être un autre.
Dernier mais non le moindre, de cette façon est plutôt moche hack tout à fait. Vous pourriez voulez plonger dans elasticsearch ou lucene. Ces produits à mon humble avis sont beaucoup, beaucoup plus adapté pour ce que vous voulez.
Content d'avoir pu aider. Pour être honnête avec vous, c'était une belle apprenti pièce. Veuillez noter que les élastiques de recherche ne donne pas de résultats en temps réel, mais vous n'obtiendrez pas plus proche d'eux, à mon humble avis.
pour lesquels des données de tailles de la solution est-elle bonne? J'ai un dictionnaire avec 1 million de cordes, qui se composent principalement d'un ou deux mots (en moyenne 12 caractères), le tout fonctionnant sur le plus petit google cloud machine
Avec un différentiel de carte de réduire, nous sommes limité par la RAM et le disque de la taille seulement. 1M * 12 Octets = 12 MO. Permet de même le double, et nous sommes encore parler d'un négligeable de la consommation de RAM. Mais comme toujours: vous avez à tester. Indice de compression, disponible dès 3.0 lorsque vous utilisez wiredTiger, peut aider à ici. Mais pour être honnête, je n'ai pas couru les points de repère ou testé la consommation. Je dois l'avouer, vous êtes à peu près sur votre propre, mais je serai heureux de vous aider.
OriginalL'auteur Markus W Mahlberg