Pełnotekstowa wyszukiwarka Sphinx

Sphinx to (w przypadku tego artykułu) pełnotekstowa wyszukiwarka potrafiąca indeksować dane z baz MySQL, PostgreSQL, czy też danych w specjalnym formacie XML. Sphinx składa się z następujących elementów:
  • indexer: narzędzie do tworzenia pełnotekstowych indeksów (indices)
  • search: proste (testowe) narzędzie do wykonywania zapytań
  • searchd: demon do przeszukiwania indeksów przez zewnętrzne aplikacji (np. skrypty www komunikujące się przez API, MySQ z SphinxSE itp.)
  • sphinxapi: zbiór bibliotek udostępniających API Sphinxa dla PHP, Pythona, Javy, Perla, czy Rubiego
Główne funkcjonalności i możliwości Sphinxa to m.in.:
  • Wysokie prędkości indeksowania (do 10 MB/s)
  • Wysokie prędkości wyszukiwania
  • Wysoka skalowalność (do 100 GB tekstu, 100 milionów dokumentów na jednym procesorze)
  • Obsługuje rozproszone wyszukiwanie (od 0.9.6)
  • Natywna obsługa MySQL
  • Obsługuje wyszukiwanie fraz
  • Obsługa słowotwórstwa angielskiego i rosyjskiego
  • Obsluga "stopwords"
Sphinx powinien być dostępny w większości repozytoriów. Należy zwrócić uwagę czy instalujemy właściwego Sphinxa, jako że istnieje kilka projektów o takiej nazwie (w tym generator dokumentacji dla Pythona). Standardowo konfiguracja powinna znajdować się w /etc/sphinx, a wszystkie pliki wykonywalne w /usr/bin.

Konfiguracja Sphinxa

By mieć działającą wyszukiwarkę danych zawartych w bazie MySQL musimy mieć - tabele z danymi, oraz musimy skonfigurowac indeks Sphinxa dla tych tabel. Dla przykładu stworzymy tabelę dla wiadomości (np. stworzoną przez Django dla naszej aplikacji):
CREATE TABLE IF NOT EXISTS `news_news` (
  `id` int(11) NOT NULL auto_increment,
  `title` varchar(255) collate utf8_polish_ci NOT NULL,
  `slug` varchar(255) collate utf8_polish_ci NOT NULL,
  `text` longtext collate utf8_polish_ci NOT NULL,
  `date` datetime NOT NULL,
  PRIMARY KEY  (`id`),
  UNIQUE KEY `slug` (`slug`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 COLLATE=utf8_polish_ci;
Dodaj do tabeli trochę wpisów, tak by było co wyszukiwać (ja dodałem newsy z F1). Gdy mamy to już za sobą musimy skonfigurować Sphinxa. Należy określić źródło danych - w tym przypadku bazę danych, oraz stworzyć przynajmniej jeden indeks, po którym będzie można szukać. Konfiguracja indeksu polega w najprostszym przypadku na podaniu zapytania pobierającego dane. Oto /etc/sphinx/sphinx.conf dla naszego przykładu:
# nasze źródło
source django_news
{
	type					= mysql
	sql_host				= localhost
	sql_user				= root
	sql_pass				=
	sql_db				= sph
	sql_port				= 3306

	sql_query				= 		SELECT `id`, `title`, `slug`, `text`, `date` 		FROM `news_news`

	sql_query_info			= SELECT * FROM `news_news` WHERE id=$id
}

# definiujemy indeks
index django_news
{
	source				= django_news
	path					= /var/lib/sphinx/data/django_news
	docinfo				= extern
	charset_type			= sbcs
}

# ustawienia, np. limit pamięci
indexer
{
	mem_limit				= 32M
}

# ustawienia demona wyszukiwania / domyślne z przykładowej konfiguracji
searchd
{
	port					= 3312
	log					= /var/lib/sphinx/log/searchd.log
	query_log				= /var/lib/sphinx/log/query.log
	read_timeout			= 5
	max_children			= 30
	pid_file				= /var/lib/sphinx/log/searchd.pid
	max_matches			= 1000
	seamless_rotate			= 1
	preopen_indexes		= 0
	unlink_old				= 1
}
W powyższej konfiguracji interesujące nas bloki to "index django_news" definiujący indeks oraz "source django_news" określający źródło - bazę danych MySQL. By zbudować wszystkie indeksy wystarczy wydac polecenie:
sphinx-indexer --config /etc/sphinx/sphinx.conf --all
By wyszukać wiadomości w stworzonym indeksie:
sphinx-search --config /etc/sphinx/sphinx.conf bmw
Sphinx 0.9.8.1-release (r1533)
Copyright (c) 2001-2008, Andrew Aksyonoff

using config file '/etc/sphinx/sphinx.conf'...
index 'django_news': query 'bmw ': returned 2 matches of 2 total in 0.000 sec

displaying matches:
1. document=1, weight=3
        id=1
        title=*coś*
        slug=*coś*
        text=*coś*
        date=2008-11-01 14:50:05
2. document=2, weight=1
        id=2
        title=*coś*
        slug=*coś*
        text=*coś*
        date=2008-11-01 14:50:34

words:
1. 'bmw': 2 documents, 5 hits

Wyszukiwanie w Sphinx z poziomu Pythona

Do obsługi Sphinxa w Pythonie możemy wykorzystać bibliotekę sphinxclient.py. By wyszukać frazę w naszym indeksie wystarczy taki kod:
# -*- coding: utf-8 -*-
from sphinxclient import *
c = SphinxClient(host='localhost', port=3312)
res = c.query('bmw', index='django_news')
for i in res['matches']:
	print i
Żeby klient mógł się podłączyć musi działać demon, którego uruchamiamy wykonując polecenie sphinx-searchd. Powyższy skrypt zwróci wynik w postaci:
(1, 3, {})
(2, 1, {})

Gdzie pierwsza liczba to wartość pola ID w tabeli, a druga to wartość atrybutu "weight" nadana przez Sphinxa.

W przypadku dużej ilości dopasowanych rekordów Sphinx zwróci domyślnie pierwsze 1000 trafień. Żeby pobrać wszystkie wyniki należy ponownie wywołać metodę query podając dodatkowo argument offset, określający "stronę" wyników.

# -*- coding: utf-8 -*-
from sphinxclient import *
c = SphinxClient(host='localhost', port=3312)
res = c.query('bmw', index='django_news')
for i in res['matches']:
	print i

if res['total_found'] > 1000:
	pages = float(res['total_found']/1000)
	ofset = 1
	while ofset <= pages:
		res = c.query(q, index='django_news', offset=ofset)
		ofset = ofset+1
		if len(res['matches']) > 0:
			for i in a['matches']:
				print i
Powyższy artykuł opisuje podstawy Sphinxa i najprostszy indeks. Bardziej szczegółowa dokumentacja dostępna jest w sieci:
In-Depth django-sphinx Tutorial
Lista artykułów poświęconych Sphinxowi
Dokumentacja
RkBlog

Podstawy Pythona, 1 November 2008

Comment article
Comment article RkBlog main page Search RSS Contact