MongoDB, una dintre cele mai importante baze de date NoSQL, este binecunoscută pentru performanța sa rapidă, schema flexibilă, scalabilitatea și capacitățile excelente de indexare. În centrul acestei performanțe rapide se află indicii MongoDB, care sprijină executarea eficientă a interogărilor prin evitarea scanărilor complete și prin urmare limitarea numărului de căutări ale documentelor MongoDB.
Pornind de la versiunea 2.4, MongoDB a început cu ajutorul unei caracteristici experimentale Căutarea în întregul text utilizând Indicii de text. Această caracteristică a devenit acum o parte integrantă a produsului (și nu mai este o caracteristică experimentală). În acest articol vom explora funcționalitățile full-text de căutare ale MongoDB chiar de la fundamentale.
Dacă sunteți nou la MongoDB, vă recomand să citiți următoarele articole despre Envato Tuts + care vă vor ajuta să înțelegeți conceptele de bază ale MongoDB:
Înainte de a intra în detalii, să ne uităm la un anumit fundal. Căutarea full-text se referă la tehnica de căutare a text complet de date în funcție de criteriile de căutare specificate de utilizator. Este ceva asemănător cu modul în care căutăm orice conținut de pe Google (sau de fapt orice altă aplicație de căutare) prin introducerea anumitor cuvinte cheie / fraze și ștergerea rezultatelor relevante sortate după clasarea lor.
Iată câteva scenarii în care se va întâmpla o căutare de text întreg:
pisici
în ele; sau să fie mai complexe, toate posturile care au comentarii care conțin cuvântul pisici
. Înainte de a merge mai departe, există anumiți termeni generali referitori la căutarea full-text pe care ar trebui să o cunoașteți. Acești termeni se aplică oricărei implementări de căutare fulltext (și nu MongoDB specifice).
Cuvintele stop sunt cuvintele irelevante care trebuie filtrate dintr-un text. De exemplu: a, un, este, la, care, etc.
Stemming este procesul de reducere a cuvintelor la tulpina lor. De exemplu: cuvinte cum ar fi picioarele, standurile, picioarele etc. au un stand comun de bază.
O clasare relativă pentru a măsura care dintre rezultatele căutării este cea mai relevantă.
Înainte ca MongoDB să vină cu conceptul de indexuri de text, vom modela datele noastre pentru a sprijini căutările de cuvinte cheie sau pentru a folosi expresii regulate pentru implementarea unor astfel de funcționalități de căutare. Cu toate acestea, folosirea oricăreia dintre aceste abordări a avut propriile limitări:
În afară de aceste abordări, pentru aplicații mai avansate și mai complexe în funcție de căutare, există soluții alternative cum ar fi Elastic Search sau SOLR. Dar folosind oricare dintre aceste soluții crește complexitatea arhitecturală a aplicației, deoarece MongoDB trebuie să discute cu o bază de date externă suplimentară.
Rețineți că căutarea integrală a textului de către MongoDB nu este propusă ca o înlocuire completă a bazelor de date ale motoarelor de căutare, cum ar fi Elastic, SOLR etc. Cu toate acestea, aceasta poate fi utilizată în mod eficient pentru majoritatea aplicațiilor construite astăzi cu MongoDB.
Folosind căutarea full-text MongoDB, puteți defini un index text pe orice câmp din document a cărui valoare este un șir sau un șir de șiruri de caractere. Atunci când creăm un index text pe un câmp, MongoDB tokenizes și sfârșește conținutul textului câmpului indexat și stabilește indexurile în mod corespunzător.
Pentru a înțelege lucrurile în continuare, să ne aruncăm acum câteva lucruri practice. Vreau să urmați tutorialul cu mine încercând exemplele din coajă mongo. Vom crea mai întâi câteva exemple de date pe care le vom folosi în întregul articol, apoi vom trece mai departe pentru a discuta conceptele cheie.
În sensul prezentului articol, luați în considerare o colecție mesaje
care stochează documente cu următoarea structură:
"subiect": "Joe posedă un câine", "conținut": "Câinii sunt cel mai bun prieten al omului", "place": 60, "an": 2015, "language": "english"
Să introducem câteva exemple de documente folosind introduce
comandați-ne pentru a crea datele noastre de testare:
db.messages.insert ("subiect": "Joe posedă un câine", "conținut": "Câinii sunt cel mai bun prieten al omului", "place": 60, "anul": 2015, "limba": engleză " ) db.messages.insert ("subject": "Câini mănâncă pisici și câini mănâncă și porumbei", "content": "Pisicile nu sunt rele", "likes": 30, "year": 2015; "englezesc") db.messages.insert ("subiect": "Pisici mănâncă șobolani", "conținut": "Șobolani nu gătesc alimente", "place": 55; "Engleză") db.messages.insert ("subiect": "Șobolani mănâncă Joe", "conținut": "Joe a mâncat un șobolan" Engleză")
Se creează un index text similar cu modul în care creăm un index regulat, cu excepția faptului că specifică text
în loc să specificați o ordine ascendentă / descendentă.
Creați un index text pe subiect
câmpul documentului nostru folosind următoarea interogare:
db.messages.createIndex ( "subiect": "text")
Pentru a testa acest index nou creat pe subiect
câmp, vom căuta documente folosind $ Text
operator. Vom căuta toate documentele care au cuvântul cheie câini
în lor subiect
camp.
Din moment ce efectuăm o căutare text, suntem, de asemenea, interesați de obținerea unor statistici despre cât de relevante sunt documentele rezultate. În acest scop, vom folosi $ Meta: "textScore"
expresie, care oferă informații despre prelucrarea $ Text
operator. De asemenea, vom sorta documentele prin intermediul lor textScore
folosind fel
comanda. O mai mare textScore
indică o potrivire mai relevantă.
db.messages.find ($ text: $ search: "câini", scor: $ meta: "toextScore") sortați (scor: $ meta: "textScore")
Interogarea de mai sus returnează următoarele documente care conțin cuvântul cheie câini
în lor subiect
camp.
"_id": ObjectId ("55f4a5d9b592880356441e94"), "subject": "Câini mănâncă pisici și câini mănâncă și porumbei", "content": " "câinele este cel mai bun prieten al omului", "câinele este cel mai bun prieten al omului", " place ": 60," an ": 2015," limbă ":" engleză "," scor ": 0.6666666666666666
După cum puteți vedea, primul document are un scor de 1 (de la cuvântul cheie câine
apare de două ori în subiectul său), spre deosebire de cel de-al doilea document cu un scor de 0,66. De asemenea, interogarea a sortat documentele returnate în ordinea descrescătoare a scorului lor.
O singură întrebare care ar putea apărea în mintea dvs. este că dacă căutăm cuvântul cheie câini
, de ce este motorul de căutare este de luare a cuvântului cheie câine
(fără "s")? Amintiți-vă discuția noastră cu privire la stopming, în cazul în care orice cuvinte cheie de căutare sunt reduse la baza lor? Acesta este motivul pentru care cuvântul cheie câini
este redus la câine
.
De cele mai multe ori, veți utiliza căutarea pe mai multe câmpuri ale unui document. În exemplul nostru, vom permite indexarea textului compus pe subiect
și conţinut
câmpuri. Mergeți mai departe și executați următoarea comandă în shell mongo:
db.messages.createIndex ( "subiect": "text", "conținut": "text")
A funcționat? Nu!! Crearea unui al doilea index de text vă va oferi un mesaj de eroare care spune că există deja un index de căutare în format întreg. De ce este așa? Răspunsul este că indiciile de text vin cu o limitare a unui singur index de text per colecție. Prin urmare, dacă doriți să creați un alt index de text, va trebui să renunțați la cel existent și să creați unul nou.
db.messages.dropIndex ("subject_text") db.messages.createIndex ("subiect": "text", "conținut": "text"
După ce ați executat interogările de creare a indexului de mai sus, încercați să căutați toate documentele cu cuvântul cheie pisică
.
db.messages.find ($ text: $ search: "cat", scor: $ meta: "textScore") sort ($ meta: "textScore")
Interogarea de mai sus va afișa următoarele documente:
"_id": ObjectId ("55f4af22b592880356441ea4"), "subject": "Câini mănâncă pisici și câine mănâncă și porumbei", "content": " "limba": "engleză", "scor": "1.3333333333333335 " _id ": ObjectId (" 55f4af22b592880356441ea5 ")," subject ":" Pisici mănâncă șobolani " ": 55," an ": 2014," limbă ":" engleză "," scor ": 0.6666666666666666
Puteți observa scorul primului document, care conține cuvântul cheie pisică
în ambele subiect
și conţinut
câmpuri, este mai mare.
În ultimul exemplu, am pus un index combinat pe subiect
și conţinut
câmpuri. Dar pot exista scenarii în care doriți ca orice document text din documentele dvs. să poată fi căutat.
De exemplu, luați în considerare stocarea e-mailurilor în documentele MongoDB. În cazul e-mailurilor, toate câmpurile, inclusiv expeditorul, destinatarul, subiectul și corpul, trebuie să poată fi căutate. În astfel de scenarii, puteți să indexați toate câmpurile de caractere ale documentului folosind $ **
indicatorul wildcard.
Interogarea ar merge așa (asigurați-vă că ștergeți indicele existent înainte de a crea unul nou):
db.messages.createIndex ( "$ **": "text")
Această interogare ar crea automat indexuri de text pe orice câmp de șir din documentele noastre. Pentru a testa acest lucru, introduceți un nou document cu un câmp nou Locație
în el:
db.messages.insert ("subiect": "Păsările pot găti", "conținut": "Păsările nu mănâncă șobolani", "place": 12, "an" :"Engleză")
Acum, dacă încercați să căutați text cu cuvântul cheie chicago
(interogare de mai jos), va returna documentul pe care tocmai l-am inserat.
db.messages.find ($ text: $ search: "chicago", scor: $ meta: "textScore") sortați (scor: $ meta: "textScore")
Cateva lucruri la care as vrea sa ma concentrez aici:
Locație
după introducerea unui nou document. Acest lucru se datorează faptului că am definit deja un index text pe întregul document folosind $ **
operator.Puteți căuta expresii precum "păsările inteligente care iubesc gătitul"folosind indexuri de text. În mod implicit, expresia de căutare face o SAU căutați în toate cuvintele cheie specificate, adică va căuta documente care conțin fie cuvintele cheie inteligent
, pasăre
, dragoste
sau bucătar
.
db.messages.find ($ text: $ search: "păsări inteligente care gătesc", scor: $ meta: "scor text") sortare (scor: $ meta: „)
Această interogare va afișa următoarele documente:
"_id": ObjectId ("55f5289cb592880356441ead"), "subiect": "Păsările pot găti", "conținut": "Păsările nu mănâncă șobolani"; "Chicago", "limbă": "engleză", "scor": 2 "_id": ObjectId ("55f5289bb592880356441eab"), "subject": " "," place ": 55," an ": 2014," limbă ":" engleză "," scor ": 0.6666666666666666
În cazul în care doriți să efectuați o căutare frază exactă (logică ȘI), puteți face acest lucru specificând citate duble în textul de căutare.
db.messages.find ($ text: $ search: "\" cook food \ "", scor: $ meta: "textScore") sort (scor: $ meta: „)
Această interogare ar duce la următorul document care conține fraza "bucate de mâncare" împreună:
"_id": ObjectId ("55f5289bb592880356441eab"), "subject": "Pisici mănâncă șobolani", "conținut": "Șobolani nu gătesc alimente"; "engleză", "scor": 0.6666666666666666
Prefixarea unui cuvânt cheie de căutare cu -
(semnul minus) exclude toate documentele care conțin termenul negat. De exemplu, încercați să căutați orice document care conține cuvântul cheie şobolan
dar nu conține păsări
utilizând următoarea interogare:
db.messages.find ($ text: $ search: "rat -birds", scor: $ meta: "textScore") sortați (scor: $ meta: "textScore" )
O funcționalitate importantă pe care nu am dezvăluit-o până acum este modul în care te uiți în spatele scenei și vezi cum sunt descoperite cuvintele dvs. cheie de căutare, opriți formularea aplicată, negată etc.. $ explica
la salvare. Puteți rula interogarea de explicație prin trecere Adevărat
ca parametru, care vă va oferi statistici detaliate privind executarea interogării.
db.messages.find ($ text: $ căutare: "câini care nu mănâncă pisici" - câini mănâncă "prietenii", scor: $ meta: "textScore" scor: $ meta: "textScore".) explică (adevărat)
Dacă te uiți la queryPlanner
obiect returnat de comanda explică, veți putea vedea modul în care MongoDB analizează șirul de căutare dat. Observați că a neglijat cuvinte de oprire precum care
, și a izbucnit câini
la câine
.
Puteți vedea, de asemenea, termenii pe care i-am neglijat din căutarea noastră și frazele pe care le-am folosit în parsedTextQuery
secțiune.
"parsedTextQuery": "terms": ["câine", "pisică", "nu", "mâncare", "mâncat", "șobolan", "câine" "]," fraze ": [" câinii mănâncă "]," negatPrazii ": []
Interogarea explicată va fi foarte utilă pe măsură ce executăm interogări de căutare mai complexe și doriți să le analizați.
Când în documentul nostru avem indicii pe mai multe câmpuri, de cele mai multe ori un câmp va fi mai important (adică mai multă greutate) decât celălalt. De exemplu, atunci când căutați pe un blog, titlul blogului ar trebui să aibă o greutate maximă, urmat de conținutul blogului.
Greutatea prestabilită pentru fiecare câmp indexat este 1. Pentru a aloca greutăți relative pentru câmpurile indexate, puteți include greutăți
în timpul utilizării createIndex
comanda.
Să înțelegem acest lucru cu un exemplu. Dacă încercați să căutați bucătar
cuvântul cheie cu indicii actuali, va rezulta în două documente, ambele având același punctaj.
db.messages.find ($ text: $ search: "cook", scor: $ meta: "textScore") sortați (scor: $ meta: "textScore")
"_id": ObjectId ("55f5289cb592880356441ead"), "subiect": "Păsările pot găti", "conținut": "Păsările nu mănâncă șobolani"; "Chicago", "limbă": "engleză", "scor": 0.6666666666666666 "_id": ObjectId ("55f5289bb592880356441eab"), "subject": " "," place ": 55," an ": 2014," limbă ":" engleză "," scor ": 0.6666666666666666
Acum permiteți-ne să modificăm indicii pentru a include greutăți; cu subiect
câmp având o greutate de 3 împotriva conţinut
câmp având o greutate de 1.
db.messages.createIndex ("$ **": "text", "greutăți": subiect: 3, conținut: 1)
Încercați să căutați un cuvânt cheie bucătar
acum, și veți vedea că documentul care conține acest cuvânt cheie în subiect
câmpul are un scor mai mare (de 2) decât celălalt (care are 0.66).
"_id": ObjectId ("55f5289cb592880356441ead"), "subiect": "Păsările pot găti", "conținut": "Păsările nu mănâncă șobolani"; "Chicago", "limbă": "engleză", "scor": 2 "_id": ObjectId ("55f5289bb592880356441eab"), "subject": " "," place ": 55," an ": 2014," limbă ":" engleză "," scor ": 0.6666666666666666
Pe măsură ce datele stocate în aplicația dvs. cresc, mărimea indexurilor de text continuă să crească. Cu această creștere a dimensiunii indexurilor de text, MongoDB trebuie să caute toate intrările indexate ori de câte ori este efectuată o căutare text.
Ca o tehnică care vă permite să vă păstrați eficiența căutării textului cu indicii în creștere, puteți limita numărul de intrări scanate indexate utilizând condițiile de egalitate cu o regulă $ Text
căutare. Un exemplu foarte comun al acestui lucru ar fi căutarea tuturor postărilor făcute într-un anumit an / lună sau căutarea tuturor postărilor cu o anumită categorie / etichetă.
Dacă observați documentele pe care lucrăm, avem un a an
câmpul în care nu am folosit încă. Un scenariu comun ar fi căutarea de mesaje pe an, împreună cu căutarea full-text pe care am învățat-o.
Pentru aceasta, putem crea un index compus care specifică o cheie index ascendentă / descendentă an
urmat de un index text pe subiect
camp. Făcând acest lucru, facem două lucruri importante:
Aruncați indiciile pe care le aveți deja și creați un nou index pe (an
, subiect
):
db.messages.createIndex ("an": 1, "subiect": "text")
Acum, executați următoarea interogare pentru a căuta toate mesajele create în 2015 și pentru a le conține pisici
cuvinte cheie:
db.messages.find (anul: 2015, text $: $ search: "pisici", scor: $ meta: "textScore" )
Interogarea ar întoarce un singur document potrivit așa cum era de așteptat. daca tu explica
această interogare și uita-te la executionStats
, veți găsi asta totalDocsExamined
pentru că această interogare a fost 1, ceea ce confirmă faptul că noul nostru index a fost utilizat corect, iar MongoDB a trebuit să scaneze doar un singur document ignorând în siguranță toate celelalte documente care nu se încadrează în 2015.
Am parcurs un drum lung în acest articol de învățare despre indici de text. Există multe alte concepte pe care le puteți experimenta cu indici de text. Dar datorită domeniului de aplicare al acestui articol, nu vom putea să le discutăm în detaliu astăzi. Cu toate acestea, să aruncăm o scurtă privire asupra a ceea ce sunt aceste funcționalități:
limbă $
operator. MongoDB susține în prezent în jur de 15 limbi, inclusiv franceză, germană, rusă etc.Ținând cont de faptul că căutarea full-text MongoDB nu este o înlocuire completă a bazelor de date tradiționale ale motoarelor de căutare utilizate cu MongoDB, se recomandă utilizarea funcționalității native MongoDB din următoarele motive:
Căutarea integrală a textului este o caracteristică relativ nouă în MongoDB, existând anumite funcționalități care îi lipsesc în prezent. Le-aș împărți în trei categorii. Haideți să aruncăm o privire.
$ Text
expresie, nu puteți folosi $ Text
cu $ și nici
, nu puteți folosi aluzie()
comanda cu $ Text
, utilizând $ Text
cu $ sau
are nevoie de toate clauzele din textul tău $ sau
expresia care trebuie indexată etc.Căutarea integrală a textului a fost întotdeauna una dintre cele mai solicitate funcții ale MongoDB. În acest articol, am început cu o introducere a ceea ce este căutarea full-text, înainte de a trece la elementele de bază ale creării de indici de text.
Apoi am explorat indexarea compușilor, indexarea wildcard-urilor, căutări de expresii și căutări de negare. Mai mult, am explorat câteva concepte importante, cum ar fi analizarea indexurilor de text, căutarea ponderată și partiționarea logică a indexurilor. Ne putem aștepta la unele actualizări majore ale acestei funcționalități în versiunile viitoare ale MongoDB.
Vă recomandăm să încercați să căutați în text și să vă împărtășiți gândurile. Dacă l-ați implementat deja în aplicația dvs., împărtășiți-vă cu amabilitate experiența dvs. aici. În cele din urmă, nu ezitați să postați întrebările, gândurile și sugestiile pe acest articol în secțiunea de comentarii.