Wyszukiwanie pełnotekstowe (ang. full-text search) było czymś, co staraliśmy się osiągnąć w pierwszym projekcie, w którym zdecydowaliśmy się na użycie Elasticsearcha. Szybko okazało się, że pełnotekstowo można w nim wyszukiwać na 7 różnych sposobów. Dziś chciałbym przedstawić pokrótce każdy z nich.

Pamiętaj proszę, że tworząc dzisiejszy wpis testowałem wszystko na Elasticsearchu w wersji 6.3 (najnowsza jaka w tamtym momencie była dostępna). Możliwe jest, że w starszych lub nowszych wydaniach wygląda to nieco inaczej.

Rodzaje pełnotekstowych zapytań

match

Podstawowy typ zapytania pełnotekstowego. Najprostsze wywołanie wygląda tak:

Gdzie field_name_here jest nazwą pola, w którym będziemy wyszukiwali. Oznacza to ni mniej, ni więcej, że tego typu zapytanie możemy wykonać tylko na jednym, wybranym przez nas polu.

W najprostszej konfiguracji Elasticsearch wykonując powyższe zapytanie wyszuka nam wszystkie dokument, które w polu field_name_here zawierają co najmniej jedno słowo z wyrażenia: this is a test. Mówiąc pseudokodem zwrócone zostaną dokumenty spełniające warunek: (this OR is OR a OR test) IN field_name_here.

Przy pomocy jednego parametru możemy określić minimalną liczbę słów z naszego wyrażenia, które muszą zostać znalezione, żeby Elasticsearch zwrócił nam dany dokument w wynikach wyszukiwania (domyślna wartość to 1):

Łatwo konfigurowalne jest także przestawienie domyślnego operatora z OR na AND dzięki czemu otrzymamy wszystkie dokumenty, które zawierają wszystkie słowa z wyrażenia this is a test (pseudokod: (this AND is AND a AND test) IN field_name_here):

Konfigurowalne jest również wykorzystanie fuzzy matching (na pewno pojawi się odrębny wpis na ten temat), czy wyszukanie synonimów do wprowadzonych wyrażeń oraz kilka innych funkcjonalności.

Więcej: Match Query

match_phrase

Jak łatwo zauważyć, zapytanie typu match skupia się na wyszukiwaniu poszczególnych słów. Jeżeli chcielibyśmy skupić się na wyszukiwaniu całych fraz, powinniśmy użyć zapytania typu match_phrase. W najprostszej wersji mamy:

Powyższe zapytanie zwróci nam wszystkie dokumenty, które w polu field_name_here zawierają wyrażenie this is a test.

Jednym z bardziej przydatnych parametrów do konfiguracji przy tym zapytaniu jest slop (domyślna wartość to 0), który umożliwia akceptowanie pominięcia słowa lub przestawienia słów w wyrażeniu. Na przykład zapytanie:

pozwoli wyszukać zarówno this is a test, jak i this is the test oraz kilka innych zbliżonych wyrażeń. Z kolei zapytanie:

akceptuje przestawienie kolejności dwóch słów w wyrażeniu i zwróci choćby dokumenty zawierające wyrażenie is this a test.

Więcej: Match Phrase Query

match_phrase_prefix

Wariacją zapytania typu match_phrase jest zapytanie typu match_phrase_prefix. Jedyna różnica w działaniu polega na tym, że ostatnie słowo z wyszukiwanego wyrażenia jest traktowane jako prefiks. A więc zapytanie:

może wyszukać zarówno this is a test, jak i this is a team, czy this is a text.

Ważną opcją konfiguracji jest parametr max_expansions, który określa do ilu wyrażeń rozwijany jest nasz prefiks w trakcie wyszukiwania. Domyślnie jest ustawione 50.

Do czego może przydać się zapytanie typu match_phrase_prefix? Do czegoś, co twórcy Elasticsearcha określają jako search-as-you-type. Kojarzysz wyszukiwarki, które asynchronicznie zwracają rezultaty zaraz po wpisaniu kolejnych liter tekstu? No właśnie. To jest to. A dokładniej, jest to najprostsza opcja implementacji takiego zachowania w Elasticsearchu (o innych być może kiedyś również napiszę).

Więcej: Match Phrase Prefix Query

multi_match

Wspomniałem powyżej, że zapytanie typu match pozwala wyszukiwać tylko i wyłącznie w jednym polu. Gdy chcemy przeszukać kilka pól na raz możemy użyć zapytania typu multi_match:

Dopuszczalne są również wildcard-y (nie mam pojęcia jak to przetłumaczyć na język polski):

oraz boosting (podbicie ważności) poszczególnych pól:

^3 przy polu other_field_name_here oznacza, że to pole jest trzy razy ważniejsze od pola field_name_here podczas ustalania trafności otrzymanych rezultatów.

Z trafnością rezultatów związana jest tutaj jeszcze jedna rzeczy. Ze względu na to, że zapytanie multi_match pozwala na wyszukiwanie w różnych polach, pozwala również określić w jaki sposób owo wyszukiwanie koreluje ze sobą w poszczególnych polach i jak zliczane są wyniki do określenia trafności. Nie będę tu ich opisywał, ale warto wiedzieć, że mamy pięć podejść: best_fields (domyślny), most_fields, cross_fields, phrase oraz phrase_prefix.

Więcej: Multi Match Query

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. ...

