W jaki sposób Elasticsearch potraktuje słowa zawierające litery ze znakami diakrytycznymi? Czy je wyszuka? Jak się zachowa? Takie pytania zada sobie prędzej czy później każdy kto zamierza zbudować wyszukiwarkę opartą o Elasticsearch indeksującą polskojęzyczne dokumenty (albo dokumenty z dowolnego innego języka, który wykorzystuje „ogonki”). Dziś postaram się na nie odpowiedzieć, pokazując jednocześnie jak przebiega cały proces przygotowania tekstu do wyszukiwania i jak możemy na niego wpływać.

Analiza tekstu

W jednym z wcześniejszych wpisów wspomniałem, że indeks odwrócony zbudowany jest z tokenów i związanych z nimi metadanych. Nie jest jednak tak, a przynajmniej nie w większości przypadków, że w indeksie ląduje cały tekst słowo po słowie. Inaczej mówiąc, słowo występujące w tekście nie jest tożsame z tokenem w indeksie. Dzieje się tak, ponieważ indeksowany tekst podlega analizie i to od jej wyniku zależy jak wyglądał będzie wynikowy zbiór tokenów.

Dla przykładu prześledźmy analizę najczęściej słyszanego przez programistów zdania. Na początek potraktujmy je domyślnym analizatorem Elasticsearcha (standard):

W efekcie otrzymamy:

Co jeśli użyjemy analizatora dedykowanego językowi angielskiemu? (english):

Dostaniemy:

Co tu się stanęło? Zaraz się dowiemy.

W tym miejscu trzeba jeszcze pamiętać, że analizie poddawany jest nie tylko indeksowany dokument, ale także wyszukiwana fraza. Zazwyczaj, ale nie zawsze, żeby otrzymać satysfakcjonujące rezultaty wystarczy zastosować ten sam sposób analizy zarówno podczas indeksowania, jak i wyszukiwania. Nie ma jednak problemu żeby zastosować odrębne analizatory kiedy tylko zajdzie taka potrzeba.

Cykl artykułów "Uczymy się Elasticsearch"

Ten wpis jest częścią cyklu, w którym staram się pokazać w jaki sposób możesz zbudować przyjazną dla użytkownika wyszukiwarkę, wykorzystując do tego celu potężny silnik wyszukiwania jakim jest Elasticsearch.

Do tej pory w ramach cyklu ukazały się następujące artykuły:

  1. instalacja, uruchomienie i pierwsze zapytanie
  2. kilka słów na temat Elastic Stack
  3. przydatne narzędzia
  4. indeks odwrócony Apache Lucene
  5. wyszukiwanie pełnotekstowe
  6. trafność
  7. przygotowanie tekstu do optymalnego wyszukiwania
  8. coś poszło nie tak, czyli seria moich fackupów
  9. zaczarowany zakreślacz
  10. o co jeszcze możemy zapytać?
  11. ...

Analizatory

Czym jest wspomniany już analizator (ang. analyzer)? Jest to komponent, którego zadaniem jest przyjęcie surowego tekstu i zwrócenie zbioru tokenów na podstawie zdefiniowanego zestawu reguł.

Każdy analizator składa się z trzech bloków: filtrów znaków (ang. character filters), tokenizatora (ang. tokenizer) oraz filtrów tokenów (ang. token filters). Tekst wejściowy przechodzi po kolei przez każdy z wymienionych bloków, przy czym tylko tokenizator jest wymaganym elementem. O ile tokenizator musi być dokładnie jedne, to obie sekcje filtrów mogą zawierać ich zero lub więcej.

Elasticsearch dostarcza szeroki wachlarz wbudowanych analizatorów, które najczęściej zaspokajają potrzeby użytkowników. Kiedy jednak czegoś brakuje, to łatwo i szybko możemy zbudować własny konstruując samodzielnie trzy wyżej wymienione bloki.

Filtry znaków

Filtry znaków służą do wstępnej obróbki tekstu (strumienia znaków) zanim zostanie on przekazany do tokenizatora.

