Polish TSearch in 8.3 (polski tsearch w postgresie 8.3)

2008-04-22 18:30:44 CEST | Tags: , , , ,

English disclaimer: this post will be in Polish only, as it’s use for other nationalities is somehow limited :)

jakiś czas temu pisałem jak skonfigurować polskiego tsearcha pod postgresem 8.2.

od tamtej pory trochę się zmieniło, pojawił się 8.3, w którym tsearch jest wbudowany w bazowego postgresa, więc instalacja jest prostsza.

zakładam, że postgres jest skonfigurowany tak by działać w utf-8. jeśli jest to iso-8859-2, to trzeba po prostu pominąć kroki odpowiedzialne za zmianę kodowania plików.

zaczynamy od wizyty na znanej z poprzedniego postu stronie: http://kurnik.pl/dictionary/.

ona, przenosi nas na sjp.pl, ale to jest mało istotne. znajdujemy najnowszy słownik w formacie ispella, i pobieramy jego źródła. dziś plik nazywa się sjp-ispell-pl-20080422-src.tar.bz2 - jutro pewnie będzie inny :)

po ściągnięciu plik rozpakowuję:

tar xvjf sjp-ispell-pl-*-src.tar.bz2

a następnie, wchodzę do źródeł i wydaję sekwencję poleceń:

cd sjp-ispell-pl-[0-9]*
sort -u -t/ +0f -1 +0 -T /usr/tmp -o polish.med polish.all
for a in polish.aff polish.med; do cat $a | iconv -f iso8859-2 -t utf-8 > $a.utf8; done
cp polish.aff.utf8 `pg_config –sharedir`/tsearch_data/polish.affix
cp polish.med.utf8 `pg_config –sharedir`/tsearch_data/polish.dict
touch `pg_config –sharedir`/tsearch_data/polish.stop

ostatnie 3 polecenia mogą wymagać użycia sudo - zależnie od tego czy user z którego to odpalaliśmy miał prawa zapisu do katalogu “share” postgresa.

po zrobieniu tego pora na “przyjemności”.

łączę się psql’em do bazy w której chcę mieć tsearcha i wykonuję następujące sqlki:

CREATE TEXT SEARCH CONFIGURATION public.polish ( COPY = pg_catalog.english );
CREATE TEXT SEARCH DICTIONARY polish_ispell (
TEMPLATE = ispell,
DictFile = polish,
AffFile = polish,
StopWords = polish
);
ALTER TEXT SEARCH CONFIGURATION polish
ALTER MAPPING FOR asciiword, asciihword, hword_asciipart,
word, hword, hword_part
WITH polish_ispell, simple;

i to zasadniczo wszystko.

już teraz powinniście zobaczyć, że parser działa i odmienia prawidłowo:

SELECT * FROM ts_debug(
'public.polish',
'W Szczebrzeszynie chrząszcz brzmi w trzcinie, i Szczebrzeszyn z tego słynie'
) where alias <> 'blank';
alias | description | token | dictionaries | dictionary | lexemes
-----------+-------------------+-----------------+------------------------+---------------+-----------------
asciiword | Word, all ASCII | W | {polish_ispell,simple} | polish_ispell | {w}
asciiword | Word, all ASCII | Szczebrzeszynie | {polish_ispell,simple} | polish_ispell | {szczebrzeszyn}
word | Word, all letters | chrząszcz | {polish_ispell,simple} | polish_ispell | {chrząszcz}
asciiword | Word, all ASCII | brzmi | {polish_ispell,simple} | polish_ispell | {brzmieć}
asciiword | Word, all ASCII | w | {polish_ispell,simple} | polish_ispell | {w}
asciiword | Word, all ASCII | trzcinie | {polish_ispell,simple} | polish_ispell | {trzcina}
asciiword | Word, all ASCII | i | {polish_ispell,simple} | polish_ispell | {i}
asciiword | Word, all ASCII | Szczebrzeszyn | {polish_ispell,simple} | polish_ispell | {szczebrzeszyn}
asciiword | Word, all ASCII | z | {polish_ispell,simple} | polish_ispell | {z}
asciiword | Word, all ASCII | tego | {polish_ispell,simple} | polish_ispell | {ten,ty}
word | Word, all letters | słynie | {polish_ispell,simple} | polish_ispell | {słynąć}
(11 rows)

teraz, zakładając, że mamy tabelkę:

CREATE TABLE test (
id SERIAL PRIMARY KEY,
title TEXT NOT NULL DEFAULT '',
lead TEXT NOT NULL DEFAULT '',
body TEXT
);

możemy dodać do niej pełnotekstowe wyszukiwanie na 2 sposoby: prosty, ale brzydki i utrudniający później pisanie. albo ciut bardziej skomplikowany, ale za to ładniejszy.

metoda 1:

CREATE INDEX tsearch_test ON test USING gin(to_tsvector('public.polish', title || lead || body));

i koniec.

minus jest taki, że teraz trzeba będzie za każdym razem:

select * from test where to_tsvector('public.polish', title || lead || body) @@ 'trzciny';

metoda 2:

alter table test add column ft tsvector;
update test set ft=to_tsvector('public.polish', title || lead || body);
CREATE TRIGGER tsvectorupdate BEFORE INSERT OR UPDATE
ON test FOR EACH ROW EXECUTE PROCEDURE
tsvector_update_trigger(ft, 'public.polish', title, lead, body);
CREATE INDEX tsearch_test ON test USING gin( ft );

jak widać - roboty trochę więcej, ale za to zapytania będą ładniejsze:

select * from test where ft @@ 'trzciny'

dodatkowo - aby sobie ułatwić testowania można zrobić coś takiego:

alter database NAZWA_BAZY_DANYCH set default_text_search_config = 'public.polish';

dzięki czemu używając np. ts_debug() nie trzeba będzie podawać słownika (w 8.2 do detekcji używał encodingu, tu jest to inaczej rozwiązane).

mam nadzieję, że opis jest jasny. no i, że się przyda :)

2 Responses to “Polish TSearch in 8.3 (polski tsearch w postgresie 8.3)”

  1. Yogi Says:

    Jedna uwaga. Wydaje mi się, że w przypadku systemu z LC_ALL=pl_PL.UTF-8 należy zmienić kodowanie pliku polish.all przed jego posortowaniem. W przeciwnym wypadku uzyskany efekt jest trochę inny od zamierzonego :)

  2. destroyer Says:

    Świetne, dzięki za tą notke ;)

Leave a Reply