Hej venner! Der er folk med forskellige niveauer af erfaring, der bidrager til vores fora - og det er dejligt! Men lige nu leder jeg efter ægte Ruby-titaner!
Elasticsearch er en søgemaskine, der er baseret på et pålideligt og modent bibliotek - Apache Lucene. Kæmpe aktivitet i git projekt Repository og implementeringen i projekter som GitHub, SoundCloud, Stack Overflow og LinkedIn vidner om dets store popularitet. Delen "Elastic" siger alt om systemets natur, hvis muligheder er enorme: fra en simpel filsøgning i lille skala over vidensopdagelse til big data-analyse i realtid. Det, der gør Elastic mere kraftfuld end konkurrenterne, er sættet af standardkonfigurationer og adfærd, som gør det muligt at oprette en klynge og begynde at tilføje dokumenter til indekset på et par minutter. Elastic konfigurerer en klynge for dig, definerer et indeks og definerer felttyperne for det første dokument, og når du tilføjer en anden server, sørger den automatisk for at dele indeksdata mellem serverne. Desværre gør den ovennævnte automatisering det uklart for os, hvad standardindstillingerne indebærer, og det viser sig ofte at være misvisende. Denne artikel er starten på en serie, hvor jeg vil beskæftige mig med de mest populære problemer, som man kan støde på i forbindelse med oprettelsen af en Elastic-baseret app.
Antallet af skår kan ikke ændres
Lad os indeksere det første dokument ved hjælp af indeks API:
$ curl -XPUT 'http://localhost:9200/myindex/employee/1' -d '{
"fornavn" : "Jane",
"efternavn": "Smith",
"steet_number": 12
}'
I dette øjeblik opretter Elastic et indeks til os med titlen myindex. Det, der ikke er synligt her, er antallet af shards, der er tildelt indekset. Shards kan forstås som individuelle processer, der er ansvarlige for indeksering, lagring og søgning af en del af dokumenterne i et helt indeks. I løbet af dokumentindekseringsprocessen beslutter elastic, i hvilken shard et dokument skal findes. Det er baseret på følgende formel:
shard = hash(document_id) % number_of_primary_shards
Det er nu klart, at antallet af primære shards ikke kan ændres for et indeks, der indeholder dokumenter. Så før du indekserer det første dokument, skal du altid oprette et indeks manuelt og angive det antal shards, som du mener er tilstrækkeligt til en mængde indekserede data:
$ curl -XPUT 'http://localhost:9200/myindex/' -d '{
"indstillinger" : {
"antal_af_skår" : 10
}
}'
Standardværdi for antal_af_skår
er 5. Det betyder, at indekset kan skaleres til op til 5 servere, som indsamler data under indekseringen. For produktionsmiljøet bør værdien af shards indstilles afhængigt af den forventede indekseringsfrekvens og dokumenternes størrelse. Til udviklings- og testmiljøer anbefaler jeg at sætte værdien til 1 - hvorfor? Det vil blive forklaret i næste afsnit af denne artikel.
Sortering af tekstsøgeresultater med et relativt lille antal dokumenter
Når vi søger efter et dokument med en sætning:
$ curl -XGET 'http://localhost:9200/myindex/my_type/_search' -d
'{
"query": {
"match": {
"title": "Den hurtige brune ræv"
}
}
}'
Elastic behandler tekstsøgning i få trin, ganske enkelt:
- sætningen fra anmodningen konverteres til den samme identiske form, som dokumentet blev indekseret i, i vores tilfælde vil det være et sæt termer:
["hurtig", "brun", "ræv"].
("the" er fjernet, fordi det er ubetydeligt),
- indekset gennemsøges for at finde de dokumenter, der indeholder mindst et af de søgte ord,
- Hvert dokument, der er et match, vurderes i forhold til, om det er relevant for søgefrasen,
- Resultaterne sorteres efter den beregnede relevans, og den første side med resultater returneres til brugeren.
I det tredje trin tages der bl.a. hensyn til følgende værdier:
- hvor mange ord fra søgefrasen der er i dokumentet
- hvor ofte et givet ord forekommer i et dokument (TF - termfrekvens)
- om og hvor ofte de matchende ord forekommer i andre dokumenter (IDF - invers dokumentfrekvens) - jo mere populært ordet er i andre dokumenter, jo mindre vigtigt er det
- Hvor langt er dokumentet?
IDF's funktion er vigtig for os. Af hensyn til ydeevnen beregner Elastic ikke denne værdi for hvert dokument i indekset - i stedet beregner hver shard (indeksarbejder) sin lokale IDF og bruger den til sortering. Derfor kan vi under indekssøgningen med et lavt antal dokumenter opnå væsentligt forskellige resultater afhængigt af antallet af shards i et indeks og dokumentfordelingen.
Lad os forestille os, at vi har to skår i et indeks; i det første er der 8 dokumenter indekseret med ordet "ræv", og i det andet er der kun 2 dokumenter med det samme ord. Som følge heraf vil ordet "ræv" være meget forskelligt i begge dele, og det kan give forkerte resultater. Derfor bør der til udviklingsformål oprettes et indeks, der kun består af én primær shard:
$ curl -XPUT 'http://localhost:9200/myindex/' -d
'{"settings" : {"number_of_shards" : 1 } }'
Visning af resultaterne af "fjerne" søgesider dræber din klynge
Som jeg har skrevet i tidligere afsnit, deles dokumenterne i et indeks mellem helt individuelle indeksprocesser - shards. Hver proces er helt uafhængig og beskæftiger sig kun med de dokumenter, som er tildelt den.
Når vi søger i et indeks med millioner af dokumenter og venter på at få top 10-resultater, skal hver shard returnere sine 10 bedst matchede resultater til klyngens Knudepunktsom indledte søgningen. Derefter samles svarene fra hver shard, og de 10 bedste søgeresultater vælges (inden for hele indekset). En sådan tilgang gør det muligt at fordele søgeprocessen effektivt mellem mange servere.
Lad os forestille os, at vores app giver mulighed for at se 50 resultater pr. side uden begrænsninger i antallet af sider, som en bruger kan se. Husk, at vores indeks består af 10 primære shards (1 pr. server).
Lad os se, hvordan erhvervelsen af søgeresultater vil se ud for den 1. og den 100. side:
Side nr. 1 af søgeresultaterne:
- Den node, der modtager en forespørgsel (controller), sender den videre til 10 shards.
- Hver del returnerer sine 50 bedst matchende dokumenter sorteret efter relevans.
- Når svarene er modtaget fra hver del, fletter controlleren resultaterne (500 dokumenter).
- Vores resultater er de 50 bedste dokumenter fra det foregående trin.
Side nr. 100 af søgeresultaterne:
- Den node, der modtager en forespørgsel (controller), sender den videre til 10 shards.
- Hver del returnerer sine 5000 bedst matchende dokumenter sorteret efter relevans.
- Når controlleren har modtaget svar fra alle dele, fletter den resultaterne (50000 dokumenter).
- Vores resultater er dokumenterne fra det foregående trin, der er placeret 4901 - 5000.
Hvis vi antager, at et dokument er 1 KB stort, betyder det i det andet tilfælde, at ~50 MB data skal sendes og behandles rundt i klyngen for at kunne se 100 resultater for en bruger.
Det er ikke svært at se, at netværkstrafikken og indeksbelastningen stiger markant for hver enkelt resultatside. Derfor anbefales det ikke at gøre de "fjerne" søgesider tilgængelige for brugeren. Hvis vores indeks er godt konfigureret, bør brugeren finde det resultat, han er interesseret i, på de første søgesider, og vi beskytter os selv mod unødvendig belastning af vores klynge. For at bevise denne regel kan du tjekke, op til hvor mange sider med søgeresultater de mest populære websøgemaskiner tillader visning.
Hvad der også er interessant, er observationen af browserens svartid for successive søgeresultatsider. Nedenfor kan du f.eks. se svartider for individuelle sider med søgeresultater i Google Search (søgeordet var "søgemaskine"):
| Søgeresultatside (10 dokumenter pr. side) Svartid
|——————————————–|—————|
| 1 250 ms
| 10 290 ms
| 20 350 ms
| 30 380 ms
| 38 (den sidste tilgængelige)
I næste del vil jeg se nærmere på problemerne med dokumentindeksering.