Обработка опечаток с помощью to_tsvector и to_tsquery в postgresql - PullRequest
0 голосов
/ 15 мая 2018

У меня есть простая таблица с этими полями enter image description here

Последние два поля предназначены для индексации одно с типом данных tsvector, а другое с типом данных text.

Я хочу выполнить запрос по имени или идентификатору. Я делаю это

SELECT * FROM foo WHERE foo.searchtext @@ to_tsquery('1234 & abcd');  

Работает нормально, но теперь я хочу, чтобы опечатки были удалены, например, если имя abcd, я набираю abbd, тогда оно должно получить все возможные значения. Я видел pg_tgrm(), но он не не работает с целыми числами или tsvector

Существуют и другие варианты, которые я пытался использовать pg_tgrm(), как будто я сохранил свой индекс в другом поле searchtextstring с типом text и запросом, подобным

select *
      from foo
    where searchtextstring % '123' and searchtextstring % 'abbd';

но я не думаю, что это эффективно, а также это не работает для опечаток.

Итак, как я могу обработать опечатки с помощью to_tsquery?

Спасибо

1 Ответ

0 голосов
/ 15 мая 2018

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

pg_trgm - это путь.

Я использую этот образец таблицы:

CREATE TABLE foo (id integer PRIMARY KEY, searchtextstring text);

INSERT INTO foo VALUES (1, 'something 0987');
INSERT INTO foo VALUES (2, 'abbd 1224');

CREATE INDEX ON foo USING gist (searchtextstring gist_trgm_ops);

Это настолько мало, что PostgreSQL всегда будет использовать последовательное сканирование, поэтому давайте по возможности заставим PostgreSQL использовать индекс (чтобы мы могли смоделировать таблицу большего размера):

SET enable_seqscan = off;

Теперь давайте запрос:

EXPLAIN (COSTS off)
   SELECT * FROM foo WHERE searchtextstring % '1234'
                       AND searchtextstring % 'abcd';

                       QUERY PLAN                                        
--------------------------------------------------------
 Index Scan using foo_searchtextstring_idx on foo
   Index Cond: ((searchtextstring % '1234'::text)
            AND (searchtextstring % 'abcd'::text))
(2 rows)

Индекс используется довольно хорошо, при одном сканировании индекса!

Но запрос не возвращает строк:

SELECT * FROM foo WHERE searchtextstring % '1234'
                    AND searchtextstring % 'abcd';

 id | searchtextstring 
----+------------------
(0 rows)

Это не потому, что & ldquo; он не работает & rdquo;, а потому, что слова недостаточно похожи. Не забывайте, что в четырехбуквенном слове не так много триграмм, поэтому, если вы измените одну букву, они уже не будут такими похожими. Это не удивительно, правда?

Таким образом, мы должны снизить порог подобия, чтобы получить результат;

SET pg_trgm.similarity_threshold = 0.1;

SELECT * FROM foo WHERE searchtextstring % '1234'
                    AND searchtextstring % 'abcd';

 id | searchtextstring 
----+------------------
  2 | abbd 1224
(1 row)
...