Hei venner! Det er folk med forskjellige nivåer av erfaring som bidrar til forumet vårt - og det er flott! Men akkurat nå leter jeg etter ekte Ruby-titaner!
Elasticsearch er en søkemotor som er basert på et pålitelig og modent bibliotek - Apache Lucene. Stor aktivitet i git prosjekt Repository og implementeringen i prosjekter som GitHub, SoundCloud, Stack Overflow og LinkedIn vitner om dets store popularitet. Delen "Elastic" sier alt om systemets natur, hvis evner er enorme: fra et enkelt filsøk i liten skala, gjennom kunnskapsoppdagelse, til stordataanalyse i sanntid. Det som gjør Elastic kraftigere enn konkurrentene, er settet med standardkonfigurasjoner og atferd, som gjør det mulig å opprette en klynge og begynne å legge til dokumenter i indeksen på et par minutter. Elastic konfigurerer en klynge for deg, definerer en indeks og definerer felttypene for det første dokumentet som innhentes, og når du legger til en annen server, vil den automatisk håndtere fordelingen av indeksdata mellom serverne. Dessverre gjør den ovennevnte automatiseringen det uklart for oss hva standardinnstillingene innebærer, og det viser seg ofte å være misvisende. Denne artikkelen er starten på en serie der jeg vil ta for meg de vanligste problemene du kan støte på når du oppretter en Elastic-basert app.
Antall skjær kan ikke endres
La oss indeksere det første dokumentet ved hjelp av indeks API:
$ curl -XPUT 'http://localhost:9200/myindex/employee/1' -d '{
"fornavn" : "Jane",
"etternavn" : "Smith",
"steet_number": 12
}'
I dette øyeblikket oppretter Elastic en indeks for oss, med tittelen myindex. Det som ikke er synlig her, er antallet shards som er tilordnet indeksen. Shards kan forstås som individuelle prosesser som er ansvarlige for indeksering, lagring og søk i en del av dokumentene i en hel indeks. Under prosessen med dokumentindeksering bestemmer elastic i hvilken shard et dokument skal finnes. Det er basert på følgende formel:
shard = hash(document_id) % number_of_primary_shards
Det er nå klart at antallet primære skjæringer ikke kan endres for en indeks som inneholder dokumenter. Før du indekserer det første dokumentet, må du derfor alltid opprette en indeks manuelt, og angi det antallet skår som du mener er tilstrekkelig for en mengde indekserte data:
$ curl -XPUT 'http://localhost:9200/myindex/' -d '{
"innstillinger" : {
"antall_av_skår" : 10
}
}'
Standardverdi for antall_av_skår
er 5. Dette betyr at indeksen kan skaleres til opptil 5 servere, som samler inn data under indekseringen. For produksjonsmiljøet bør verdien av shards settes avhengig av forventet indekseringsfrekvens og størrelsen på dokumentene. For utviklings- og testmiljøer anbefaler jeg å sette verdien til 1 - hvorfor det? Det vil bli forklart i neste avsnitt i denne artikkelen.
Sortering av tekstsøkeresultater med et relativt lite antall dokumenter
Når vi søker etter et dokument med en frase:
$ curl -XGET 'http://localhost:9200/myindex/my_type/_search' -d
'{
"query": {
"match": {
"title": "Den raske, brune reven"
}
}
}'
Elastic behandler tekstsøk i få trinn, enkelt sagt:
- frasen fra forespørselen konverteres til samme identiske form som dokumentet ble indeksert i, i vårt tilfelle vil det være et sett med termer:
["rask", "brun", "rev"]
("den" er fjernet fordi det er ubetydelig),
- indeksen blir gjennomgått for å søke i dokumenter som inneholder minst ett av søkeordene,
- hvert dokument som er et treff, blir evaluert med tanke på om det er relevant for søkefrasen,
- sorteres resultatene etter den beregnede relevansen, og den første siden med resultater returneres til brukeren.
I det tredje trinnet tas det blant annet hensyn til følgende verdier:
- hvor mange ord fra søkefrasen som finnes i dokumentet
- hvor ofte et gitt ord forekommer i et dokument (TF - termfrekvens)
- om og hvor ofte de samsvarende ordene forekommer i andre dokumenter (IDF - invers dokumentfrekvens) - jo mer populært ordet er i andre dokumenter, desto mindre viktig er det
- hvor langt er dokumentet
Funksjonen til IDF er viktig for oss. Elastic beregner av ytelseshensyn ikke denne verdien for hvert dokument i indeksen - i stedet beregner hver shard (indeksarbeider) sin lokale IDF og bruker den til sortering. Derfor kan vi under indekssøk med et lavt antall dokumenter få svært forskjellige resultater, avhengig av antall skjæringer i en indeks og dokumentfordelingen.
La oss tenke oss at vi har to skjæringer i en indeks; i den første er det 8 dokumenter indeksert med ordet "fox", og i den andre er det bare 2 dokumenter med det samme ordet. Som et resultat vil ordet "fox" være svært forskjellig i de to skårene, og dette kan gi feil resultater. Derfor bør det opprettes en indeks som bare består av én primær del for utviklingsformål:
$ curl -XPUT 'http://localhost:9200/myindex/' -d
'{"settings" : { "number_of_shards" : 1 } }' }'
Visning av resultatene fra "fjerne" søkesider dreper klyngen din
Som jeg har skrevet i tidligere avsnitt, deles dokumentene i en indeks mellom helt individuelle indeksprosesser - shards. Hver prosess er helt uavhengig og behandler bare de dokumentene som er tilordnet den.
Når vi søker i en indeks med millioner av dokumenter og venter på å få de 10 beste resultatene, må hver klynge returnere sine 10 best matchende resultater til klyngens node, som startet søket. Deretter slås svarene fra hver del sammen, og de 10 beste søkeresultatene velges (innenfor hele indeksen). En slik tilnærming gjør det mulig å distribuere søkeprosessen effektivt mellom mange servere.
La oss tenke oss at appen vår tillater visning av 50 resultater per side, uten begrensninger når det gjelder antall sider som kan vises av en bruker. Husk at indeksen vår består av 10 primære skjæringer (1 per server).
La oss se hvordan anskaffelsen av søkeresultater vil se ut for den første og den 100. siden:
Side nr. 1 av søkeresultatene:
- Noden som mottar en forespørsel (kontrolleren), sender den videre til 10 skjæringer.
- Hver del returnerer sine 50 best matchende dokumenter sortert etter relevans.
- Etter at svarene er mottatt fra hver del, slår kontrolleren sammen resultatene (500 dokumenter).
- Resultatene våre er de 50 beste dokumentene fra forrige trinn.
Side nr. 100 av søkeresultatene:
- Noden som mottar en forespørsel (kontrolleren), sender den videre til 10 skjæringer.
- Hver del returnerer sine 5000 best matchende dokumenter sortert etter relevans.
- Etter å ha mottatt svar fra hver delingsenhet, slår kontrolleren sammen resultatene (50000 dokumenter).
- Resultatene våre er dokumentene fra forrige trinn, plassert 4901 - 5000.
Hvis vi antar at et dokument er 1 KB stort, betyr det i det andre tilfellet at ca. 50 MB data må sendes og behandles rundt i klyngen for å vise 100 resultater for én bruker.
Det er ikke vanskelig å legge merke til at nettverkstrafikken og indeksbelastningen øker betydelig for hver påfølgende resultatside. Derfor anbefales det ikke å gjøre de "fjerne" søkesidene tilgjengelige for brukeren. Hvis indeksen vår er godt konfigurert, bør brukeren finne resultatet han er interessert i på de første søkesidene, og vi vil beskytte oss mot unødvendig belastning av klyngen vår. For å bevise denne regelen kan du sjekke hvor mange søkeresultatsider de mest populære søkemotorene på nettet tillater visning av.
Det som også er interessant, er observasjonen av nettleserens responstid for påfølgende søkeresultatsider. Nedenfor finner du for eksempel svartider for individuelle søkeresultatsider i Google Søk (søkeordet var "søkemotor"):
| Søkeresultatside (10 dokumenter per side) | Svartid | Svartid
|——————————————–|—————|
1 | 250ms | 1 | 250ms
| 10 | 290ms | | | 10
| 20 | 350ms | | 20
| 30 | 380ms | | 30
| 38 (siste tilgjengelige)
I neste del vil jeg se nærmere på problemene knyttet til dokumentindeksering.