Отримайте часткове збіг із стовпця TSVECTOR, індексованого GIN


13

Я хотів би отримати результати, запитуючи це:

SELECT * FROM (
  SELECT id, subject
  FROM mailboxes
  WHERE tsv @@ plainto_tsquery('avail')
) AS t1 ORDER by id DESC;

Це працює і повертає рядки, tsvщо містять Available. Але якщо я використовую avai(випав lable), він нічого не може знайти.

Чи всі запити повинні бути в словнику? Чи не можемо ми просто запитувати такі листи? У мене є база даних, яка містить тіло електронної пошти (вміст), і я хотів би зробити її швидкою, оскільки її зростання зростає щосекунди. В даний час я використовую

... WHERE content ~* 'letters`

Відповіді:


22

Чи всі запити повинні бути в словнику?

Ні. Тому що лише індекси слова (відповідно до використовуваної конфігурації пошуку тексту ) знаходяться в індексі для початку. Але ще важливіше:

Ні . Тому що, крім цього, повнотекстовий пошук також може відповідати префіксам :

Це спрацювало б:

SELECT id, subject
FROM   mailboxes
WHERE  tsv @@ to_tsquery('simple', 'avail:*')
ORDER  BY id DESC;

Примітка 3 речі:

  1. Використовуйте to_tsquery()не plainto_tsquery()в цьому випадку тому, що ( цитуючи посібник ):

    ... plainto_tsqueryне впізнає tsqueryоператорів, міток ваги або міток збігу префіксів у своєму введенні

  2. Використовуйте 'simple'конфігурацію пошуку тексту, щоб генерувати, tsqueryоскільки ви, очевидно, хочете прийняти слово "avail" таким, яке є, і не застосовувати випливає.

  3. Додайте, :*щоб зробити це префіксом пошуку, тобто знайти всі лексеми, що починаються з 'avail'.

Важливо: Це пошук префікса у лексемах (слова стебла) у документі. Збіг регулярного вираження без символів ( content ~* 'avail') не зовсім такий! Останній не залишається закріпленим (до початку лексеми), і він також знайде "FOOavail" тощо.

Незрозуміло, чи хочете ви, щоб поведінка, викладена у вашому запиті, або еквівалент доданого регулярного виразу. Триграм-індекси ( pg_trgm), як @Evan вже запропоновано, є правильним інструментом для цього. На dba.SE є багато пов’язаних питань, спробуйте знайти .

Огляд:

Демо

SELECT *
FROM (
   VALUES
     ('Zend has no framework')
   , ('Zend Framework')
   ) sub(t), to_tsvector(t) AS tsv
WHERE tsv @@ to_tsquery('zend <-> fram:*');
 id |       t        |          tsv
----+----------------+------------------------
  2 | Zend Framework | 'framework':2 'zend':1

Нещодавній відповідь (глава Інший підхід до оптимізації пошуку ):

Електронні листи?

Оскільки ви згадали електронні листи, пам’ятайте, що аналізатор пошуку тексту визначає електронні листи та не розділяє їх на окремі слова / лексеми. Поміркуйте:

SELECT ts_debug('english', 'xangr@some.domain.com')
(email,"Email address",xangr@some.domain.com,{simple},simple,{xangr@some.domain.com})

Я замінив би розділювачі @та .у ваших електронних листах пробілом ( ' '), щоб індексувати слова, що містяться.

Крім того, оскільки ви маєте справу з іменами в електронних листах, а не з англійськими (чи якимись іншими мовами) словами , я б використовував 'simple'конфігурацію пошуку тексту, щоб відключити вихідні та інші особливості мови :

Створіть ts_vectorстовпець за допомогою:

SELECT to_tsvector('simple', translate('joe.xangr@some.domain.com', '@.', '  ')) AS tsv;

Я видаляю свою відповідь на це, тому що в будь-якому випадку, тому що я вперше я помиляюся, і я не хочу про це нагадувати. У мене є два питання до вас: 1) де це :*документально зафіксовано, і 2) чи не слід згадувати про складання з to_tsvector('simple'..)рук в руки з інструкціями про те, що подальший запит цього телевізора потребуватиме «простої» конфігурації також для tsquery? Я думаю, ви повинні уточнити наслідки відключення, що виникають із цвектора / tsquery.
Еван Керролл

@EvanCarroll: Використання "простої" конфігурації не потрібно . Він просто уникає зародження (наприклад, 'щури' до 'щура'), що може бути, а може і не бути бажаним. Не бажано для даного прикладу. Посібник: Я додав посилання вище ...
Ервін Брандштеттер

4
@EvanCarroll: Убік: Думаючи, що помилився перший раз, було б вдруге. І це було б неправильно, рекурсивно. ;)
Ервін Брандстеттер

2
@ErwinBrandstetter, Вау, твій шлях просто дав мені повний швидкий пошук. Перед вашим шляхом він занадто сильно 0.380msотримує результат. Після вашого шляху це пройшло 0.079 ms.
xangr

1
@xangr: Ні, FTS пропонує лише відповідність префіксів для лексеми. Щось більше, зверніть увагу pg_trgm. FTS швидше (з меншим показником). Можна навіть комбінувати обидва індекси ...
Ервін Брандштеттер
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.