Полнотекстовый поиск в PostgreSQL

Полнотекстовый поиск (Full Text Search, FTS) позволяет искать в базе данных определенные слова, фразы или предложения. Это чрезвычайно полезно, когда вам нужно найти соответствующие документы или записи в большом текстовом корпусе.

PostgreSQL имеет встроенную поддержку полнотекстового поиска, что упрощает его реализацию в ваших приложениях баз данных.

Как работает полнотекстовый поиск в PostgreSQL

Ключевые компоненты, участвующие в полнотекстовом поиске:

  • Parser: он разбивает текстовые документы на токены, которые представляют собой слова, числа или синтаксис языка. Словарь может использоваться синтаксическим анализатором для формирования слов.
  • Tsvector: это доступное для поиска представление документа, созданного анализатором. Он содержит лексемы, которые представляют собой нормализованные слова с удаленными префиксами.
  • Tsquery: это фактический текстовый запрос, введенный пользователем. Он также разбирается на лексемы.
  • Ранжирование: определяет, насколько точно tsvector соответствует tsquery и соответствующим образом сортируется. Триггеры используются для поддержания актуальности tsvectors.

Когда вы запускаете текстовый поисковый запрос в PostgreSQL, он «за кулисами» выполняет следующие шаги:

  1. Запрос разбирается на лексемы с помощью словаря.
  2. Соответствующий tsvector генерируется из текста целевого документа.
  3. Лексемы tsquery сравниваются с tsvector для поиска совпадений.
  4. Ранг вычисляется на основе найденных совпадений.
  5. Результаты сортируются по рангу и возвращаются.

Теперь давайте посмотрим, как мы можем использовать этот процесс, включив полнотекстовый поиск в базе данных PostgreSQL.

Включение полнотекстового поиска в PostgreSQL

Функцию полнотекстового поиска необходимо включить в конкретной базе данных, прежде чем вы сможете ее использовать. Есть несколько способов сделать это:

Вариант 1. Использование CREATE DATABASE (рекомендуется)

Самый простой способ — включить FTS при создании самой базы данных:

CREATE DATABASE mydb WITH TEMPLATE=template0 LC_COLLATE=‘C‘ LC_CTYPE=‘C‘ ENCODING=‘UTF8‘ CONNECTION LIMIT=-1 IS_TEMPLATE=FALSE ;

Настройки LC_COLLATE и LC_CTYPEздесь определяют последовательность сортировки и классификацию символов — оба эти параметра необходимы для правильной работы FTS.

Вариант 2. Использование ALTER DATABASE

Если ваша база данных уже создана, вы можете изменить ее, чтобы включить полнотекстовый поиск:

ALTER DATABASE mydb SET lc_collate TO ‘C‘;
ALTER DATABASE mydb SET lc_ctype TO ‘C‘;

Это изменит настройки локали базы данных, необходимые для FTS.

Вот и все! Теперь ваша база данных готова к использованию полнотекстового поиска. В следующих разделах мы рассмотрим ключевые функции, операторы и шаги для выполнения поисковых запросов.

Использование tsvector и tsquery для поиска

PostgreSQL предоставляет два основных типа данных, которые используются для полнотекстового поиска:

  1. tsvector — сохраняет документ в лексическом формате с возможностью поиска.
  2. tsquery — здесь хранится пользовательский запрос, который выполняется по tsvector.

Ключевые функции их использования:

  • to_tsvector() — преобразует текстовый документ в tsvector для индексации.
  • to_tsquery() — анализирует текстовый запрос в tsquery.
  • @@ — оператор для сопоставления tsvector с tsquery.

Давайте посмотрим, как они работают в действии.

Рассмотрим таблицу articles, имеющую текстовое поле body, в котором необходимо выполнить поиск:

CREATE TABLE articles(
   id SERIAL PRIMARY KEY,
   title TEXT,
   body TEXT 
);

Чтобы включить полнотекстовый поиск по body полю, нам нужно сгенерировать его tsvector представление. Это делается функцией to_tsvector:

SELECT to_tsvector(body) FROM articles; 

Это разлагается body на лексемы в соответствии с настройками локали базы данных. Предположим, мы вставляем в эту таблицу некоторый текст:

INSERT INTO articles VALUES 
  (1, ‘Postgres Guide‘, ‘Learn how to use PostgreSQL from basics to advanced‘),
  (2, ‘MySQL vs Postgres‘, ‘Compare the differences between MySQL and Postgres‘); 

Теперь, если мы используем to_tsvectorна теле, будут извлечены такие ключевые слова, как:

