Silniki wyszukiwania pełnotekstowego, a SphinxSearch z pewnością może do takich się zaliczyć, stworzone zostały z myślą sprawnego i wydajnego wyszukiwania tekstu, niekoniecznie przechowując go jednocześnie. Zatem, typowy scenariusz aplikacji korzystającej z takiego silnika wygląda następująco: 1. wyszukiwanie dokumentów za pomocą silnika wyszukiwania (np. SphinxSearch), 2. pobranie właściwej treści dokumentów (z bazy danych bądź innego źródła ) dla wyników znalezionych w poprzednim kroku.
Inny, często spotykany przypadek, jest taki, iż istniejącą aplikację chcemy rozszerzyć o możliwość wyszukiwania - w tym przypadku konieczne będzie wprowadzenie szeregu zmian, sposób postępowania będzie podobny do tego opisanego powyżej: wyszukiwanie, np. korzystając z API, pobranie wymaganych informacji dla znalezionych wyników. Tutaj z pomocą przychodzi rozwiązanie znane jako SphinxSE.
SphinxSE (ang. Sphinx Storage Engine) to jeden z dostępnych silników przechowywania (ang. storage engine) takich jak np. InnoDb czy też MyISAM. Nie przechowuje on jednak danych sam w sobie a jest jedynie wbudowanym klientem umożliwiającym komunikację ze Sphinxem, wykonywanie zapytań oraz pobieranie wyników. Zaletą tego rozwiązania jest to, że przedstawione powyżej dwa kroki można zredukować do jednego - w jednym kroku wyszukujemy dokumenty oraz pobieramy właściwą treść dokumentu dla znalezionych wyników. Co więcej, także w przypadku rozbudowania istniejącej aplikacji o wyszukiwanie, koszt zmian nie będzie duży - wystarczy jedynie dodać do istniejącego zapytania SQL warunek zgodny ze składnią wyszukiwania SphinxSE i złączyć wyniki ze Sphinxa z rezultatami otrzymanymi przez pierwotne zapytanie do bazy.
ENGINE=SPHINX
Rolę pośrednika pomiędzy search daemonem Sphinxa (searchd) a bazą danych (MySQL, MariaDb) pełni pomocnicza tabela o strukturze:
Nazwa tabeli oczywiście jest dowolna, ale konieczne jest aby pierwsze trzy kolumny były następujących typów:
- pierwsza - INTEGER UNSIGNED lub BIGINT: identyfikator dokumentu
- druga - INTEGER bądź BIGINT: waga (score) znalezionego dokumentu
- trzecia - VARCHAR lub TEXT: zapytanie oraz powinna być indeksowana
Pozostałe, dodatkowe kolumny mogą być typów INTEGER, TIMESTAMP, BIGINT, VARCHAR lub FLOAT - będą reprezentowały atrybuty odpowiadające nazwom kolumn (stąd wymagana zgodność typów kolumn dla odpowiadających im atrybutom). Dodatkowo istnieją specjalne kolumny _sph_groupby, _sph_count, _sph_distinct zawierające liczniki dla klauzul @groupby, @count oraz @distinct. Ponadto, dla tabeli-pośrednika trzeba ustawić ENGINE=SPHINX.
Po wysłaniu zapytania i otrzymaniu wyników ze Sphinxa, pomocnicza tabela będzie zawierała znalezione wyniki: identyfikator dokumentu - kolumna id, score wyniku - weight oraz wartości atrybutów w kolejnych kolumnach o nazwach odpowiadającym nazwom atrybutów. Złączając otrzymane wyniki (sphinx_results) z tabelą (lub tabelami) przechowującymi szczegółowe informacje o dokumentach rozwiążemy problem opisany na początku artykułu.
Przykład:
Ze złączenia wyników ze Sphinxa z innymi tabelami będziemy mogli zrezygnować jeśli w indeksie będziemy przechowywali (w postaci atrybutów) także wartości, w których wyszukujemy (np. title, content itd.). W tym celu konieczna jest zmiana konfiguracji indeksu:
W tym przypadku nasze zapytanie będzie wyglądało następująco:
Składania zapytań SphinxSE została szczegółowo opisana w dokumentacji, przedstawię jedynie typowe, godne uwagi przypadki:
- filtrowanie - w pierwszej kolejności wykonywane jest wyszukiwanie dla podanej frazy a następnie uzyskane wyniki są filtrowane po wybranym atrybucie, dlatego warto rozważyć (ze względów optymalizacyjnych) czy nie korzystniej będzie zaindeksować i przeszukiwać pole zawierające atrybut
- grupowanie - istnieje możliwość grupowania bezpośrednio po atrybucie (groupby=attr:attr_name) bądź korzystając z predefiniowanego ziarna czasowego (jeśli atrybut typu timestamp), np. ziarno dzienne (groupby=day:attr_name), tygodniowe (groupby=week:attr_name) itd. Dodatkowo _sph_count będzie zawierał liczbę wyników w danej grupie
- escape’owanie wartości specjalnych w zapytaniach - wartości specjalne takie jak np. ; bądź = czy też , (przecinek) escape’ujemy za pomocą trzech / (slash). Dodatkowo jeśli w zapytaniu pojawia się ” (cudzysłów) a treść całego zapytania SphinxSE (query) zawieramy również pomiędzy ”“, w takim przypadku cudzysłów w szukanej frazie należy poprzedzić siedmioma znakami slash, ponieważ escape’ujemy wyrażenie /” (trzy / dla slasha oraz kolejne trzy dla “). Przykład - szukamy frazy “test” ‘test’ test% @;,=
Podsumowując, pomimo tego iż SphinxSE nie oferuje pełnych możliwości wyszukiwania za pomocą SphinxSearch oraz wymaga znajomości specyficznej składni zapytań, warto rozważyć wykorzystanie tego rozwiązania w naszej aplikacji. Możemy w prosty i bardzo wydajny sposób, a przy tym nie wymagający dużych nakładów pracy, umożliwić zaawansowane wyszukiwanie w naszym serwisie.
Przydatne linki:
- http://sphinxsearch.com/docs/current.html#sphinxse
- http://www.slideshare.net/bytebot/mariadb-with-sphinxse
- https://mariadb.com/kb/en/sphinxse/
- http://www.pythian.com/blog/using-the-sphinx-search-engine-with-mysql/
- http://www.mysqlperformanceblog.com/2013/01/15/sphinx-search-performance-optimization-attribute-based-filtering/
tagi: MariaDb , MySQL , search , SphinxSE , search , sphinx , sphinxsearch