MongoDB, en av de ledende NoSQL-databasene, er kjent for sin raske ytelse, fleksible skjema, skalerbarhet og gode indekseringsegenskaper. Kjernen til denne raske ytelsen ligger MongoDB indekser, som støtter effektiv eksekvering av spørringer ved å unngå fullsamlingssøk og dermed begrense antall dokumenter MongoDB-søk.
Fra og med versjon 2.4 begynte MongoDB med en eksperimentell funksjon som støtter Fullt tekstsøk ved hjelp av Tekstindekser. Denne funksjonen har nå blitt en integrert del av produktet (og er ikke lenger en eksperimentell funksjon). I denne artikkelen skal vi utforske fulltekstsøkfunksjonalitetene til MongoDB, rett fra grunnleggende.
Hvis du er ny på MongoDB, anbefaler jeg at du leser følgende artikler om Envato Tuts + som vil hjelpe deg å forstå de grunnleggende konseptene i MongoDB:
Før vi kommer inn i noen detaljer, la oss se på litt bakgrunn. Fulltekstsøk refererer til teknikken for å søke en fulltekstdatabase mot søkekriteriene spesifisert av brukeren. Det er noe som ligner på hvordan vi søker på innhold på Google (eller faktisk andre søkeprogrammer) ved å skrive inn bestemte strengord / setninger og få tilbake de relevante resultatene sortert etter deres rangering.
Her er noen flere scenarier der vi ville se et fulltekstsøk som skjer:
katter
i dem; eller å være mer komplisert, alle innleggene som har kommentarer som inneholder ordet katter
. Før vi går videre, er det visse generelle vilkår knyttet til fulltekstsøk som du burde vite. Disse vilkårene gjelder for fullføringssøkimplementering (og ikke MongoDB-spesifikk).
Stoppord er de irrelevante ordene som skal filtreres ut fra en tekst. For eksempel: a, an, den, er, på, som osv.
Stemming er prosessen med å redusere ordene til deres stamme. For eksempel: ord som stående, står, stod, etc. har en felles base stå.
En relativ rangering for å måle hvilken av søkeresultatene som er mest relevant.
Før MongoDB kom opp med begrepet tekstindekser, ville vi enten modellere våre data for å støtte søkeordssøk eller bruke vanlige uttrykk for å implementere slike søkefunksjoner. Bruk av noen av disse tilnærmingene hadde imidlertid sine egne begrensninger:
Bortsett fra disse tilnærmingene, for mer avanserte og komplekse søk-sentriske applikasjoner, finnes det alternative løsninger som Elastic Search eller SOLR. Men ved hjelp av noen av disse løsningene øker applikasjonens arkitektoniske kompleksitet, siden MongoDB nå må snakke med en ekstern ekstern database.
Merk at MongoDBs fulltekstsøk ikke er foreslått som en komplett erstatning av søkemotordatabaser som Elastic, SOLR, etc. Det kan imidlertid brukes effektivt til de fleste applikasjoner som er bygget med MongoDB i dag.
Ved å bruke MongoDB fulltekstsøk kan du definere en tekstindeks på et hvilket som helst felt i dokumentet hvis verdi er en streng eller en rekke strenger. Når vi oppretter en tekstindeks på et felt, tilkaller MongoDB og stilker det indekserte feltets tekstinnhold, og setter opp indeksene tilsvarende.
For å forstå ting ytterligere, la oss nå dykke inn i noen praktiske ting. Jeg vil at du skal følge veiledningen med meg ved å prøve ut eksemplene i mongo skallet. Vi vil først lage noen prøvedata som vi skal bruke gjennom hele artikkelen, og så fortsetter vi videre for å diskutere nøkkelbegreper.
For formålet med denne artikkelen, vurder en samling meldinger
som lagrer dokumenter av følgende struktur:
"subject": "Joe eier en hund", "innhold": "Hunder er mannens beste venn", "liker": 60, "år": 2015, "språk": "engelsk")
La oss sette inn noen eksemplar dokumenter ved hjelp av sett inn
kommando for å lage testdataene våre:
db.messages.insert ("subject": "Joe eier en hund", "innhold": "Hunder er mannens beste venn", "liker": 60, "år": 2015, "språk": "engelsk") ) "db.messages.insert" ("subject": "Hunder spiser katter og hund spiser duer også", "innhold": "Katter er ikke onde", "liker": 30, "år": 2015, "språk": "engelsk") db.messages.insert ("subject": "Katter spiser rotter", "innhold": "Rotter kjenner ikke mat", "liker": 55, "år": 2014, "språk": "engelsk") db.messages.insert ("subject": "Rats eat Joe", "innhold": "Joe spiste en rotte", "liker": 75, "år": 2014, "språk" Engelsk")
En tekstindeks opprettes ganske likt hvordan vi lager en vanlig indeks, bortsett fra at den spesifiserer tekst
søkeord i stedet for å angi en stigende / synkende rekkefølge.
Lag en tekstindeks på Emne
feltet i dokumentet vårt ved hjelp av følgende spørring:
db.messages.createIndex ( "emne": "tekst")
For å teste denne nyopprettede tekstindeksen på Emne
feltet, søker vi dokumenter ved hjelp av $ tekst
operatør. Vi vil se etter alle dokumentene som har søkeordet hunder
i deres Emne
felt.
Siden vi kjører et tekstsøk, er vi også interessert i å få litt statistikk om hvor relevant de resulterende dokumentene er. For dette formålet vil vi bruke $ Meta: "textScore"
uttrykk, som gir informasjon om behandling av $ tekst
operatør. Vi vil også sortere dokumentene av deres textScore
bruker sortere
kommando. En høyere textScore
Indikerer en mer relevant kamp.
db.messages.find ($ text: $ search: "dogs", poengsum: $ meta: "toextScore"). sort (score: $ meta: "textScore")
Ovennevnte søk returnerer følgende dokumenter som inneholder søkeordet hunder
i deres Emne
felt.
"_id": ObjectId ("55f4a5d9b592880356441e94"), "subject": "Hunder spiser katter og hunder spiser duer også", "innhold": "Katter er ikke onde", "liker": 30, "år" "Language": "Engelsk", "Score": 1 "_id": ObjectId ("55f4a5d9b592880356441e93"), "Subject": "Joe eier en hund", "innhold": "Hunder er mannens beste venn" liker ": 60," år ": 2015," språk ":" engelsk "," poengsum ": 0.6666666666666666
Som du kan se har det første dokumentet en score på 1 (siden søkeordet hund
vises to ganger i emnet) i motsetning til det andre dokumentet med en poengsum på 0,66. Spørringen har også sortert de returnerte dokumentene i synkende rekkefølge av partituret deres.
Et spørsmål som kan oppstå i tankene dine er at hvis vi søker etter søkeordet hunder
, hvorfor er søkemotoren tar søkeordet hund
(uten 's') i betraktning? Husk vår diskusjon om stemming, hvor noen søkeord er redusert til deres base? Dette er grunnen til at søkeordet hunder
er redusert til hund
.
Oftere enn ikke, vil du bruke tekstsøk på flere felt i et dokument. I vårt eksempel vil vi aktivere sammensatt tekstindeksering på Emne
og innhold
Enger. Gå videre og utfør følgende kommando i mongo shell:
db.messages.createIndex ( "emne": "tekst", "innhold": "tekst")
Gjorde dette arbeidet? Nei!! Opprette en ny tekstindeks vil gi deg en feilmelding som sier at det allerede finnes en fulltekstsøkingsindeks. Hvorfor er det slik? Svaret er at tekstindeksene kommer med en begrensning av kun en tekstindeks per samling. Derfor, hvis du ønsker å opprette en annen tekstindeks, må du slippe den eksisterende og gjenskape den nye.
db.messages.dropIndex ("subject_text") db.messages.createIndex ("emne": "tekst", "innhold": "tekst")
Etter å ha utført de ovennevnte indeksopprettingsspørsmålene, prøv å søke etter alle dokumenter med søkeord katt
.
db.messages.find ($ text: $ search: "cat", poengsum: $ meta: "textScore"). sort (score: $ meta: "textScore")
Ovennevnte spørring vil sende ut følgende dokumenter:
"_id": ObjectId ("55f4af22b592880356441ea4"), "subject": "Hunder spiser katter og hunder spiser også duer", "innhold": "Katter er ikke onde", "liker": 30, "år" "språk": "engelsk", "poeng": 1.3333333333333335 "_id": ObjectId ("55f4af22b592880356441ea5"), "subject": "Katter spiser rotter", "innhold": "Rotter kjenner ikke mat" ": 55," år ": 2014," språk ":" engelsk "," poeng ": 0.6666666666666666
Du kan se at poengsummen til det første dokumentet, som inneholder søkeordet katt
i begge Emne
og innhold
felter, er høyere.
I det siste eksemplet legger vi en kombinert indeks på Emne
og innhold
Enger. Men det kan være scenarier der du vil at tekstinnhold i dokumentene skal søkes.
For eksempel, bør du vurdere å lagre e-post i MongoDB-dokumenter. I tilfelle av e-post, må alle feltene, inkludert Avsender, Mottaker, Emne og Kropp, søkes. I slike scenarier kan du indeksere alle strengfeltene i dokumentet ditt ved hjelp av $ **
wildcard spesifier.
Forespørselen ville gå noe slikt (pass på at du sletter den eksisterende indeksen før du oppretter en ny):
db.messages.createIndex ( "$ **": "text")
Denne spørringen vil automatisk sette opp tekstindekser på noen strengfelter i våre dokumenter. For å teste dette ut, legg inn et nytt dokument med et nytt felt plassering
i det:
db.messages.insert ("subject": "Fugler kan lage mat", "innhold": "Fugler spiser ikke rotter", "liker": 12, "år": 2013, plassering: "Chicago" :"Engelsk")
Nå hvis du prøver tekstsøk med søkeord chicago
(spørring under), vil det returnere dokumentet som vi nettopp har satt inn.
db.messages.find ($ text: $ search: "chicago", score: $ meta: "textScore"). sort (score: $ meta: "textScore")
Noen ting jeg vil fokusere på her:
plassering
feltet etter at vi har satt inn et nytt dokument. Dette skyldes at vi allerede har definert en tekstindeks på hele dokumentet ved hjelp av $ **
operatør.Du kan søke etter setninger som "smarte fugler som elsker matlaging"bruker tekstindekser. Som standard gjør søkeordet en ELLER søk på alle de angitte søkeordene, dvs. det vil se etter dokumenter som inneholder enten søkeordene smart
, fugl
, kjærlighet
eller kokk
.
db.messages.find ($ text: $ search: "smarte fugler som lager mat", score: $ meta: "tekstpoeng"). sort (score: $ meta: ")
Denne spørringen vil sende ut følgende dokumenter:
"_id": ObjectId ("55f5289cb592880356441ead"), "emne": "Fugler kan lage mat", "innhold": "Fugler spiser ikke rotter", "liker": 12, "år": 2013, "plassering" "Cats eat rats", "content": "Rats koker ikke mat", "Chicago", "Language": "Engelsk", "Score": 2 "_id": ObjectId ("55f5289bb59282880356441eab") "," liker ": 55," år ": 2014," språk ":" engelsk "," poeng ": 0.6666666666666666
I tilfelle du ønsker å utføre en eksakt setningssøk (logisk OG), kan du gjøre det ved å angi dobbelte sitater i søketeksten.
db.messages.find ($ text: $ search: "\" lag mat \ "", poengsum: $ meta: "textScore"). sort (score: $ meta: "textScore ")
Denne spørringen vil resultere i følgende dokument, som inneholder uttrykket "lag mat" sammen:
"_id": ObjectId ("55f5289bb59282880356441eab"), "subject": "Katter spiser rotter", "innhold": "Rotter kjenner ikke mat", "liker": 55, "år": 2014, "språk": "engelsk", "poengsum": 0.666666666666666666
Prefikser et søkeord med -
(minustegn) utelukker alle dokumentene som inneholder det negerte begrepet. For eksempel, prøv å søke etter ethvert dokument som inneholder søkeordet rotte
men inneholder ikke fugler
bruker følgende spørring:
db.messages.find ($ text: $ search: "rotte -birds", score: $ meta: "textScore"). sort (score: $ meta: "textScore" )
En viktig funksjonalitet jeg ikke avslørte til nå, er hvordan du ser bak kulissene og ser hvordan søkeordene dine blir stemmed, stopper formulering, negerer, etc. $ forklare
til redning. Du kan kjøre forklare spørringen ved å passere ekte
som parameter, som vil gi deg detaljert statistikk på spørringen.
db.messages.find ($ text: $ search: "hunder som ikke spiser katter spiste rotter \" hunder spiser \ "-vennner, score: $ meta:" textScore ") score: $ meta: "textScore".) forklare (sann)
Hvis du ser på queryPlanner
objekt returnert av forklar kommandoen, vil du kunne se hvordan MongoDB analyserte den gjeldende søkestrengen. Vær oppmerksom på at det forsømte å stoppe ord som hvem
, og stammede hunder
til hund
.
Du kan også se vilkårene som vi forsømte fra vårt søk og setningene vi brukte i parsedTextQuery
seksjon.
"parsedTextQuery": "vilkår": ["hund", "katt", "ikke", "spise", "spiste", "rotte", "hund", "spise"], "negatedTerms" "]," setninger ": [" hunder spiser "]," negatedPhrases ": []
Forklar spørringen vil være svært nyttig når vi utfører mer komplekse søk og ønsker å analysere dem.
Når vi har indekser på mer enn ett felt i dokumentet, vil de fleste ganger det ene feltet bli viktigere (det vil si mer vekt) enn det andre. For eksempel, når du søker på tvers av en blogg, bør tittelen på bloggen ha høyest vekt, etterfulgt av blogginnholdet.
Standardvekten for hvert indeksert felt er 1. For å tilordne relative vekter for de indekserte feltene, kan du inkludere vekter
alternativet mens du bruker createIndex
kommando.
La oss forstå dette med et eksempel. Hvis du prøver å søke etter kokk
søkeord med våre nåværende indekser, vil det resultere i to dokumenter, som begge har samme poengsum.
db.messages.find ($ text: $ search: "cook", score: $ meta: "textScore"). sort (score: $ meta: "textScore")
"_id": ObjectId ("55f5289cb592880356441ead"), "emne": "Fugler kan lage mat", "innhold": "Fugler spiser ikke rotter", "liker": 12, "år": 2013, "plassering" "Cats eat rats", "content": "rotter koker ikke mat", "cats eat rats", "content": "english", "score": 0.666666666666666666 "_id": ObjectId ("55f5289bb59282880356441eab") "," liker ": 55," år ": 2014," språk ":" engelsk "," poeng ": 0.6666666666666666
La oss nå endre indeksene våre for å inkludere vekter; med Emne
feltet har en vekt på 3 mot innhold
felt med en vekt på 1.
db.messages.createIndex ("$ **": "text", "vekter": emne: 3, innhold: 1)
Prøv å søke etter søkeord kokk
nå, og du vil se at dokumentet som inneholder dette søkeordet i Emne
feltet har en større poengsum (av 2) enn den andre (som har 0,66).
"_id": ObjectId ("55f5289cb592880356441ead"), "emne": "Fugler kan lage mat", "innhold": "Fugler spiser ikke rotter", "liker": 12, "år": 2013, "plassering" "Cats eat rats", "content": "Rats koker ikke mat", "Chicago", "Language": "Engelsk", "Score": 2 "_id": ObjectId ("55f5289bb59282880356441eab") "," liker ": 55," år ": 2014," språk ":" engelsk "," poeng ": 0.6666666666666666
Etter hvert som dataene som er lagret i søknaden din vokser, fortsetter størrelsen på tekstindeksene å vokse også. Med denne økningen i størrelsen på tekstindekser, må MongoDB søke etter alle indekserte oppføringer når et tekstsøk er gjort.
Som en metode for å holde tekstsøkingen effektiv med voksende indekser, kan du begrense antall skannede indeksoppføringer ved å bruke likestillingsforhold med en vanlig $ tekst
Søke. Et svært vanlig eksempel på dette ville være å søke alle innleggene som ble gjort i løpet av et bestemt år / måned, eller søke på alle innleggene med en bestemt kategori / tag.
Hvis du observerer dokumentene som vi jobber med, har vi en år
feltet i dem som vi ikke har brukt ennå. Et vanlig scenario ville være å søke meldinger etter år, sammen med det fulltekstsøk som vi har lært om.
For dette kan vi opprette en sammensatt indeks som spesifiserer en stigende / synkende indeksnøkkel på år
etterfulgt av en tekstindeks på Emne
felt. Ved å gjøre dette, gjør vi to viktige ting:
Slett indeksene du allerede har, og opprett en ny sammensatt indeks på (år
, Emne
):
db.messages.createIndex ("år": 1, "emne": "tekst")
Nå utfør følgende spørring for å søke alle meldingene som ble opprettet i 2015 og inneholde katter
søkeord:
db.messages.find (år: 2015, $ tekst: $ søk: "katter", poengsum: $ meta: "textScore"). sort (score: $ meta: "textScore" )
Forespørselen ville returnere bare ett sammenpasset dokument som forventet. Hvis du forklare
denne spørringen og se på executionStats
, du vil finne det totalDocsExamined
for denne spørringen var 1, noe som bekrefter at vår nye indeks ble utnyttet riktig, og MongoDB måtte bare skanne et enkelt dokument mens du sikkert ignorerte alle andre dokumenter som ikke var under 2015.
Vi har kommet langt i denne artikkelen og lærer om tekstindekser. Det er mange andre begreper som du kan eksperimentere med tekstindekser. Men på grunn av omfanget av denne artikkelen, vil vi ikke kunne diskutere dem i detalj i dag. Likevel, la oss få en kort titt på hva disse funksjonene er:
$ språk
operatør. MongoDB støtter for tiden rundt 15 språk, inkludert fransk, tysk, russisk, etc.Med tanke på det faktum at MongoDB fulltekstsøk ikke er en komplett erstatning for tradisjonelle søkemotordatabaser som brukes med MongoDB, anbefales det å bruke den innfødte MongoDB-funksjonaliteten av følgende grunner:
Fulltekstsøk er en relativt ny funksjon i MongoDB, det er visse funksjoner som den for tiden mangler. Jeg ville dele dem i tre kategorier. La oss se.
$ tekst
uttrykk, du kan ikke bruke $ tekst
med $ nor
, du kan ikke bruke hint()
kommandoen med $ tekst
, ved hjelp av $ tekst
med $ eller
trenger alle klausulene i din $ eller
uttrykk for å bli indeksert, osv.Fulltekstsøk har alltid vært en av de mest etterspurte funksjonene i MongoDB. I denne artikkelen startet vi med en introduksjon til hva fulltekstsøk er, før vi går videre til grunnleggende om å lage tekstindekser.
Vi undersøkte deretter sammensatt indeksering, wildcard-indeksering, setningssøk og negasjonssøk. Videre utforsket vi noen viktige begreper som å analysere tekstindekser, vektet søk og logisk partisjonering av indeksene dine. Vi kan forvente noen store oppdateringer til denne funksjonaliteten i de kommende utgivelsene til MongoDB.
Jeg anbefaler at du gir tekst-søk et forsøk og deler tankene dine. Hvis du allerede har implementert den i søknaden din, vennligst del din erfaring her. Endelig er du velkommen til å legge inn dine spørsmål, tanker og forslag til denne artikkelen i kommentarfeltet.