common

Zapytanie typu common jest, jak dotąd, najmniej przetestowanym przeze mnie typem zapytania pełnotekstowego. Podejmuje ono temat w jaki sposób traktowane są często występujące w tekście słowa. Znów wszystko rozbija się o wspomnianą wcześniej trafność. Nie wdając się zbytnio w szczegóły chodzi o to, że w językach takich jak polski lub angielski pojawiają się słowa, które występują znacznie częściej od innych. W polskim są to na przykład spójniki (np. i, oraz, lub). Częstą praktyką wykorzystywaną przez wyszukiwarki jest po prostu pomijanie tego typu słów (które z angielskiego możemy nazywać stopwords). W Elasticsearch również możliwe jest ich pomijanie. Niestety nie jest ono najefektywniejsze. Może się bowiem zdarzyć, że wyszukiwana fraza w całości składa się ze stopwordów. Przykładem jest choćby dobrze znane: to be, or not to be. Zapytanie typu common podejmuje ten temat nieco inaczej.

Wykorzystując je określamy poziom odcięcia słów ważniejszych, od tych mniej ważnych. W efekcie ważniejsze słowa wpływają w większym stopniu na określenie trafności wyników wyszukiwania, ale te mniej ważne też się liczą i nie są pomijane.

Więcej: Common Terms Query

query_string

Zapytanie query_string jest pierwszym z dwóch typów zapytań, które przed wykonaniem parsują składnie wprowadzanego wyrażenia. Przykładowo zapytanie:

wyszuka nam dokumenty, które w polach title lub description zawierają frazę star wars lub marvel movies.

Oprócz operatorów logicznych i wyszukiwania fraz mamy również grupowanie wyrażeń ((Ala ma kota) OR (Ola ma psa)), określanie pola w jakim ma zostać wyszukane dane słowo (author:"Piotr Prądzyński" OR title:"Uczymy się Elasticsearch"), wildcardy (Manch?ster Uni*), wyrażenia regularne (nie będę dawał przykładu, bo nie chcę się pomylić 😉 ), szukanie w zakresach (date:[1986-08-05 TO 2015-04-02] i wiele, wiele innych.

Mnogość konfiguracji oraz fakt, że źle zbudowane zapytanie rzuca wyjątkiem sprawiają, że query_string nie służy do tego, żeby wystawiać je bezpośrednio zwykłym użytkownikom aplikacji. Przeznaczone jest raczej do użytku „eksperckiego”.

Więcej: Query String Query

simple_query_string

Jeżeli chcemy osiągnąć zbliżony efekt do query_string i móc spokojnie wystawić takie zapytanie do użytkownika końcowego, to możemy użyć alternatywnego simple_query_string. Powyższe zapytanie będzie wyglądało teraz tak:

W odróżnieniu od query_string, źle przygotowane zapytanie typu simple_query_string nie rzuca wyjątkiem, a więc nie ma obawy, że użytkownik coś nabroi. Dodatkowo ilość udostępnianych opcji (która jest nieco skromniejsza od tej z query_string) można łatwo zawęzić.

Więcej: Simple Query String Query

The End

Jak widzisz opcji rozwiązania problemu wygodnego wyszukiwania pełnotekstowego jest całkiem sporo. Co ciekawsze wcale nie jest tak, że musisz decydować się wyłącznie na jeden sposób. Powyższe typy można w bardzo elastyczny sposób łączyć ze sobą lub z innymi nie-pełnotekstowymi wyszukiwaniami. Dzięki temu możemy osiągnąć jeszcze bardziej efetk[o|y]wne rezultaty. Wszystko zależy wyłącznie od naszych potrzeb.

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ć :)

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.

1 000 000 zł

Milion złotych. Tak, milion złotych. Milion złotych to cel, który sobie postawiłem jakiś czas temu. Chcę zarobić milion złotych na tym blogu. Do tej pory zebrało się 34 228,77 zł, więc jak widzisz jest już co pokazać, ale do celu nadal sporo brakuje. Jeszcze nie wiem do końca jak, ale to zrobię. Na pewno nigdy nie będę pobierał żadnych opłat za dostęp do treści, bo tymi chcę się po prostu dzielić.

Wysoko ponad ten milion stawiam na szerzenie wiedzy i dotarcie do jak największej liczby osób. I tu mam prośbę do Ciebie: jeśli uważasz, ten artykuł za wartościowy, to udostępnij go proszę swoim znajomym. Przy lewej lub dolnej (na małych wyświetlaczach) krawędzi ekranu znajdziesz przyciski, które Ci to ułatwią. Jeżeli ich nie widzisz, to najprawdopodobniej zostały zablokowane przez Twój program do blokowania reklam. Niezależnie od tego, czy prześlesz ten wpis dalej, czy nie, to ja i tak dziękuję Ci serdecznie za doczytanie do tego miejsca! Do przeczytania niebawem.

PS. Jeśli mój blog przypadł Ci do gustu tak bardzo, że chciał(a)byś mi się w jakiś sposób odwdzięczyć, to mam dla Ciebie kilka ciekawych propozycji, z których możesz skorzystać. Szczególnie gorąco zachęcam do wsparcia poprzez serwis Patronite, ale jeżeli zdecydujesz się na którąkolwiek z wymienionych opcji, to serdecznie Ci za to DZIĘKUJĘ!

Picture Credits
Tribute to Patrons