‘learn‘:4 ‘use‘:5 ‘postgre‘:1,6 ‘bas‘:2 ‘advanc‘:3  
‘mysql‘:1 ‘postgre‘:3 ‘compar‘:2 ‘differ‘:4

Далее нам нужно проанализировать строку поискового запроса, введенную пользователем, в tsquery, используя to_tsquery:

SELECT to_tsquery(‘Postgres guide‘);

Это возвращает:

‘postgre‘:1 ‘guide‘:2

Наконец, чтобы выполнить фактический текстовый поиск:

SELECT title 
FROM articles 
WHERE to_tsvector(body) @@ to_tsquery(‘Postgres guide‘);

Оператор @@ сопоставления tsvector сравнит tsquery с tsvectors документа и вернет все совпадающие строки.

Эта архитектура полнотекстового поиска обеспечивает большую гибкость при создании сложных функций поиска в PostgreSQL. Далее мы рассмотрим некоторых продвинутых операторов, предоставляемых FTS.

Операторы расширенного полнотекстового поиска

PostgreSQL предоставляет несколько операторов, обеспечивающих детальный контроль над поисковыми запросами:

1. Оператор & (И)

Используйте & для поиска документов, соответствующих ВСЕМ условиям:

SELECT * FROM articles 
WHERE to_tsvector(body) @@ to_tsquery(‘Postgres & guide‘);

Это вернет строки, только если они содержат как «postgres», так и «guide».

2. Оператор | (ИЛИ)

Используйте | для поиска документов, соответствующих ЛЮБОМУ из условий:

SELECT * FROM articles
WHERE to_tsvector(body) @@ to_tsquery(‘Postgres | MySQL‘);  

Это вернет строки, содержащие либо «postgres», либо «mysql».

3. Оператор ! (НЕ)

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

SELECT * FROM articles
WHERE to_tsvector(body) @@ to_tsquery(‘Postgres & !MySQL‘);

Это вернет строки, содержащие «postgres», но НЕ «mysql».

4. Поиск фраз

Используйте двойные кавычки для точного соответствия фразам:

SELECT * FROM articles
WHERE to_tsvector(body) @@ to_tsquery(‘"Postgres guide"‘); 

Это вернет строки, содержащие точную фразу «Руководство по Postgres».

5. Соответствие префикса

Используйте :* для поиска префикса:

SELECT * FROM articles 
WHERE to_tsvector(body) @@ to_tsquery(‘postgre:*‘);

Это будет соответствовать всем словам, начинающимся с «postgre», например postgres, postgresql и т. д.

Умно комбинируя эти операторы, вы можете создавать очень мощные поисковые запросы в PostgreSQL.

Настройка языков в PostgreSQL FTS

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

PostgreSQL использует конфигурации текстового поиска для определения поведения языка.

Ключевыми компонентами конфигурации являются:

  • Парсер: разбивает текст на токены.
  • Словари: они используются для определения слов.
  • Стоп-слова: общие слова, такие как «есть», «the», которые игнорируются.

Некоторые примеры конфигураций, поставляемых с PostgreSQL:

  • english – Парсер английского языка
  • russian — Парсер для русского языка
  • Hindi – Парсер языка хинди

Чтобы использовать другую конфигурацию, вам необходимо:

  1. Создайте конфигурацию, если она еще не создана.
  2. Измените базу данных, чтобы установить default_text_search_config.

Например, чтобы использовать русскоязычную конфигурацию:

-- Create config if not exist
CREATE TEXT SEARCH CONFIGURATION russian (COPY=russian); 

-- Set default config for database  
ALTER DATABASE mydb SET default_text_search_config = ‘russian‘;

Теперь to_tsvector по умолчанию будет использоваться русский парсер, словарь и стоп-слова.

Вы также можете указать конфигурацию в to_tsvectorсамом вызове функции:

SELECT to_tsvector(‘russian‘, ‘Text in russian‘); 

Это позволяет использовать разные языки в одном столбце таблицы.

Благодаря пользовательским конфигурациям PostgreSQL может обеспечить возможности точного полнотекстового поиска на различных языках мира.

Повышение релевантности с помощью весов

По умолчанию каждое индексированное слово в tsvector считается одинаково важным при сопоставлении с tsquery. Но на самом деле некоторым словам, таким как названия продуктов или редкие ключевые слова, необходимо придавать большее значение.

PostgreSQL позволяет вам настроить, насколько сильно каждая лексема влияет на релевантность документа посредством весов.

