Получить частичное совпадение из индексированного в GIN столбца TSVECTOR


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поскольку вы, очевидно, хотите принять слово «все» как есть и не применять stemming.

  3. Добавить, :*чтобы сделать поиск по префиксу, то есть найти все лексемы, начинающиеся с «польза».

Важно: это префикс поиска по лексемам (основам слов) в документе. Соответствие регулярному выражению без подстановочных знаков ( 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'..)идти рука об руку с инструкциями о том, что для будущих запросов этого tsv потребуется также «простая» конфигурация, чем tsquery? Я думаю, что вы должны уточнить последствия отключения отключения от tsvector / 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.