Hej alla vänner! Det finns människor med olika nivåer av erfarenhet som bidrar till våra forum - och det är fantastiskt! Men just nu letar jag efter sanna Ruby-titaner!
Elasticsearch är en sökmotor som bygger på ett pålitligt och moget bibliotek - Apache Lucene. Stor aktivitet i git projekt och implementeringen i sådana projekt som GitHub, SoundCloud, Stack Overflow och LinkedIn vittnar om dess stora popularitet. Delen "Elastic" säger allt om systemets natur, vars kapacitet är enorm: från en enkel filsökning i liten skala, genom kunskapsupptäckt, till analys av stora data i realtid.Vad som gör Elastic till en kraftfullare än konkurrensen är uppsättningen standardkonfigurationer och beteenden, som gör det möjligt att skapa ett kluster och börja lägga till dokument i indexet på ett par minuter. Elastic kommer att konfigurera ett kluster åt dig, definiera ett index och definiera typerna av fält för det första dokumentet som erhålls, och när du lägger till en annan server kommer den automatiskt att hantera delning av indexdata mellan servrar.Tyvärr gör den ovan nämnda automatiseringen det oklart för oss vad standardinställningarna innebär, och det visar sig ofta vara vilseledande. Den här artikeln startar en serie där jag kommer att ta upp de mest populära problemen som du kan stöta på under processen med att skapa Elastic-baserade appar.
Antalet skärvor kan inte ändras
Låt oss indexera det första dokumentet med hjälp av index API:
$ curl -XPUT 'http://localhost:9200/myindex/employee/1' -d '{
"förnamn" : "Jane",
"efternamn": "Smith",
"steet_number": 12
}'
I det här ögonblicket skapar Elastic ett index för oss med titeln myindex. Det som inte syns här är antalet shards som tilldelats indexet. Shards kan förstås som enskilda processer som ansvarar för indexering, lagring och sökning av en del av dokumenten i ett helt index. Under processen med dokumentindexering bestämmer elastic i vilken shard ett dokument ska hittas. Det baseras på följande formel:
shard = hash(document_id) % antal_av_primära_shards
Det står nu klart att antalet primära shards inte kan ändras för ett index som innehåller dokument. Innan du indexerar det första dokumentet ska du därför alltid skapa ett index manuellt och ange det antal shards som du anser vara tillräckligt för en viss volym indexerade data:
$ curl -XPUT 'http://localhost:9200/myindex/' -d '{
"inställningar" : {
"antal_av_skärvor" : 10
}
}'
Standardvärde för antal_skärvor
är 5. Det innebär att indexet kan skalas till upp till 5 servrar, som samlar in data under indexeringen. För produktionsmiljön bör värdet på shards ställas in beroende på den förväntade frekvensen av indexering och storleken på dokumenten. För utvecklings- och testmiljöer rekommenderar jag att värdet sätts till 1 - varför det? Det kommer att förklaras i nästa stycke i den här artikeln.
Sortering av textsökningsresultat med ett relativt litet antal dokument
När vi söker efter ett dokument med en fras:
$ curl -XGET 'http://localhost:9200/myindex/my_type/_search' -d
'{
"fråga": {
"match": {
"titel": "Den snabba bruna räven"
}
}
}'
Elastic bearbetar textsökning i några få steg, helt enkelt:
- frasen från förfrågan konverteras till samma identiska form som dokumentet indexerades i, i vårt fall blir det en uppsättning termer:
["snabb", "brun", "räv"]
("den" har tagits bort eftersom det är obetydligt),
- indexet bläddras igenom för att söka efter de dokument som innehåller minst ett av de sökta orden,
- varje dokument som är en matchning utvärderas med avseende på om det är relevant för sökfrasen,
- resultaten sorteras efter den beräknade relevansen och den första sidan med resultat returneras till användaren.
I det tredje steget tas hänsyn till bland annat följande värden
- hur många ord från sökfrasen som finns i dokumentet
- hur ofta ett visst ord förekommer i ett dokument (TF - termfrekvens)
- om och hur ofta de matchande orden förekommer i andra dokument (IDF - inverse document frequency) - ju mer populärt ordet är i andra dokument, desto mindre betydelsefullt är det
- hur långt är dokumentet
IDF:s funktion är viktig för oss. Elastic beräknar av prestandaskäl inte detta värde för varje dokument i indexet - i stället beräknar varje shard (indexarbetare) sin lokala IDF och använder den för sortering. Därför kan vi under indexsökningen med lågt antal dokument få väsentligt olika resultat beroende på antalet shards i ett index och dokumentfördelningen.
Låt oss tänka oss att vi har 2 shards i ett index; i den första finns det 8 dokument indexerade med ordet "fox", och i den andra endast 2 dokument med samma ord. Som ett resultat kommer ordet "fox" att skilja sig avsevärt i båda delarna, och detta kan ge felaktiga resultat. Därför bör ett index som består av endast en primär shard skapas för utvecklingsändamål:
$ curl -XPUT 'http://localhost:9200/myindex/' -d
'{"settings" : {"number_of_shards" : 1 } }'
Visning av resultaten från "fjärran" söksidor dödar ditt kluster
Som jag har skrivit i tidigare stycken delas dokumenten i ett index mellan helt individuella indexprocesser - shards. Varje process är helt oberoende och hanterar endast de dokument som har tilldelats den.
När vi söker i ett index med miljontals dokument och väntar på att få de 10 bästa resultaten, måste varje shard returnera sina 10 bäst matchade resultat till klustrets nod, som initierade sökningen. Därefter sammanställs svaren från varje shard och de 10 bästa sökresultaten väljs ut (inom hela indexet). Ett sådant tillvägagångssätt gör det möjligt att effektivt fördela sökprocessen mellan många servrar.
Låt oss föreställa oss att vår app tillåter visning av 50 resultat per sida, utan begränsningar när det gäller antalet sidor som kan visas av en användare. Kom ihåg att vårt index består av 10 primära shards (1 per server).
Låt oss se hur förvärvet av sökresultat kommer att se ut för den 1:a och den 100:e sidan:
Sida nr 1 av sökresultaten:
- Den nod som tar emot en förfrågan (controller) skickar den vidare till 10 shards.
- Varje shard returnerar sina 50 bäst matchande dokument sorterade efter relevans.
- När svaren har inkommit från varje delning sammanställer den registeransvarige resultaten (500 dokument).
- Våra resultat är de 50 bästa dokumenten från föregående steg.
Sida nr 100 av sökresultaten:
- Den nod som tar emot en förfrågan (controller) skickar den vidare till 10 shards.
- Varje shard returnerar sina 5000 bäst matchande dokument sorterade efter relevans.
- Efter att ha fått svar från varje delning sammanställer den registeransvarige resultaten (50000 dokument).
- Våra resultat är dokumenten från föregående steg positionerade 4901 - 5000.
Om man antar att ett dokument är 1 kB stort innebär det i det andra fallet att ~50 MB data måste skickas och bearbetas runt klustret för att visa 100 resultat för en användare.
Det är inte svårt att märka, att nätverkstrafiken och indexbelastningen ökar avsevärt med varje efterföljande resultatsida. Det är därför det inte rekommenderas att göra de "långa" söksidorna tillgängliga för användaren. Om vårt index är välkonfigurerat, då ska användaren hitta det resultat han är intresserad av på de första söksidorna, och vi skyddar oss mot onödig belastning av vårt kluster. För att bevisa denna regel, kontrollera, upp till vilket antal sökresultatsidor tillåter de mest populära webbsökmotorerna visning.
Vad som också är intressant är observationen av webbläsarens svarstid för successiva sökresultatsidor. Nedan kan du till exempel se svarstiderna för enskilda sökresultatsidor i Google Search (sökordet var "sökmotor"):
| Sökresultatsida (10 dokument per sida) | Svarstid
|——————————————–|—————|
1 | 250 ms | 1 | 250 ms
10 | 290 ms | 10 | 290 ms
20 | 350 ms | 20 | 350 ms
30 | 380ms | 30 | 380ms
38 (sista tillgängliga) | | | 38
I nästa del kommer jag att titta närmare på problemen med dokumentindexering.