MongoDB, een van de toonaangevende NoSQL-databases, staat bekend om zijn snelle prestaties, flexibel schema, schaalbaarheid en uitstekende indexeringsmogelijkheden. De kern van deze snelle uitvoering bestaat uit MongoDB-indexen, die efficiënte uitvoering van zoekopdrachten ondersteunen door scans met volledige incasso's te voorkomen en daardoor het aantal documenten dat door MongoDB wordt gezocht te beperken.
Vanaf versie 2.4 begon MongoDB met ondersteuning van een experimentele functie Zoek volledige text gebruik makend van Tekstindexen. Deze functie is nu een integraal onderdeel van het product geworden (en is niet langer een experimentele functie). In dit artikel gaan we de full-text search-functionaliteiten van MongoDB verkennen, rechtstreeks van de grondbeginselen.
Als u MongoDB nieuw bent, raad ik u aan de volgende artikelen over Envato Tuts + te lezen die u zullen helpen de basisconcepten van MongoDB te begrijpen:
Voordat we in details treden, laten we eens kijken naar wat achtergrondinformatie. Full-text search verwijst naar de techniek van zoeken naar een volledige tekstdatabase tegen de zoekcriteria gespecificeerd door de gebruiker. Het is vergelijkbaar met hoe we inhoud op Google (of eigenlijk elke andere zoekapplicatie) doorzoeken door bepaalde sleutelwoorden / woordgroepen in te voeren en de relevante resultaten terug te vinden gesorteerd op rangorde.
Hier volgen enkele scenario's waarin we een zoekopdracht in volledige tekst zouden zien plaatsvinden:
katten
in hen; of om complexer te zijn, alle berichten met opmerkingen die het woord bevatten katten
. Voordat we verdergaan, zijn er bepaalde algemene voorwaarden voor het zoeken in volledige tekst die u moet weten. Deze voorwaarden zijn van toepassing op elke full-text search-implementatie (en niet op MongoDB-specifiek).
Stopwoorden zijn de irrelevante woorden die uit een tekst moeten worden weggefilterd. Bijvoorbeeld: a, an, the, is, at, which, etc..
Stemming is het proces waarbij de woorden tot hun stam worden gereduceerd. Bijvoorbeeld: woorden zoals staan, staan, staan, enz. Hebben een gemeenschappelijke basis.
Een relatieve ranglijst om te meten welke van de zoekresultaten het meest relevant is.
Voordat MongoDB met het concept van tekstindexen kwam, zouden we onze gegevens modelleren om zoekacties met zoekwoorden te ondersteunen of reguliere expressies gebruiken voor het implementeren van dergelijke zoekfunctionaliteiten. Het gebruik van een van deze benaderingen had echter zijn eigen beperkingen:
Afgezien van deze benaderingen, voor meer geavanceerde en complexe zoekgerichte toepassingen, zijn er alternatieve oplossingen zoals Elastic Search of SOLR. Maar het gebruik van een van deze oplossingen verhoogt de architecturale complexiteit van de applicatie, aangezien MongoDB nu met een extra externe database moet praten.
Merk op dat de volledige tekstzoekopdracht van MongoDB niet wordt voorgesteld als een volledige vervanging van databases van zoekmachines zoals Elastic, SOLR, enz. Het kan echter effectief worden gebruikt voor de meeste toepassingen die vandaag met MongoDB zijn gebouwd..
Als u de volledige tekstzoekopdracht van MongoDB gebruikt, kunt u een tekstindex definiëren voor elk veld in het document waarvan de waarde een reeks of een reeks tekenreeksen is. Wanneer we een tekstindex maken voor een veld, codeert en strueert MongoDB de tekstinhoud van het geïndexeerde veld en stelt de indexen dienovereenkomstig in.
Laten we, om de dingen verder te begrijpen, nu een paar praktische dingen onderzoeken. Ik wil dat je de tutorial met me volgt door de voorbeelden in mongo shell uit te proberen. We zullen eerst een aantal voorbeeldgegevens maken die we in het hele artikel zullen gebruiken, en daarna bespreken we de belangrijkste concepten.
Zie voor de toepassing van dit artikel een verzameling berichten
welke documenten van de volgende structuur opslaat:
"subject": "Joe bezit een hond", "inhoud": "Honden zijn beste vriend van de mens", "vind-ik-leuk": 60, "jaar": 2015, "taal": "Engels"
Laten we enkele voorbeelddocumenten invoegen met behulp van de invoegen
opdracht om onze testgegevens te maken:
db.messages.insert ("subject": "Joe bezit een hond", "inhoud": "Honden zijn beste vriend van de mens", "likes": 60, "year": 2015, "language": "english" ) db.messages.insert ("subject": "Honden eten katten en honden eten ook duiven", "inhoud": "Katten zijn niet slecht", "likes": 30, "jaar": 2015, "taal": "Engels") db.messages.insert ("subject": "Katten eten ratten", "inhoud": "Ratten koken geen eten", "vind-ik-leuk": 55, "jaar": 2014, "taal": "Engels") db.messages.insert ("subject": "Rats eat Joe", "content": "Joe at a rat", "likes": 75, "year": 2014, "language": " Engels")
Er is een tekstindex gemaakt die lijkt op hoe we een normale index maken, behalve dat deze de index aangeeft tekst
sleutelwoord in plaats van een oplopende / aflopende volgorde op te geven.
Maak een tekstindex op de onderwerpen
veld van ons document met behulp van de volgende query:
db.messages.createIndex ( "onderwerp": "tekst")
Om deze nieuw gemaakte tekstindex te testen op de onderwerpen
veld, zullen we documenten doorzoeken met behulp van de $ text
operator. We gaan op zoek naar alle documenten met het trefwoord honden
in hun onderwerpen
veld-.
Omdat we een tekstzoekopdracht uitvoeren, zijn we ook geïnteresseerd in het opvragen van statistieken over de relevantie van de resulterende documenten. Voor dit doel zullen we de $ Meta: "textScore"
expressie, die informatie geeft over de verwerking van de $ text
operator. We zullen de documenten ook sorteren op hun textScore
de ... gebruiken soort
commando. Een hogere textScore
geeft een relevantere overeenkomst aan.
db.messages.find ($ text: $ search: "dogs", score: $ meta: "toextScore"). sort (score: $ meta: "textScore")
De bovenstaande query retourneert de volgende documenten met het trefwoord honden
in hun onderwerpen
veld-.
"_id": ObjectId ("55f4a5d9b592880356441e94"), "subject": "Honden eten katten en honden eten ook duiven", "inhoud": "Katten zijn niet slecht", "likes": 30, "year": 2015, "taal": "Engels", "score": 1 "_id": ObjectId ("55f4a5d9b592880356441e93"), "onderwerp": "Joe bezit een hond", "inhoud": "Honden zijn beste vriend van de mens", " likes ": 60," year ": 2015," language ":" english "," score ": 0.6666666666666666
Zoals u kunt zien, heeft het eerste document een score van 1 (sinds het sleutelwoord hond
verschijnt tweemaal in het onderwerp) in tegenstelling tot het tweede document met een score van 0,66. De query heeft ook de geretourneerde documenten gesorteerd in aflopende volgorde van hun score.
Een vraag die in je hoofd kan opkomen, is dat als we op zoek zijn naar het sleutelwoord honden
, waarom neemt de zoekmachine het trefwoord aan? hond
(zonder 's') in overweging? Denk aan onze discussie over stemmen, waar sleutelwoorden worden gereduceerd tot hun basis? Dit is de reden waarom het zoekwoord honden
is teruggebracht tot hond
.
Vaker wel dan niet, zult u tekstonderzoek op meerdere velden van een document gebruiken. In ons voorbeeld zullen we samengestelde tekstindexering inschakelen op de onderwerpen
en inhoud
velden. Ga je gang en voer het volgende commando uit in mongo shell:
db.messages.createIndex ( "onderwerp": "tekst", "content": "tekst")
Heeft dit gewerkt? Nee!! Als u een tweede tekstindex maakt, krijgt u een foutbericht met de melding dat er al een index voor volledige tekst bestaat. Waarom is het zo? Het antwoord is dat tekstindexen een beperking van slechts één tekstindex per verzameling bevatten. Als u dus een nieuwe tekstindex wilt maken, moet u de bestaande index laten vallen en de nieuwe indexeren.
db.messages.dropIndex ("subject_text") db.messages.createIndex ("subject": "text", "content": "text")
Na het uitvoeren van de bovenstaande query's voor het maken van indexen, zoekt u naar alle documenten met trefwoord kat
.
db.messages.find ($ text: $ search: "cat", score: $ meta: "textScore"). sort (score: $ meta: "textScore")
De bovenstaande query zou de volgende documenten uitvoeren:
"_id": ObjectId ("55f4af22b592880356441ea4"), "subject": "Honden eten katten en honden eten ook duiven", "inhoud": "Katten zijn niet slecht", "likes": 30, "year": 2015, "taal": "engels", "score": 1.3333333333333335 "_id": ObjectId ("55f4af22b592880356441ea5"), "onderwerp": "Katten eten ratten", "inhoud": "Ratten koken geen eten", "vind-ik-leuks" ": 55," jaar ": 2014," taal ":" engels "," score ": 0.6666666666666666
U kunt zien dat de score van het eerste document, dat het trefwoord bevat kat
in beide onderwerpen
en inhoud
velden, is hoger.
In het laatste voorbeeld plaatsen we een gecombineerde index op de onderwerpen
en inhoud
velden. Maar er kunnen scenario's zijn waarbij u wilt dat tekstuele inhoud in uw documenten doorzoekbaar is.
Overweeg bijvoorbeeld e-mails op te slaan in MongoDB-documenten. In het geval van e-mails moeten alle velden, inclusief afzender, ontvanger, onderwerp en hoofdtekst doorzoekbaar zijn. In dergelijke scenario's kunt u alle tekenreeksen van uw document indexeren met behulp van de $ **
wildcard specifier.
De zoekopdracht zou ongeveer zo gaan (zorg ervoor dat u de bestaande index verwijdert voordat u een nieuwe maakt):
db.messages.createIndex ( "$ **": "tekst")
Deze query stelt automatisch tekstindexen in voor alle tekenreeksen in onze documenten. Om dit uit te testen, voegt u een nieuw document in met een nieuw veld plaats
in het:
db.messages.insert ("subject": "Birds can cook", "content": "Birds do not eat ratten", "likes": 12, "year": 2013, locatie: "Chicago", "language" :"Engels")
Nu als u tekst zoekt met trefwoord chicago
(vraag hieronder), het geeft het document terug dat we zojuist hebben ingevoegd.
db.messages.find ($ text: $ search: "chicago", score: $ meta: "textScore"). sort (score: $ meta: "textScore")
Een paar dingen waar ik me hier graag op wil concentreren:
plaats
veld nadat we een nieuw document hebben ingevoegd. Dit komt omdat we al een tekstindex over het hele document hebben gedefinieerd met behulp van de $ **
operator.Je kunt zoeken naar uitdrukkingen als 'slimme vogels die van koken houden'tekstindexen gebruiken. Standaard maakt de zoekopdracht op woordgroep een OF zoeken op alle opgegeven trefwoorden, d.w.z. het zal zoeken naar documenten die ofwel de sleutelwoorden bevatten slim
, vogel
, liefde
of koken
.
db.messages.find ($ text: $ search: "smart birds who cook", score: $ meta: "text Score"). sort (score: $ meta: "text Score ")
Deze query levert de volgende documenten op:
"_id": ObjectId ("55f5289cb592880356441ead"), "onderwerp": "Birds can cook", "content": "Birds eat not ratten", "likes": 12, "year": 2013, "location": "Chicago", "taal": "Engels", "score": 2 "_id": ObjectId ("55f5289bb592880356441eab"), "onderwerp": "Katten eten ratten", "inhoud": "Ratten koken geen voedsel "," likes ": 55," year ": 2014," language ":" english "," score ": 0.6666666666666666
In het geval dat u een exact zinsdeel zoekt (logisch EN), kunt u dit doen door dubbele aanhalingstekens in de zoektekst op te geven.
db.messages.find ($ text: $ search: "\" cook food \ "", score: $ meta: "textScore"). sort (score: $ meta: "textScore ")
Deze vraag zou resulteren in het volgende document, dat de uitdrukking "cook food" samen bevat:
"_id": ObjectId ("55f5289bb592880356441eab"), "subject": "Katten eten ratten", "inhoud": "Ratten koken geen eten", "vind-ik-leuk": 55, "jaar": 2014, "taal": "Engels", "score": 0.6666666666666666
Voorvoeging van een zoekwoord met -
(minteken) sluit alle documenten uit die de ontkende term bevatten. Probeer bijvoorbeeld te zoeken naar een document dat het trefwoord bevat Rat
maar bevat niet vogelstand
met behulp van de volgende query:
db.messages.find ($ text: $ search: "rat -birds", score: $ meta: "textScore"). sort (score: $ meta: "textScore" )
Een belangrijke functionaliteit die ik tot nu toe niet heb onthuld, is hoe je achter de schermen kijkt en ziet hoe je zoektermen worden gestamd, stoppen met toepassen, negeren, enz.. $ uitleggen
te hulp schieten. U kunt de uitlegvraag uitvoeren door te geven waar
als zijn parameter, die u gedetailleerde statistieken over de uitvoering van de query zal geven.
db.messages.find ($ text: $ search: "honden die katten niet eten aten ratten \" honden eten \ "-vrienden", score: $ meta: "textScore"). sort ( score: $ meta: "textScore".) uit te leggen (true)
Als je naar de queryPlanner
object geretourneerd door de opdracht explain, kunt u zien hoe MongoDB de opgegeven zoekreeks heeft geparseerd. Merk op dat het verwaarloosde stopwoorden zoals wie
, en stamde honden
naar hond
.
U kunt ook de termen bekijken die we hebben verwaarloosd in onze zoekopdracht en de zinnen die we in de. Hebben gebruikt parsedTextQuery
sectie.
"parsedTextQuery": "terms": ["dog", "cat", "dont", "eat", "at", "rat", "dog", "eat"], "negatedTerms": ["friend" "]," zinnen ": [" honden eten "]," negatedPhrases ": []
De uitlegvraag zal zeer nuttig zijn naarmate we complexere zoekopdrachten uitvoeren en deze willen analyseren.
Wanneer we indexen op meer dan één veld in ons document hebben, zal meestal één veld belangrijker (dat wil zeggen meer gewicht) zijn dan het andere. Wanneer u bijvoorbeeld op een blog zoekt, moet de titel van de blog het hoogste gewicht hebben, gevolgd door de bloginhoud.
Het standaardgewicht voor elk geïndexeerd veld is 1. Als u relatieve gewichten wilt toewijzen voor de geïndexeerde velden, kunt u de gewichten
optie tijdens het gebruik van de createIndex
commando.
Laten we dit begrijpen met een voorbeeld. Als u probeert te zoeken naar de koken
sleutelwoord met onze huidige indexen, het zal resulteren in twee documenten, die beide dezelfde score hebben.
db.messages.find ($ text: $ search: "cook", score: $ meta: "textScore"). sort (score: $ meta: "textScore")
"_id": ObjectId ("55f5289cb592880356441ead"), "onderwerp": "Birds can cook", "content": "Birds eat not ratten", "likes": 12, "year": 2013, "location": "Chicago", "taal": "engels", "score": 0.6666666666666666 "_id": ObjectId ("55f5289bb592880356441eab"), "onderwerp": "Katten eten ratten", "inhoud": "Ratten koken geen voedsel "," likes ": 55," year ": 2014," language ":" english "," score ": 0.6666666666666666
Laten we nu onze indexen aanpassen om gewichten op te nemen; met de onderwerpen
veld met een gewicht van 3 tegen de inhoud
veld met een gewicht van 1.
db.messages.createIndex ("$ **": "text", "weights": subject: 3, content: 1)
Probeer op trefwoord te zoeken koken
nu, en u zult zien dat het document dat dit sleutelwoord bevat in de onderwerpen
veld heeft een hogere score (van 2) dan de andere (die 0.66 heeft).
"_id": ObjectId ("55f5289cb592880356441ead"), "onderwerp": "Birds can cook", "content": "Birds eat not ratten", "likes": 12, "year": 2013, "location": "Chicago", "taal": "Engels", "score": 2 "_id": ObjectId ("55f5289bb592880356441eab"), "onderwerp": "Katten eten ratten", "inhoud": "Ratten koken geen voedsel "," likes ": 55," year ": 2014," language ":" english "," score ": 0.6666666666666666
Naarmate de gegevens die in uw toepassing zijn opgeslagen toenemen, blijft de grootte van uw tekstindexen groeien. Met deze toename in de grootte van tekstindexen moet MongoDB alle geïndexeerde vermeldingen doorzoeken wanneer er een zoekopdracht wordt uitgevoerd.
Als een techniek om uw tekst efficiënt te laten doorzoeken met groeiende indexen, kunt u het aantal gescande indexvermeldingen beperken door gelijkheidsvoorwaarden te gebruiken met een reguliere $ text
zoeken. Een heel gebruikelijk voorbeeld hiervan is het doorzoeken van alle berichten die gedurende een bepaald jaar / maand zijn gemaakt of het doorzoeken van alle berichten met een bepaalde categorie / tag.
Als u de documenten waar we aan werken, in acht neemt, hebben we een jaar
veld in hen dat we nog niet hebben gebruikt. Een veelvoorkomend scenario zou zijn om berichten per jaar te doorzoeken, samen met de volledige tekstzoekopdracht waarover we hebben geleerd.
Hiervoor kunnen we een samengestelde index maken waarin een oplopende / aflopende indexsleutel wordt opgegeven jaar
gevolgd door een tekstindex op de onderwerpen
veld. Door dit te doen, doen we twee belangrijke dingen:
Drop de indexen die je al hebt en maak een nieuwe samengestelde index op (jaar
, onderwerpen
):
db.messages.createIndex ("jaar": 1, "subject": "text")
Voer nu de volgende query uit om alle berichten te zoeken die in 2015 zijn gemaakt en de katten
trefwoord:
db.messages.find (jaar: 2015, $ text: $ search: "cats", score: $ meta: "textScore"). sort (score: $ meta: "textScore" )
De query retourneert slechts één overeenkomend document zoals verwacht. als jij leg uit
deze vraag en kijk naar de executionStats
, je zult dat vinden totalDocsExamined
voor deze zoekopdracht was 1, wat bevestigt dat onze nieuwe index correct is gebruikt en dat MongoDB slechts één document hoeft te scannen terwijl alle andere documenten die niet onder 2015 vielen veilig werden genegeerd.
We hebben een lange weg afgelegd in dit artikel over tekstindexen. Er zijn veel andere concepten waarmee u kunt experimenteren met tekstindexen. Maar vanwege de reikwijdte van dit artikel zullen we vandaag niet in detail kunnen bespreken. Laten we toch een korte blik werpen op wat deze functionaliteiten zijn:
$ language
operator. MongoDB ondersteunt momenteel ongeveer 15 talen, waaronder Frans, Duits, Russisch, enz.Rekening houdend met het feit dat zoeken in de volledige tekst van MongoDB geen volledige vervanging is voor traditionele databases van zoekmachines die worden gebruikt met MongoDB, wordt de native MongoDB-functionaliteit aanbevolen om de volgende redenen:
Full-text zoeken is een relatief nieuwe functie in MongoDB, er zijn bepaalde functionaliteiten die het momenteel mist. Ik zou ze in drie categorieën verdelen. Laten we eens kijken.
$ text
expressie, je kunt niet gebruiken $ text
met $ noch
, je kunt de hint ()
commando met $ text
, gebruik makend van $ text
met $ of
heeft alle clausules in jouw $ of
expressie die moet worden geïndexeerd, enz.Full-text zoeken is altijd een van de meest gevraagde functies van MongoDB geweest. In dit artikel zijn we begonnen met een inleiding tot wat full-text search is, voordat we verdergaan met de basisbeginselen van het maken van tekstindexen.
Vervolgens hebben we samengestelde indexering, wildcardindexering, zoeken op woordgroep en negatiezoekopdrachten onderzocht. Verder hebben we enkele belangrijke concepten onderzocht, zoals het analyseren van tekstindexen, gewogen zoekopdrachten en het logisch partitioneren van uw indexen. We kunnen enkele belangrijke updates van deze functionaliteit verwachten in de aankomende releases van MongoDB.
Ik raad u aan om eens een tekst-zoekopdracht uit te proberen en uw gedachten te delen. Als u het al in uw toepassing hebt geïmplementeerd, deel uw ervaring hier alstublieft. Tot slot, voel je vrij om je vragen, gedachten en suggesties over dit artikel in de commentaarsectie te plaatsen.