MongoDB, uno dei principali database NoSQL, è ben noto per le sue prestazioni veloci, lo schema flessibile, la scalabilità e le ottime capacità di indicizzazione. Al centro di questa rapida performance si trovano gli indici MongoDB, che supportano l'esecuzione efficiente delle query evitando scansioni full-collection e quindi limitando il numero di documenti ricerche MongoDB.
A partire dalla versione 2.4, MongoDB ha iniziato con una funzione sperimentale di supporto Ricerca full-text utilizzando Indici di testo. Questa funzionalità è ora diventata parte integrante del prodotto (e non è più una funzionalità sperimentale). In questo articolo esploreremo le funzionalità di ricerca full-text di MongoDB direttamente dai fondamenti.
Se sei nuovo in MongoDB, ti consiglio di leggere i seguenti articoli su Envato Tuts + che ti aiuteranno a capire i concetti di base di MongoDB:
Prima di entrare nei dettagli, diamo un'occhiata ad alcuni retroscena. La ricerca full-text si riferisce alla tecnica di ricerca a database full-text contro i criteri di ricerca specificati dall'utente. È qualcosa di simile al modo in cui cerchiamo qualsiasi contenuto su Google (o in realtà qualsiasi altra applicazione di ricerca) inserendo determinate parole chiave / frasi e recuperando i risultati pertinenti ordinati in base alla loro posizione.
Ecco alcuni scenari in cui verrebbe visualizzata una ricerca full-text:
gatti
in loro; o per essere più complesso, tutti i post che contengono commenti contenenti la parola gatti
. Prima di andare avanti, ci sono alcuni termini generali relativi alla ricerca full-text che dovresti sapere. Questi termini sono applicabili a qualsiasi implementazione di ricerca full-text (e non specifica per MongoDB).
Le parole di stop sono le parole irrilevanti che dovrebbero essere filtrate da un testo. Ad esempio: a, an, the, is, at, which, ecc.
Staminare è il processo di riduzione delle parole alla loro radice. Ad esempio: parole come in piedi, in piedi, in piedi, ecc. Hanno una base comune.
Una classifica relativa per misurare quale dei risultati della ricerca è più rilevante.
Prima che MongoDB arrivasse con il concetto di indici di testo, modellavamo i nostri dati per supportare le ricerche di parole chiave o usiamo espressioni regolari per implementare tali funzionalità di ricerca. Tuttavia, l'utilizzo di uno di questi approcci ha i suoi limiti:
Oltre a questi approcci, per applicazioni di ricerca più complesse e avanzate, esistono soluzioni alternative come Elastic Search o SOLR. Ma l'utilizzo di una di queste soluzioni aumenta la complessità architettonica dell'applicazione, dal momento che MongoDB deve ora parlare con un database esterno aggiuntivo.
Si noti che la ricerca full-text di MongoDB non viene proposta come una sostituzione completa dei database dei motori di ricerca come Elastic, SOLR, ecc. Tuttavia, può essere efficacemente utilizzata per la maggior parte delle applicazioni che sono state costruite con MongoDB oggi.
Utilizzando la ricerca full text di MongoDB, è possibile definire un indice di testo su qualsiasi campo nel documento il cui valore è una stringa o un array di stringhe. Quando creiamo un indice di testo su un campo, MongoDB tokenizza e blocca il contenuto del testo del campo indicizzato e imposta gli indici di conseguenza.
Per comprendere meglio le cose, passiamo ora ad alcune cose pratiche. Voglio che seguiate il tutorial con me provando gli esempi nella shell mongo. Per prima cosa creeremo alcuni dati campione che utilizzeremo in tutto l'articolo, quindi passeremo a discutere concetti chiave.
Ai fini di questo articolo, prendere in considerazione una raccolta messaggi
che memorizza i documenti della seguente struttura:
"oggetto": "Joe possiede un cane", "contenuto": "I cani sono il migliore amico dell'uomo", "Mi piace": 60, "anno": 2015, "lingua": "inglese"
Cerchiamo di inserire alcuni documenti di esempio usando il inserire
comando per creare i nostri dati di test:
db.messages.insert ("oggetto": "Joe possiede un cane", "contenuto": "I cani sono il migliore amico dell'uomo", "Mi piace": 60, "anno": 2015, "lingua": "inglese" ) db.messages.insert ("subject": "I cani mangiano gatti e il cane mangia anche i piccioni", "contenuto": "I gatti non sono cattivi", "Mi piace": 30, "anno": 2015, "lingua": "inglese") db.messages.insert ("oggetto": "I gatti mangiano i ratti", "contenuto": "I ratti non cucinano cibo", "Mi piace": 55, "anno": 2014, "lingua": "inglese") db.messages.insert ("subject": "Rats eat Joe", "content": "Joe ha mangiato un topo", "likes": 75, "year": 2014, "language": " Inglese")
Un indice di testo è creato in modo abbastanza simile al modo in cui creiamo un indice regolare, tranne per il fatto che specifica il testo
parola chiave invece di specificare un ordine crescente / decrescente.
Crea un indice di testo sul soggetto
campo del nostro documento utilizzando la seguente query:
db.messages.createIndex ( "soggetto": "text")
Per testare questo indice di testo appena creato sul soggetto
campo, cercheremo i documenti usando il $ testo
operatore. Cercheremo tutti i documenti che contengono la parola chiave cani
nel loro soggetto
campo.
Poiché stiamo eseguendo una ricerca di testo, siamo anche interessati a ottenere alcune statistiche su quanto siano pertinenti i documenti risultanti. Per questo scopo, useremo il $ Meta: "textScore"
espressione, che fornisce informazioni sull'elaborazione del file $ testo
operatore. Ordineremo anche i documenti con i loro textScore
usando il ordinare
comando. Un più alto textScore
indica una corrispondenza più rilevante.
db.messages.find ($ text: $ search: "dogs", score: $ meta: "toextScore"). sort (score: $ meta: "textScore")
La query precedente restituisce i seguenti documenti contenenti la parola chiave cani
nel loro soggetto
campo.
"_id": ObjectId ("55f4a5d9b592880356441e94"), "subject": "I cani mangiano gatti e il cane mangia anche i piccioni", "contenuto": "I gatti non sono cattivi", "Mi piace": 30, "anno": 2015, "lingua": "inglese", "punteggio": 1 "_id": ObjectId ("55f4a5d9b592880356441e93"), "oggetto": "Joe possiede un cane", "contenuto": "I cani sono i migliori amici dell'uomo", " likes ": 60," year ": 2015," language ":" inglese "," score ": 0.6666666666666666
Come puoi vedere, il primo documento ha un punteggio di 1 (dalla parola chiave cane
appare due volte nella sua materia) rispetto al secondo documento con un punteggio di 0,66. La query ha anche ordinato i documenti restituiti in ordine decrescente del loro punteggio.
Una domanda che potrebbe sorgere nella tua mente è che se stiamo cercando la parola chiave cani
, perché il motore di ricerca sta prendendo la parola chiave cane
(senza "s") in considerazione? Ricorda la nostra discussione sulla derivazione, dove le parole chiave di ricerca sono ridotte alla loro base? Questo è il motivo per cui la parola chiave cani
è ridotto a cane
.
Più spesso, userete la ricerca testuale su più campi di un documento. Nel nostro esempio, abiliteremo l'indicizzazione del testo composto su soggetto
e soddisfare
campi. Vai avanti ed esegui il seguente comando in mongo shell:
db.messages.createIndex ( "soggetto": "testo", "content": "text")
Questo lavoro? No!! La creazione di un secondo indice di testo ti darà un messaggio di errore che dice che esiste già un indice di ricerca full-text. Perché è così? La risposta è che gli indici di testo hanno una limitazione di un solo indice di testo per collezione. Quindi se si desidera creare un altro indice di testo, sarà necessario eliminare quello esistente e ricreare quello nuovo.
db.messages.dropIndex ("subject_text") db.messages.createIndex ("oggetto": "testo", "contenuto": "testo")
Dopo aver eseguito le query di creazione dell'indice sopra, prova a cercare tutti i documenti con la parola chiave gatto
.
db.messages.find ($ text: $ search: "cat", score: $ meta: "textScore"). sort (score: $ meta: "textScore")
La query precedente produrrebbe i seguenti documenti:
"_id": ObjectId ("55f4af22b592880356441ea4"), "subject": "I cani mangiano gatti e il cane mangia anche i piccioni", "contenuto": "I gatti non sono cattivi", "Mi piace": 30, "anno": 2015, "lingua": "inglese", "punteggio": 1.3333333333333335 "_id": ObjectId ("55f4af22b592880356441ea5"), "oggetto": "I gatti mangiano ratti", "contenuto": "I ratti non cucinano cibo", "Mi piace" ": 55," anno ": 2014," lingua ":" inglese "," punteggio ": 0.6666666666666666
Puoi vedere che il punteggio del primo documento, che contiene la parola chiave gatto
in entrambe soggetto
e soddisfare
campi, è più alto.
Nell'ultimo esempio, abbiamo inserito un indice combinato su soggetto
e soddisfare
campi. Ma ci possono essere degli scenari in cui desideri che qualsiasi contenuto di testo nei tuoi documenti sia ricercabile.
Ad esempio, considera la possibilità di memorizzare le email nei documenti MongoDB. Nel caso di e-mail, tutti i campi, incluso Mittente, Destinatario, Oggetto e Corpo, devono essere ricercabili. In tali scenari è possibile indicizzare tutti i campi stringa del documento utilizzando il $ **
identificatore di caratteri jolly.
La query dovrebbe essere simile a questa (assicurati di eliminare l'indice esistente prima di crearne uno nuovo):
db.messages.createIndex ( "$ **": "text")
Questa query imposta automaticamente gli indici di testo su tutti i campi stringa nei nostri documenti. Per testare questo, inserisci un nuovo documento con un nuovo campo Posizione
dentro:
db.messages.insert ("subject": "Birds can cook", "content": "Birds do not eat rats", "likes": 12, "year": 2013, location: "Chicago", "language" :"Inglese")
Ora se provi a cercare testo con parole chiave Chicago
(query sotto), restituirà il documento che abbiamo appena inserito.
db.messages.find ($ text: $ search: "chicago", score: $ meta: "textScore"). sort (score: $ meta: "textScore")
Alcune cose su cui vorrei soffermarmi qui:
Posizione
campo dopo aver inserito un nuovo documento. Questo perché abbiamo già definito un indice di testo sull'intero documento usando il $ **
operatore.Puoi cercare frasi come "uccelli intelligenti che amano cucinare"usando gli indici di testo. Per impostazione predefinita, la ricerca frase fa un O cerca su tutte le parole chiave specificate, cioè cercherà i documenti che contengono le parole chiave inteligente
, uccello
, amore
o cucinare
.
db.messages.find ($ text: $ search: "uccelli intelligenti che cucinano", punteggio: $ meta: "testo Punteggio"). ordina (punteggio: $ meta: "testo punteggio ")
Questa query produrrebbe i seguenti documenti:
"_id": ObjectId ("55f5289cb592880356441ead"), "subject": "Birds can cook", "content": "Birds do not eat rats", "likes": 12, "year": 2013, "location": "Chicago", "lingua": "inglese", "punteggio": 2 "_id": ObjectId ("55f5289bb592880356441eab"), "oggetto": "I gatti mangiano ratti", "contenuto": "I ratti non cucinano cibo "," likes ": 55," anno ": 2014," lingua ":" inglese "," punteggio ": 0.6666666666666666
Nel caso in cui si desideri eseguire una ricerca di frase esatta (logica E), puoi farlo specificando le virgolette doppie nel testo di ricerca.
db.messages.find ($ text: $ search: "\" cook food \ "", score: $ meta: "textScore"). sort (score: $ meta: "textScore ")
Questa query risulterebbe nel seguente documento, che contiene la frase "cucinare cibo" insieme:
"_id": ObjectId ("55f5289bb592880356441eab"), "oggetto": "I gatti mangiano ratti", "contenuto": "I ratti non cucinano cibo", "Mi piace": 55, "anno": 2014, "lingua": "inglese", "punteggio": 0.6666666666666666
Prefixing di una parola chiave di ricerca con -
(segno meno) esclude tutti i documenti che contengono il termine negato. Ad esempio, prova a cercare qualsiasi documento che contenga la parola chiave ratto
ma non contiene uccelli
utilizzando la seguente query:
db.messages.find ($ text: $ search: "rat -birds", score: $ meta: "textScore"). sort (score: $ meta: "textScore" )
Un'importante funzionalità che non ho rivelato finora è il modo in cui guardi dietro le quinte e vedi come vengono bloccate le tue parole chiave di ricerca, interrompi la dicitura applicata, negata, ecc.. $ spiegare
Al salvataggio. È possibile eseguire la query query passando vero
come parametro, che fornirà statistiche dettagliate sull'esecuzione della query.
db.messages.find ($ text: $ search: "cani che i gatti non mangiano mangiano ratti \" cani mangiano \ "-friends", punteggio: $ meta: "textScore"). sort ( punteggio: $ meta: "textScore".) spiegare (vero)
Se guardi il queryPlanner
oggetto restituito dal comando spiega, sarete in grado di vedere come MongoDB ha analizzato la stringa di ricerca fornita. Osservare che ha trascurato parole di arresto come chi
, e derivava cani
a cane
.
Puoi anche vedere i termini che abbiamo trascurato dalla nostra ricerca e le frasi che abbiamo usato nel parsedTextQuery
sezione.
"parsedTextQuery": "terms": ["dog", "cat", "dont", "eat", "ate", "rat", "dog", "eat"], "negatedTerms": ["friend "]," frasi ": [" cani mangiano "]," negatedPhrases ": []
La query di spiegazione sarà molto utile poiché eseguiamo query di ricerca più complesse e desideriamo analizzarle.
Quando abbiamo indici su più di un campo nel nostro documento, la maggior parte delle volte un campo sarà più importante (cioè più peso) rispetto all'altro. Ad esempio, quando stai cercando attraverso un blog, il titolo del blog dovrebbe essere di massima importanza, seguito dal contenuto del blog.
Il peso predefinito per ogni campo indicizzato è 1. Per assegnare pesi relativi ai campi indicizzati, è possibile includere il pesi
opzione durante l'utilizzo del createIndex
comando.
Comprendiamo questo con un esempio. Se provi a cercare il cucinare
parola chiave con i nostri indici correnti, genererà due documenti, entrambi con lo stesso punteggio.
db.messages.find ($ text: $ search: "cook", score: $ meta: "textScore"). sort (score: $ meta: "textScore")
"_id": ObjectId ("55f5289cb592880356441ead"), "subject": "Birds can cook", "content": "Birds do not eat rats", "likes": 12, "year": 2013, "location": "Chicago", "lingua": "inglese", "punteggio": 0.6666666666666666 "_id": ObjectId ("55f5289bb592880356441eab"), "oggetto": "I gatti mangiano ratti", "contenuto": "I ratti non cucinano cibo "," likes ": 55," anno ": 2014," lingua ":" inglese "," punteggio ": 0.6666666666666666
Ora modifichiamo i nostri indici per includere i pesi; con il soggetto
campo avendo un peso di 3 contro il soddisfare
campo con un peso di 1.
db.messages.createIndex ("$ **": "testo", "pesi": oggetto: 3, contenuto: 1)
Prova a cercare la parola chiave cucinare
ora, e vedrai che il documento che contiene questa parola chiave nel soggetto
il campo ha un punteggio maggiore (di 2) rispetto all'altro (che ha 0.66).
"_id": ObjectId ("55f5289cb592880356441ead"), "subject": "Birds can cook", "content": "Birds do not eat rats", "likes": 12, "year": 2013, "location": "Chicago", "lingua": "inglese", "punteggio": 2 "_id": ObjectId ("55f5289bb592880356441eab"), "oggetto": "I gatti mangiano ratti", "contenuto": "I ratti non cucinano cibo "," likes ": 55," anno ": 2014," lingua ":" inglese "," punteggio ": 0.6666666666666666
Man mano che i dati memorizzati nell'applicazione crescono, anche le dimensioni degli indici di testo continuano a crescere. Con questo aumento delle dimensioni degli indici di testo, MongoDB deve cercare tutte le voci indicizzate ogni volta che viene effettuata una ricerca di testo.
Come tecnica per mantenere efficiente la ricerca di testo con indici in crescita, è possibile limitare il numero di voci dell'indice digitalizzate utilizzando le condizioni di parità con un regolare $ testo
ricerca. Un esempio molto comune di questo sarebbe la ricerca di tutti i post fatti durante un determinato anno / mese, o la ricerca di tutti i messaggi con una determinata categoria / tag.
Se osservi i documenti su cui stiamo lavorando, abbiamo un anno
campo in loro che non abbiamo ancora usato. Uno scenario comune sarebbe quello di cercare i messaggi per anno, insieme alla ricerca full-text che abbiamo imparato.
Per questo, possiamo creare un indice composto che specifica una chiave di indice crescente / decrescente anno
seguito da un indice di testo sul soggetto
campo. In questo modo, stiamo facendo due cose importanti:
Rilascia gli indici che hai già e crea un nuovo indice composto su (anno
, soggetto
):
db.messages.createIndex ("anno": 1, "oggetto": "testo")
Ora esegui la seguente query per cercare tutti i messaggi che sono stati creati nel 2015 e contengono il gatti
parola chiave:
db.messages.find (year: 2015, $ text: $ search: "cats", score: $ meta: "textScore"). sort (score: $ meta: "textScore" )
La query restituirebbe solo un documento corrispondente come previsto. Se tu spiegare
questa domanda e guarda il executionStats
, lo troverai totalDocsExamined
per questa query è stato 1, il che conferma che il nostro nuovo indice è stato utilizzato correttamente e MongoDB ha dovuto eseguire la scansione di un singolo documento ignorando in sicurezza tutti gli altri documenti che non sono rientrati nel 2015.
Abbiamo fatto molta strada in questo articolo imparando gli indici di testo. Ci sono molti altri concetti che puoi sperimentare con gli indici di testo. Ma a causa della portata di questo articolo, non saremo in grado di discuterli in dettaglio oggi. Tuttavia, diamo una breve occhiata a quali sono queste funzionalità:
$ lingua
operatore. MongoDB attualmente supporta circa 15 lingue, tra cui francese, tedesco, russo, ecc.Tenendo presente che la ricerca full text di MongoDB non è una sostituzione completa dei database dei motori di ricerca tradizionali utilizzati con MongoDB, si consiglia la funzionalità nativa di MongoDB per i seguenti motivi:
La ricerca full-text è una caratteristica relativamente nuova in MongoDB, ci sono alcune funzionalità che al momento manca. Li dividerei in tre categorie. Diamo un'occhiata.
$ testo
espressione, non puoi usare $ testo
con $ né
, non puoi usare il suggerimento()
comando con $ testo
, utilizzando $ testo
con $ o
ha bisogno di tutte le clausole nel tuo $ o
espressione da indicizzare, ecc.La ricerca full-text è sempre stata una delle funzionalità più richieste di MongoDB. In questo articolo, abbiamo iniziato con un'introduzione alla ricerca full-text, prima di passare alle basi della creazione di indici di testo.
Abbiamo quindi esplorato l'indicizzazione composta, l'indicizzazione con caratteri jolly, le ricerche di frasi e le ricerche di negazione. Inoltre, abbiamo esplorato alcuni concetti importanti come l'analisi degli indici di testo, la ricerca ponderata e la partizione logica degli indici. Possiamo aspettarci alcuni importanti aggiornamenti a questa funzionalità nelle prossime versioni di MongoDB.
Ti consiglio di provare il testo e di condividere i tuoi pensieri. Se l'hai già implementato nella tua applicazione, condividi gentilmente la tua esperienza qui. Infine, sentiti libero di postare domande, pensieri e suggerimenti su questo articolo nella sezione commenti.