MongoDB, l'une des principales bases de données NoSQL, est réputée pour ses performances rapides, son schéma flexible, son évolutivité et ses excellentes capacités d'indexation. Les index MongoDB sont au cœur de ces performances rapides. Ils permettent une exécution efficace des requêtes en évitant les analyses de la collection complète et, partant, en limitant le nombre de documents. Les recherches effectuées par MongoDB.
À partir de la version 2.4, MongoDB a commencé avec une fonctionnalité expérimentale prenant en charge Recherche en texte intégral en utilisant Index de texte. Cette fonctionnalité fait désormais partie intégrante du produit (et n'est plus une fonctionnalité expérimentale). Dans cet article, nous allons explorer les fonctionnalités de recherche en texte intégral de MongoDB à partir des principes fondamentaux..
Si vous êtes nouveau sur MongoDB, je vous recommande de lire les articles suivants sur Envato Tuts + qui vous aideront à comprendre les concepts de base de MongoDB:
Avant d'entrer dans les détails, examinons le contexte. La recherche en texte intégral fait référence à la technique de recherche d'un base de données en texte intégral par rapport aux critères de recherche spécifiés par l'utilisateur. Cela ressemble à la façon dont nous recherchons tout contenu sur Google (ou en fait toute autre application de recherche) en saisissant certains mots clés / expressions de chaîne et en récupérant les résultats pertinents triés par leur classement..
Voici quelques scénarios supplémentaires dans lesquels une recherche en texte intégral serait en cours:
chats
en eux ou pour être plus complexe, tous les messages qui ont des commentaires contenant le mot chats
. Avant de poursuivre, vous devez connaître certains termes généraux relatifs à la recherche en texte intégral. Ces termes sont applicables à toute implémentation de recherche de texte intégral (et non spécifique à MongoDB).
Les mots vides sont les mots non pertinents qui doivent être filtrés du texte. Par exemple: a, an, the, is, at, which, etc..
La création de racines est le processus de réduction des mots à leur racine. Par exemple: des mots tels que se tenir debout, se tenir debout, se tenir debout, etc. ont une base commune.
Un classement relatif pour mesurer lequel des résultats de recherche est le plus pertinent.
Avant que MongoDB ne propose le concept des index de texte, nous modélisions nos données pour prendre en charge les recherches par mot clé ou utilisions des expressions régulières pour implémenter de telles fonctionnalités de recherche. Cependant, l’utilisation de l’une de ces approches avait ses propres limites:
Outre ces approches, il existe des solutions alternatives, telles que Elastic Search ou SOLR, pour des applications plus avancées et plus complexes axées sur la recherche. Mais l’utilisation de l’une de ces solutions accroît la complexité architecturale de l’application, car MongoDB doit maintenant communiquer avec une base de données externe supplémentaire..
Notez que la recherche en texte intégral de MongoDB n'est pas proposée en remplacement complet des bases de données de moteurs de recherche telles qu'Elastic, SOLR, etc. Cependant, elle peut être utilisée efficacement pour la majorité des applications construites avec MongoDB aujourd'hui..
A l'aide de la recherche en texte intégral MongoDB, vous pouvez définir un index de texte sur tout champ du document dont la valeur est une chaîne ou un tableau de chaînes. Lorsque nous créons un index de texte sur un champ, MongoDB tokenize et enregistre le contenu du texte du champ indexé, et configure les index en conséquence..
Pour mieux comprendre les choses, passons maintenant à des choses pratiques. Je veux que vous suiviez le tutoriel avec moi en essayant les exemples dans shell mongo. Nous allons d’abord créer des exemples de données que nous utiliserons tout au long de l’article, puis nous discuterons des concepts clés..
Aux fins de cet article, considérons une collection messages
qui stocke des documents de la structure suivante:
"sujet": "Joe a un chien", "contenu": "Les chiens sont les meilleurs amis de l'homme", "aime": 60, "année": 2015, "langue": "anglais"
Insérons quelques exemples de documents en utilisant le insérer
commande pour créer nos données de test:
db.messages.insert ("sujet": "Joe a un chien", "contenu": "Les chiens sont les meilleurs amis de l'homme", "aime": 60, "année": 2015, "langue": "anglais" ) db.messages.insert ("subject": "Les chiens mangent les chats et les chiens mangent aussi les pigeons" "," content ":" Les chats ne sont pas des méchants "," aime ": 30," année ": 2015," langue ": "english") db.messages.insert ("sujet": "Les chats mangent les rats", "content": "Les rats ne cuisinent pas les aliments", "aime": 55, "année": 2014, "langue": "english") db.messages.insert ("subject": "Les rats mangent Joe", "content": "Joe mange un rat", "aime": 75, "année": 2014, "langue": " Anglais")
Un index de texte est créé de manière assez similaire à la façon dont nous créons un index normal, sauf qu’il spécifie la texte
mot clé au lieu de spécifier un ordre croissant / décroissant.
Créer un index de texte sur le assujettir
champ de notre document en utilisant la requête suivante:
db.messages.createIndex ("subject": "text")
Pour tester cet index de texte nouvellement créé sur le assujettir
champ, nous allons rechercher des documents en utilisant le $ text
opérateur. Nous rechercherons tous les documents qui ont le mot clé chiens
dans leurs assujettir
champ.
Étant donné que nous effectuons une recherche de texte, nous souhaitons également obtenir des statistiques sur la pertinence des documents résultants. Pour ce faire, nous utiliserons le $ Meta: "textScore"
expression, qui fournit des informations sur le traitement des données $ text
opérateur. Nous allons également trier les documents par leur textScore
en utilisant le Trier
commander. Un plus textScore
indique une correspondance plus pertinente.
db.messages.find ($ text: $ search: "dogs", score: $ meta: "toextScore"). sort (score: $ meta: "textScore")
La requête ci-dessus renvoie les documents suivants contenant le mot clé chiens
dans leurs assujettir
champ.
"_id": ObjectId ("55f4a5d9b592880356441e94"), "subject": "Les chiens mangent les chats et les chiens mangent aussi les pigeons", "content": "Les chats ne sont pas des méchants", "aime": 30, "année": 2015, "language": "english", "score": 1 "_id": ObjectId ("55f4a5d9b592880356441e93"), "subject": "Joe possède un chien", "content": "Les chiens sont les meilleurs amis de l'homme", " aime ": 60," année ": 2015," langue ":" anglais "," partition ": 0.6666666666666666
Comme vous pouvez le constater, le premier document a un score de 1 (puisque le mot clé chien
apparaît deux fois dans son sujet) par opposition au deuxième document avec un score de 0,66. La requête a également trié les documents renvoyés dans l'ordre décroissant de leur score..
Une question qui peut se poser dans votre esprit est que si nous recherchons le mot clé chiens
, pourquoi le moteur de recherche prend le mot clé chien
(sans 's') en considération? Vous souvenez-vous de notre discussion sur le stemming, où les mots clés de recherche sont réduits à leur base? C’est la raison pour laquelle le mot clé chiens
est réduit à chien
.
Plus souvent qu'autrement, vous utiliserez la recherche de texte sur plusieurs champs d'un document. Dans notre exemple, nous activerons l’indexation de texte composé sur le assujettir
et contenu
des champs. Allez-y et exécutez la commande suivante dans le shell mongo:
db.messages.createIndex ("subject": "text", "content": "text")
Cela a-t-il fonctionné? Non!! La création d'un deuxième index de texte vous donnera un message d'erreur indiquant qu'un index de recherche en texte intégral existe déjà. Pourquoi est-ce? La réponse est que les index de texte sont limités à un seul index par collection. Par conséquent, si vous souhaitez créer un autre index de texte, vous devrez supprimer l'existant et recréer le nouvel..
db.messages.dropIndex ("subject_text") db.messages.createIndex ("subject": "text", "content": "text")
Après avoir exécuté les requêtes de création d’index ci-dessus, essayez de rechercher tous les documents avec un mot clé. chat
.
db.messages.find ($ text: $ search: "cat", score: $ meta: "textScore"). sort (score: $ meta: "textScore")
La requête ci-dessus générerait les documents suivants:
"_id": ObjectId ("55f4af22b592880356441ea4"), "sujet": "Les chiens mangent les chats et les chiens mangent aussi les pigeons", "content": "Les chats ne sont pas méchants", "aime": 30, "année": 2015, "language": "english", "score": 1.3333333333333335 "_id": ObjectId ("55f4af22b592880356441ea5"), "subject": "Les chats mangent les rats", "le contenu": "Les rats ne cuisinent pas les aliments", "aime ": 55 ans," année ": 2014," langue ":" anglais "," partition ": 0.6666666666666666
Vous pouvez voir que la partition du premier document, qui contient le mot clé chat
à la fois assujettir
et contenu
champs, est plus élevé.
Dans le dernier exemple, nous avons mis un index combiné sur le assujettir
et contenu
des champs. Mais il peut exister des scénarios dans lesquels vous souhaitez que le contenu textuel de vos documents soit interrogeable..
Par exemple, envisagez de stocker des courriels dans des documents MongoDB. Dans le cas d'e-mails, tous les champs, y compris l'expéditeur, le destinataire, le sujet et le corps, doivent être interrogeables. Dans de tels scénarios, vous pouvez indexer tous les champs de chaîne de votre document en utilisant le $ **
spécificateur générique.
La requête ressemblerait à ceci (assurez-vous de supprimer l'index existant avant d'en créer un nouveau):
db.messages.createIndex ("$ **": "text")
Cette requête définirait automatiquement des index de texte sur tous les champs de chaîne de nos documents. Pour tester ceci, insérez un nouveau document avec un nouveau champ emplacement
dedans:
db.messages.insert ("sujet": "Les oiseaux peuvent cuisiner", "contenu": "Les oiseaux ne mangent pas de rats", "aime": 12, "année": 2013, emplacement: "Chicago", "langue" :"Anglais")
Maintenant, si vous essayez la recherche de texte avec un mot clé Chicago
(requête ci-dessous), il retournera le document que nous venons d'insérer.
db.messages.find ($ text: $ search: "chicago", score: $ meta: "textScore"). sort (score: $ meta: "textScore")
Quelques points sur lesquels j'aimerais m'attarder:
emplacement
champ après avoir inséré un nouveau document. En effet, nous avons déjà défini un index de texte sur l’ensemble du document à l’aide de la touche $ **
opérateur.Vous pouvez rechercher des expressions telles que «oiseaux intelligents qui aiment cuisiner»en utilisant des index de texte. Par défaut, la recherche par phrase crée une OU recherche sur tous les mots-clés spécifiés, c’est-à-dire qu’il recherchera les documents contenant les mots-clés intelligent
, oiseau
, amour
ou cuisinier
.
db.messages.find ($ text: $ search: "les oiseaux intelligents qui cuisinent", score: $ meta: "text Score"). sort (score: $ meta: "text Score ")
Cette requête produirait les documents suivants:
"_id": ObjectId ("55f5289cb592880356441ead"), "sujet": "Les oiseaux peuvent cuisiner", "contenu": "Les oiseaux ne mangent pas de rats", "aime": 12, "année": 2013, "lieu": "Chicago", "langue": "anglais", "partition": 2 "_id": ObjectId ("55f5289bb592880356441eab"), "sujet": "Les chats mangent les rats", "contenu": "Les rats ne cuisinent pas les aliments "," aime ": 55," année ": 2014," langue ":" anglais "," partition ": 0.6666666666666666
Si vous souhaitez effectuer une recherche de phrase exacte (logique ET), vous pouvez le faire en spécifiant des guillemets dans le texte de recherche.
db.messages.find ($ text: $ search: "\" cook food \ "", score: $ meta: "textScore"). sort (score: $ meta: "textScore ")
Cette requête aboutirait au document suivant, qui contient l'expression «cuire un aliment»:
"_id": ObjectId ("55f5289bb592880356441eab"), "sujet": "Les chats mangent les rats", "le contenu": "Les rats ne cuisinent pas les aliments", "aime": 55, "année": 2014, "langue": "anglais", "partition": 0.6666666666666666
Préfixer un mot clé de recherche avec -
(signe moins) exclut tous les documents contenant le terme nié. Par exemple, essayez de rechercher tout document contenant le mot clé rat
mais ne contient pas des oiseaux
en utilisant la requête suivante:
db.messages.find ($ text: $ search: "rat -birds", score: $ meta: "textScore"). sort (score: $ meta: "textScore" )
Une fonctionnalité importante que je n’ai pas révélée jusqu’à présent est la façon dont vous regardez en coulisses et voyez comment vos mots-clés de recherche sont en cours de suppression, d’arrêter les libellés, d’annuler, etc.. $ expliquer
à la rescousse. Vous pouvez exécuter la requête explicit en passant vrai
en tant que paramètre, ce qui vous donnera des statistiques détaillées sur l'exécution de la requête.
db.messages.find ($ text: $ search: "les chiens qui ne mangent pas les chats mangent des rats \" les chiens mangent \ "-friends", score: $ meta: "textScore"). sort ( score: $ meta: "textScore"). expliquer (vrai)
Si vous regardez le queryPlanner
objet renvoyé par la commande explicit, vous pourrez voir comment MongoDB a analysé la chaîne de recherche donnée. Observez qu'il a négligé les mots vides comme qui
, et à tige chiens
à chien
.
Vous pouvez également voir les termes que nous avons négligés de notre recherche et les expressions que nous avons utilisées dans le texte. parsedTextQuery
section.
"parsedTextQuery": "terms": ["chien", "chat", "ne pas", "mange", "mangé", "rat", "chien", "mange"], "niéTermes": ["ami "]," phrases ": [" les chiens mangent "]," niéPhrases ": []
La requête explicitée sera très utile car nous effectuons des requêtes de recherche plus complexes et voulons les analyser..
Lorsque nous avons des index sur plusieurs champs de notre document, la plupart du temps, un champ sera plus important (c’est-à-dire plus important) que l’autre. Par exemple, lorsque vous effectuez une recherche sur un blog, son titre doit avoir le poids le plus élevé, suivi du contenu du blog..
La pondération par défaut pour chaque champ indexé est 1. Pour affecter des pondérations relatives aux champs indexés, vous pouvez inclure poids
option en utilisant le createIndex
commander.
Comprenons cela avec un exemple. Si vous essayez de chercher le cuisinier
mot clé avec nos index actuels, il en résultera deux documents, qui ont tous deux le même score.
db.messages.find ($ text: $ search: "cook", score: $ meta: "textScore"). sort (score: $ meta: "textScore")
"_id": ObjectId ("55f5289cb592880356441ead"), "sujet": "Les oiseaux peuvent cuisiner", "contenu": "Les oiseaux ne mangent pas de rats", "aime": 12, "année": 2013, "lieu": "Chicago", "langue": "anglais", "partition": 0.6666666666666666 "_id": ObjectId ("55f5289bb592880356441eab"), "sujet": "Les chats mangent les rats", "contenu": "Le rat ne cuisine pas "," aime ": 55," année ": 2014," langue ":" anglais "," partition ": 0.6666666666666666
Modifions maintenant nos index pour inclure des poids. avec le assujettir
champ ayant un poids de 3 contre le contenu
champ ayant un poids de 1.
db.messages.createIndex ("$ **": "text", "poids": sujet: 3, contenu: 1)
Essayez de rechercher un mot clé cuisinier
maintenant, et vous verrez que le document qui contient ce mot-clé dans le assujettir
le champ a un score plus élevé (de 2) que l'autre (qui en a 0,66).
"_id": ObjectId ("55f5289cb592880356441ead"), "sujet": "Les oiseaux peuvent cuisiner", "contenu": "Les oiseaux ne mangent pas de rats", "aime": 12, "année": 2013, "lieu": "Chicago", "langue": "anglais", "partition": 2 "_id": ObjectId ("55f5289bb592880356441eab"), "sujet": "Les chats mangent les rats", "contenu": "Les rats ne cuisinent pas les aliments "," aime ": 55," année ": 2014," langue ":" anglais "," partition ": 0.6666666666666666
Au fur et à mesure que les données stockées dans votre application augmentent, la taille de vos index de texte continue à augmenter également. Avec cette augmentation de la taille des index de texte, MongoDB doit rechercher toutes les entrées indexées chaque fois qu'une recherche de texte est effectuée..
Pour que votre recherche de texte reste efficace avec des index croissants, vous pouvez limiter le nombre d'entrées d'index numérisées en utilisant des conditions d'égalité avec un indicateur standard. $ text
chercher. Un exemple très courant de ceci serait la recherche de tous les articles publiés au cours d’une année / mois donnée, ou la recherche de tous les articles ayant une certaine catégorie / étiquette..
Si vous observez les documents sur lesquels nous travaillons, nous avons un année
champ en eux que nous n'avons pas encore utilisé. Un scénario courant consisterait à rechercher des messages par année, en même temps que la recherche en texte intégral sur laquelle nous nous sommes renseignés..
Pour cela, nous pouvons créer un index composé qui spécifie une clé d’index ascendante / descendante sur année
suivi d'un index de texte sur le assujettir
champ. En faisant cela, nous faisons deux choses importantes:
Supprimez les index que vous avez déjà et créez un nouvel index composé sur (année
, assujettir
):
db.messages.createIndex ("year": 1, "subject": "text")
Exécutez maintenant la requête suivante pour rechercher tous les messages créés en 2015 et contenant le chats
mot-clé:
db.messages.find (year: 2015, $ text: $ search: "cats", score: $ meta: "textScore"). sort (score: $ meta: "textScore" )
La requête ne renverrait qu'un seul document correspondant, comme prévu. Si vous Explique
cette requête et regardez le exécutionStats
, vous trouverez ça totalDocsExamined
1 correspond à la requête, ce qui confirme que notre nouvel index a été utilisé correctement et MongoDB n'a dû numériser qu'un seul document tout en ignorant en toute sécurité tous les autres documents ne relevant pas de 2015..
Nous avons parcouru un long chemin dans cet article en apprenant sur les index de texte. Il existe de nombreux autres concepts que vous pouvez expérimenter avec les index de texte. Mais compte tenu de la portée de cet article, nous ne pourrons pas en discuter en détail aujourd'hui. Néanmoins, examinons brièvement ces fonctionnalités:
$ langue
opérateur. MongoDB prend actuellement en charge environ 15 langues, dont le français, l'allemand, le russe, etc..Gardant à l'esprit le fait que la recherche en texte intégral MongoDB ne remplace pas totalement les bases de données de moteurs de recherche traditionnelles utilisées avec MongoDB, il est recommandé d'utiliser la fonctionnalité native de MongoDB pour les raisons suivantes:
La recherche en texte intégral étant une fonctionnalité relativement nouvelle dans MongoDB, certaines fonctionnalités lui font actuellement défaut. Je les diviserais en trois catégories. Regardons.
$ text
expression, vous ne pouvez pas utiliser $ text
avec $ ni
, vous ne pouvez pas utiliser le allusion()
commande avec $ text
, en utilisant $ text
avec $ ou
a besoin de toutes les clauses de votre $ ou
expression à indexer, etc..La recherche en texte intégral a toujours été l’une des fonctionnalités les plus demandées de MongoDB. Dans cet article, nous avons commencé par une introduction à la recherche en texte intégral, avant de passer aux bases de la création d'index de texte..
Nous avons ensuite exploré l’indexation composée, l’indexation par caractères génériques, la recherche de phrases et la recherche de négations. En outre, nous avons exploré certains concepts importants tels que l'analyse des index de texte, la recherche pondérée et le partitionnement logique de vos index. Nous pouvons nous attendre à des mises à jour majeures de cette fonctionnalité dans les prochaines versions de MongoDB..
Je vous recommande d'essayer la recherche de texte et de partager vos impressions. Si vous l'avez déjà implémenté dans votre application, merci de partager votre expérience ici. Enfin, n'hésitez pas à poster vos questions, réflexions et suggestions sur cet article dans la section commentaires..