Вес указывается как значение A, B, C или D, где D является наибольшим весом.

Например, чтобы присвоить более высокие веса названиям продуктов и редким словам:

SELECT to_tsvector(‘The apple iphone is a revolutionary phone‘::text,
   ‘iphone‘:C‘apple‘:B);

В результате получается такой tsvector:

‘apple‘:2B ‘iphon‘:3C ‘revolutionari‘:D ‘phone‘:D

Термины запроса «iphone» и «apple» будут точно соответствовать этому tsvector и поднимут строку вверх в результатах поиска.

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

В целом, веса позволяют вам точно настроить релевантность результатов поиска с помощью индивидуального повышения.

Результаты ранжирования с помощью Postgres FTS

Ранг совпадающего документа определяет его позицию в результатах поиска. PostgreSQL FTS позволяет настроить способ расчета этого ранга с помощью следующих инструментов:

1. Функции ранжирования

По умолчанию результаты сортируются по ts_rank функции. При этом используется комбинация оценки TF-IDF и совпадений весов.

Вы можете определить свою собственную функцию ранжирования, если хотите рассчитывать рейтинг по-другому.

Например:

CREATE FUNCTION my_rank(tsvector, tsquery) RETURNS float4 AS 
$$
  -- Custom ranking logic
$$ LANGUAGE sql;

SELECT title, my_rank(to_tsvector(body), query) as rank
FROM articles, to_tsquery(‘guide‘) query
WHERE query @@ body
ORDER BY rank DESC;

Это позволяет вам настроить формулу ранжирования в соответствии с вашими конкретными потребностями.

2. Корректировка рейтинга

Функция ts_rank_cd() применяет дополнительные штрафы и повышает показатель ts_rank по умолчанию. Это позволяет, например, нормализовать короткие и длинные документы.

Например:

SELECT ts_rank_cd(to_tsvector(body), query) FROM articles, query;  

3. Объединение нескольких факторов

Вы можете комбинировать ts_rank, пользовательские функции и корректировки для расчета общего ранга:

SELECT *, 
    ts_rank_cd(to_tsvector(body), query) + my_rank(title_vector, query) AS rank  
FROM articles, query
ORDER BY rank DESC;

Это дает вам полную гибкость в настройке механизма ранжирования поиска в PostgreSQL.

Оптимизация производительности FTS

Хотя полнотекстовый поиск очень полезен, он также может стать узким местом в производительности, если его не оптимизировать должным образом. Некоторые рекомендации по повышению скорости текстовых поисковых запросов:

  • Создание индекса для tsvector. Добавление индекса GIN в столбец tsvector ускоряет работу оператора сопоставления @@.
  • Уменьшите размер индекса: ограничьте шумные стоп-слова, уменьшите длину, частоту и т. д. в tsvector.
  • Таблица поиска по разделам: разбивайте данные по нескольким меньшим таблицам для лучшего параллелизма.
  • Используйте корректировки ранжирования. Более простое ранжирование снижает вычислительную нагрузку. Избегайте дорогостоящих функций.
  • Избегайте стоп-слов в поиске. Исключите стоп-слова из tsquery, чтобы улучшить фильтр.
  • Нижний default_text_search_config: простые конфигурации работают быстрее, чем сложные.
  • Увеличьте Maintenance_work_mem: до 1 ГБ для генерации сложных векторов.
  • Асинхронное обновление индекса: используйте триггеры для обновления индекса без замедления записи.

С помощью приведенных выше советов вы можете оптимизировать полнотекстовый поиск в PostgreSQL для поддержки высокопроизводительных приложений промышленного уровня.

Заключение

Возможности полнотекстового поиска сегодня имеют решающее значение для многих приложений. Как мы видели, PostgreSQL предоставляет очень надежные и масштабируемые функции для добавления полнотекстового поиска в вашу базу данных.

Ключевые выводы:

  • Включите FTS в базе данных, используя правильные настройки локали.
  • Используйте tsvector и tsquery для поисковых запросов.
  • Используйте расширенные операторы, такие как AND, OR, NOT, для сложной фильтрации.
  • Настройка языков и словарей
  • Повысьте релевантность за счет весов и рейтинга.
  • Оптимизация производительности за счет правильной индексации и настройки.

Здесь рассматриваются основы реализации производительного и высококачественного текстового поиска с помощью PostgreSQL. Функциональность, предоставляемая «из коробки», упрощает начало работы.

Кроме того, возможность настройки языков, веса и рейтинга позволяет вам постоянно улучшать качество поиска. Реализация текстового поиска никогда не была проще!