Najnowsza dokumentacja wymienia trzy wbudowane, dostępne dla nas, filtry. Najmniej generyczny służy do pozbywania się znaczników HTML z tekstu. Przydatny szczególnie, kiedy przychodzi nam działać z zawartością stron internetowych. Pozostałe dwa umożliwiają podmienianie wybranych znaków lub wzorców tekstu.

Tokenizatory

Kolejnym krokiem analizy tekstu jest przerobienie strumienia znaków na tokeny, a za zadanie to odpowiedzialny jest tokenizator. Dodatkowo odpowiada on również za określenie i zapamiętanie metadanych (kolejność, pozycja itp.) poszczególnych termów, wykorzystywanych później przez niektóre rodzaje zapytań, czy narzędzie służące do zakreślania wyszukanego tekstu.

Elasticsearch dostarcza zbiór gotowych do użycia tokenizatorów i dzieli je na trzy kategorie:

  • zorientowane na wydobycie całych słów z tekstu,
  • zorientowane na wydobycie pofragmentowanych słów z tekstu oraz
  • zorientowane na obsługę ustrukturyzowanego tekstu (np. identyfikatory, adresy email, kody pocztowe).

Zobaczmy na przykładzie jak działa kilka wybranych tokenizatorów. Sposób sprawdzania jest analogiczny do przytoczonego powyżej. Do testów użyjemy jednak trochę bardziej złożonego zdania.

I tak tokenizator:

  • standard podzieli nasze zdanie na takie tokeny: Use, the, Force, Luke, is, the, most, famous, Obi, 1, Kenobi's, sentence
  • letter da nam: Use, the, Force, Luke, is, the, most, famous, Obi, Kenobi, s, sentence
  • lowercase => use, the, force, luke, is, the, most, famous, obi, kenobi, s, sentence
  • whitespace => "Use, the, Force,, Luke.", is, the, most, famous, Obi-1, Kenobi's, sentence.
  • keyword => "Use the Force, Luke." is the most famous Obi-1 Kenobi's sentence.

Filtry tokenów

Ostatnią składową analizatora są filtry tokenów. W odróżnieniu od filtrów znaków nie działają one na strumieniu znaków, ale na strumieniu… tokenów. Przypadek? Nie sądzę 😉 Jak się zapewne domyślasz strumień tokenów jest efektem działania wybranego przez nas tokenizatora.

O ile filtrów znaków Elasticsearch dostarcza zaledwie trzy, to na liście filtrów tokenów widnieje ich około pięćdziesięciu. Nie będę ich tu wszystkich teraz wymieniał, bo łatwo je znaleźć w dokumentacji, ale wspomnę o kilku najczęściej używanych lub po prostu intrygujących 😉

Pracując z językiem polskim (lub dowolnym innym z „ogonkami”) definitywnie przyda nam się filtr asciifolding konwertujące znaki spoza bloku „Basic Latin” w Unicodzie do odpowiedników w ASCII. Dzięki temu będę znaleziony zarówno kiedy wyszukacie „Prądzyński”, jak i „Pradzynski” 🙂

Filtry lowercase lub uppercase mogą się przydać kiedy chcemy, aby nasze wyszukiwanie działało niezależnie od wielkości wprowadzonych liter. Dzięki temu znajdzie się również „prądzyński”, a łącząc lowercaseasciifolding pojawi się też „pradzynski” 😉

Filtr length w zależności od ustawień usunie zbyt krótkie lub długie tokeny. stop usunie popularne w danym języku słowa (tzw. stopwords, o których wspominałem już we wcześniejszych artykułach). Stąd też „tajemnicze” zniknięcie słówek „as” w powyższym przykładzie. trim z kolei, usunie białe znaki wokół tokenów, a keep pozostawi tylko słowa znajdujące się na zdefiniowanej liście.

