LINUX.ORG.RU
ФорумAdmin

Помогите настроить full text search в Postgresql 9.3 с индексом.

 ,


1

1

Добрый день. Встала проблема замедленного поиска. Имеется БД ОКАТО(Общероссийский классификатор административно-территориального деления объектов) с почти 200т. записей.

Описание таблички:

CREATE TABLE IF NOT EXISTS okato (
                          id serial primary key,
                          code ltree,
                          razdel smallint,
                          name varchar,
                          centrum varchar,
                          name_vector tsvector);
INSERT INTO okato (code, razdel, name, centrum, name_vector)
       VALUES (%s,%s,%s,%s, (to_tsvector('russian', %s))); /*тут в цикле заполняю значения из python*/
CREATE INDEX name_vector_idx ON okato USING gin(name_vector);

На данный момент использую поиск через ILIKE, что , соответственно, очень медленно. Например:

EXPLAIN VERBOSE SELECT replace(ltree2text(code), '.', '_') AS code, nlevel(code) AS lvl, name
FROM okato
WHERE code @> ARRAY(SELECT code
                    FROM okato
                    WHERE name ILIKE '%ал%'
                    ORDER BY code LIMIT 2000);
-------------------------------------------------------------------------------------------------
 Seq Scan on public.okato  (cost=7342.70..13609.52 rows=199 width=65)
   Output: replace(ltree2text(okato.code), '.'::text, '_'::text), nlevel(okato.code), okato.name
   Filter: (okato.code @> $0)
   InitPlan 1 (returns $0)
     ->  Limit  (cost=7337.70..7342.70 rows=2000 width=34)
           Output: okato_1.code
           ->  Sort  (cost=7337.70..7382.51 rows=17924 width=34)
                 Output: okato_1.code
                 Sort Key: okato_1.code
                 ->  Seq Scan on public.okato okato_1  (cost=0.00..6265.33 rows=17924 width=34)
                       Output: okato_1.code
                       Filter: ((okato_1.name)::text ~~* '%ал%'::text)
(12 rows)

Этот запрос выдаёт хорошие результаты, но отрабатывает около 10сек, отадает 3587т. записей. Я читаю доку постгреса по индексам и полнотекстовому поиску.

Следующий мой шаг по полнотекстовому поиску таков:

EXPLAIN VERBOSE SELECT replace(ltree2text(code), '.', '_') AS code, nlevel(code) AS lvl, name
FROM okato
WHERE code @> ARRAY(SELECT code
                    FROM okato
                    WHERE name_vector @@ plainto_tsquery('russian','ал')
                    ORDER BY code LIMIT 2000);
---------------------------------------------------------------------------------------------------
 Seq Scan on public.okato  (cost=69.60..6336.41 rows=199 width=65)
   Output: replace(ltree2text(okato.code), '.'::text, '_'::text), nlevel(okato.code), okato.name
   Filter: (okato.code @> $0)
   InitPlan 1 (returns $0)
     ->  Limit  (cost=69.55..69.60 rows=17 width=34)
           Output: okato_1.code
           ->  Sort  (cost=69.55..69.60 rows=17 width=34)
                 Output: okato_1.code
                 Sort Key: okato_1.code
                 ->  Bitmap Heap Scan on public.okato okato_1  (cost=4.41..69.21 rows=17 width=34)
                       Output: okato_1.code
                       Recheck Cond: (okato_1.name_vector @@ '''ал'''::tsquery)
                       ->  Bitmap Index Scan on name_vector_idx  (cost=0.00..4.41 rows=17 width=0)
                             Index Cond: (okato_1.name_vector @@ '''ал'''::tsquery)
(14 rows)
Этот в свою очередь отрабатывает за 100мс, отдает 42 записи.

Делаю выводы:
-первый случай устраивает по результату, но не по скорости
-второй по скорости =), но не по результату
-что-то я делаю не так!

Помогите привести полнотекстовый поиск к хорошему результату и скорости. Буду благодарен за подсказки.

Ответ на: комментарий от bj

http://wm.ite.pl/articles/sql-ngram-index.html это читал уже. Вы мне объясните, почему этот индекс? Если я буду вводить полностью слова, например, «алтайский край», как в этом случае быть? Опыта в этом к сожалению нет пока, поэтому нуждаюсь в подробностях...

second_buddha
() автор топика

Я так понимаю, n-gram индекс необходим, когда нужен поиск по маленьким кусочкам слов , но не по лексемам, верно?

second_buddha
() автор топика
Ответ на: комментарий от second_buddha

но не по лексемам, верно?

почти 200т. записей.

Тебе не нужны лексемы, инфа 99%. Хватит простого ранжирования по совпадению начала слова и популярности.

bj
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.