Hallo vrienden! Er zijn mensen met verschillende niveaus van ervaring die bijdragen aan onze forums - en dat is geweldig! Maar op dit moment ben ik op zoek naar echte Ruby titanen!
Elasticsearch is een zoekmachine die is gebaseerd op een vertrouwde en volwassen bibliotheek - Apache Lucene. Enorme activiteit in git project repository en de implementatie in projecten als GitHub, SoundCloud, Stack Overflow en LinkedIn getuigen van de grote populariteit. Het deel "Elastic" zegt alles over de aard van het systeem, waarvan de mogelijkheden enorm zijn: van een eenvoudige bestandszoekopdracht op kleine schaal, via kennisontdekking, tot big data-analyse in realtime.Wat Elastic krachtiger maakt dan de concurrentie is de set standaardconfiguraties en -gedragingen, die het mogelijk maken om binnen een paar minuten een cluster aan te maken en te beginnen met het toevoegen van documenten aan de index. Elastic configureert een cluster voor je, definieert een index en definieert de typen velden voor het eerste document dat wordt verkregen, en als je nog een server toevoegt, zal het automatisch omgaan met het verdelen van indexgegevens tussen servers.Helaas maakt de bovengenoemde automatisering het voor ons onduidelijk wat de standaardinstellingen inhouden, en het blijkt vaak misleidend te zijn. Dit artikel start een serie waarin ik de meest populaire gotchas behandel, die je kunt tegenkomen tijdens het maken van Elastic-gebaseerde apps.
Het aantal scherven kan niet worden gewijzigd
Laten we het eerste document indexeren met index-API:
$ curl -XPUT 'http://localhost:9200/myindex/employee/1' -d '{
"voornaam" : "Jane",
"last_name" : "Smith",
"steet_number": 12
}'
Op dit moment maakt Elastic een index voor ons aan, getiteld myindex. Wat hier niet zichtbaar is, is het aantal shards dat aan de index is toegewezen. Shards kunnen worden opgevat als individuele processen die verantwoordelijk zijn voor het indexeren, opslaan en doorzoeken van een deel van de documenten van een hele index. Tijdens het indexeren van documenten beslist elastic in welke shard een document moet worden gevonden. Dat is gebaseerd op de volgende formule:
shard = hash(document_id) % aantal_van_primaire_shards
Het is nu duidelijk dat het aantal primaire shards niet kan worden gewijzigd voor een index die documenten bevat. Maak dus altijd handmatig een index aan voordat je het eerste document indexeert en geef het aantal shards op waarvan je denkt dat het voldoende is voor een volume geïndexeerde gegevens:
$ curl -XPUT 'http://localhost:9200/myindex/' -d '{
"instellingen" : {
"aantal_scherven" : 10
}
}'
Standaardwaarde voor aantal_scherven
is 5. Dit betekent dat de index geschaald kan worden naar maximaal 5 servers, die gegevens verzamelen tijdens het indexeren. Voor de productieomgeving moet de waarde van shards worden ingesteld afhankelijk van de verwachte indexeringsfrequentie en de grootte van de documenten. Voor ontwikkel- en testomgevingen raad ik aan om de waarde op 1 in te stellen - waarom? Dat wordt uitgelegd in de volgende paragraaf van dit artikel.
De tekstzoekresultaten met een relatief klein aantal documenten sorteren
Als we naar een document zoeken met een woordgroep:
$ curl -XGET 'http://localhost:9200/myindex/my_type/_search' -d
'{
"query": {
"match": {
"title": "De snelle bruine vos"
}
}
}'
Elastic verwerkt het zoeken naar tekst in een paar eenvoudige stappen:
- De zin uit het verzoek wordt omgezet in dezelfde identieke vorm als waarin het document is geïndexeerd, in ons geval is dat een verzameling termen:
["snel", "bruin", "vos"].
("de" is verwijderd omdat het onbelangrijk is),
- de index wordt doorzocht om de documenten te zoeken die ten minste één van de gezochte woorden bevatten,
- Elk document dat overeenkomt, wordt geëvalueerd op relevantie voor de zoekterm,
- De resultaten worden gesorteerd op de berekende relevantie en de eerste pagina met resultaten wordt teruggestuurd naar de gebruiker.
In de derde stap wordt (onder andere) rekening gehouden met de volgende waarden:
- hoeveel woorden van de zoekterm in het document staan
- hoe vaak een bepaald woord voorkomt in een document (TF - termfrequentie)
- of en hoe vaak de overeenkomende woorden voorkomen in andere documenten (IDF - inverse document frequency) - hoe populairder het woord in andere documenten, hoe minder significant
- hoe lang is het document
De werking van IDF is belangrijk voor ons. Om prestatieredenen berekent Elastic deze waarde niet voor elk document in de index - in plaats daarvan berekent elke shard (indexwerker) zijn lokale IDF en gebruikt deze voor het sorteren. Daarom kunnen we tijdens het zoeken in de index met een laag aantal documenten substantieel verschillende resultaten krijgen, afhankelijk van het aantal shards in een index en de verdeling van de documenten.
Stel dat we 2 shards in een index hebben; in de eerste zijn er 8 documenten geïndexeerd met het woord "vos", en in de tweede slechts 2 documenten met hetzelfde woord. Als gevolg daarvan zal het woord "vos" aanzienlijk verschillen in beide shards, en dit kan onjuiste resultaten opleveren. Daarom moet voor ontwikkelingsdoeleinden een index worden gemaakt die slechts uit één primaire shard bestaat:
$ curl -XPUT 'http://localhost:9200/myindex/' -d
{"settings" : { "number_of_shards" : 1 } }'
Het bekijken van de resultaten van "verre" zoekpagina's doodt je cluster
Zoals ik al eerder heb geschreven in vorige paragrafen, worden documenten in een index gedeeld tussen volledig individuele indexprocessen - shards. Elk proces is volledig onafhankelijk en behandelt alleen de documenten die aan het proces zijn toegewezen.
Als we een index met miljoenen documenten doorzoeken en wachten om top 10 resultaten te krijgen, moet elke shard zijn 10 best matchende resultaten terugsturen naar de cluster knooppuntdie de zoekopdracht startte. Vervolgens worden de antwoorden van elke shard samengevoegd en worden de top 10 zoekresultaten gekozen (binnen de hele index). Met een dergelijke aanpak kan het zoekproces efficiënt over veel servers worden verdeeld.
Laten we ons voorstellen dat onze app 50 resultaten per pagina laat zien, zonder de beperkingen met betrekking tot het aantal pagina's dat een gebruiker kan bekijken. Onthoud dat onze index bestaat uit 10 primaire shards (1 per server).
Laten we eens kijken hoe het verwerven van zoekresultaten eruit zal zien voor de 1e en de 100e pagina:
Pagina 1 van zoekresultaten:
- Het knooppunt dat een query ontvangt (controller) geeft deze door aan 10 shards.
- Elke shard retourneert de 50 best overeenkomende documenten gesorteerd op relevantie.
- Nadat de antwoorden van elke shard zijn ontvangen, voegt de controller de resultaten samen (500 documenten).
- Onze resultaten zijn de top 50 documenten uit de vorige stap.
Pagina nr. 100 van zoekresultaten:
- Het knooppunt dat een query ontvangt (controller) geeft deze door aan 10 shards.
- Elke shard retourneert de 5000 best overeenkomende documenten gesorteerd op relevantie.
- Na het ontvangen van antwoorden van elke shard, voegt de controller de resultaten samen (50000 documenten).
- Onze resultaten zijn de documenten uit de vorige stap, gepositioneerd op 4901 - 5000.
Ervan uitgaande dat een document 1KB groot is, betekent dit in het tweede geval dat er ~50MB aan gegevens door het cluster moet worden verzonden en verwerkt om 100 resultaten voor één gebruiker te bekijken.
Het is niet moeilijk om op te merken dat het netwerkverkeer en de belasting van de index aanzienlijk toenemen met elke opeenvolgende resultaatpagina. Daarom is het niet aan te raden om de "verre" zoekpagina's beschikbaar te maken voor de gebruiker. Als onze index goed is geconfigureerd, dan zou de gebruiker het resultaat waarin hij geïnteresseerd is op de eerste zoekpagina's moeten vinden en beschermen we onszelf tegen onnodige belasting van ons cluster. Om deze regel te bewijzen, controleer tot hoeveel pagina's met zoekresultaten de populairste webzoekmachines weergave toestaan.
Wat ook interessant is, is de observatie van de responstijd van de browser voor opeenvolgende pagina's met zoekresultaten. Hieronder ziet u bijvoorbeeld de responstijden voor afzonderlijke pagina's met zoekresultaten in Google Search (de zoekterm was "zoekmachine"):
| Pagina met zoekresultaten (10 documenten per pagina) | Reactietijd |
|——————————————–|—————|
| 1 | 250ms |
| 10 290ms
| 20 350ms
| 30 380ms
| 38 (laatste beschikbare)
In het volgende deel zal ik dieper ingaan op de problemen met betrekking tot het indexeren van documenten.