Elasticsearch dostarcza również bukiet filtrów wykonujących stemming, czyli usunięcie końcówki fleksyjnej i pozostawienie tylko tematu wyrazu. Przykład: „plażing” zostanie sprowadzony do słowa „plaża” 😉 Dostępnych jest kilka algorytmów wykonujących stemming, które obsługują kilkadziesiąt najpopularniejszych języków. Język polski dostępny jest po dograniu odpowiedniej wtyczki. To właśnie stemming spowodował pojawienie się „possibl” w teście analizatora english.

Normalizatory

Relatywnie nowym tworem w Elasticsearchu są normalizatory (w momencie pisania tego tekstu cały czas są w fazie beta). Idea ich działania jest zbliżona do analizatorów, z tą różnicą, że na wyjściu produkują pojedynczy token. Co za tym idzie, nie używają one tokenizatorów, a zbiór filtrów, z których mogą korzystać jest nieco okrojony. Elasticsearch na razie nie dostarcza wbudowanych normalizatorów. Użyć możemy jedynie tych samodzielnie przygotowanych (co jest tak samo proste, jak przygotowanie własnego analizatora).

The End

Odpowiednie przygotowanie tekstu ma, w przypadku Elasticsearcha, ogromne znaczenie. To dzięki niemu możemy otrzymać więcej niż satysfakcjonujące efekty działania budowanych przez nas wyszukiwarek. Elasticsearch jest już na tyle dojrzałym narzędziem, że korzystanie z dostarczanych przez niego gotowców jest w dużej części przypadków wystarczające. Niemniej jednak zdarzają się sytuacje brzegowe, w których przydaje się wiedzieć jak to wszystko działa pod spodem. Mam nadzieję, że dzisiejszy wpis Cię do tego przybliżył.

Bądź na bieżąco!

Podobają Ci się treści publikowane na moim blogu? Nie chcesz niczego pominąć? Zachęcam Cię do subskrybowania kanału RSS, polubienia fanpage na Facebooku, zapisania się na listę mailingową:




Uwaga! Jeżeli w ciągu 24-godzin od zapisania się na listę mailingową nie otrzymasz wybranego przez siebie prezentu to skontaktuj się ze mną.

Zgoda? Zapisując się do newslettera wyrażasz zgodę na przesyłanie Ci starannie wyselekcjonowanych informacji marketingowych. Powyższe dane są przechowywane w systemie MailChimp i nie są udostępniane nikomu więcej.

lub śledzenia mnie na Twitterze. Generalnie polecam wykonanie wszystkich tych czynności, bo często zdarza się tak, że daną treść wrzucam tylko w jedno miejsce. Zawsze możesz zrobić to na próbę, a jeśli Ci się nie spodoba – zrezygnować :)

Dołącz do grup na Facebooku

Chcesz więcej? W takim razie zapraszam Cię do dołączenia do powiązanych grup na Facebooku, gdzie znajdziesz dodatkowe informacje na poruszane tutaj tematy, możesz podzielić się własnymi doświadczeniami i przemyśleniami, a przede wszystkim poznasz ludzi interesujących się tą samą tematyką co Ty.

W grupie Programista Na Swoim znajdziesz wiele doświadczonych osób chętnych do porozmawiania na tematy krążące wokół samozatrudnienia i prowadzenia programistycznej działalności gospodarczej. Vademecum Juniora przeznaczone jest zaś do wymiany wiedzy i doświadczeń na temat życia, kariery i problemów (niekoniecznie młodego) programisty.

Wesprzyj mnie

Jeżeli znalezione tutaj treści sprawiły, że masz ochotę wesprzeć moją działalność online, to zobacz na ile różnych sposobów możesz to zrobić. Niezależnie od tego co wybierzesz, będę Ci za to ogromnie wdzięczny.

Na wsparciu możesz także samemu zyskać. Wystarczy, że rzucisz okiem na listę różnych narzędzi, które używam i polecam. Decydując się na skorzystanie z któregokolwiek linku referencyjnego otrzymasz bonus również dla siebie.

Picture Credits
Tribute to Patrons