Сервис развивается: тестируем формат, собираем идеи, улучшаем сервис. Есть идеи? Написать
Дайджесты новостей
Схема гибридного поиска в PostgreSQL: поток документов BM25 и векторный поток объединяются в базе данных и формируют ранжированную выдачу.

Полнотекстовый поиск BM25 в PostgreSQL: расширения TIN от PlanetScale и pg_textsearch от Google

Классический полнотекстовый поиск в реляционной СУБД PostgreSQL исторически опирается на связку структур tsvector и tsquery с индексами GIN. Этот механизм отлично справляется с сопоставлением стеммированных лексем и булевой фильтрацией («найти все документы со словами А и Б»), однако драматически уступает специализированным поисковым движкам (Elasticsearch, OpenSearch) в качестве ранжирования.

Стандартные ранжировщики PostgreSQL (ts_rank и ts_rank_cd) не учитывают глобальное насыщение частоты терминов и не умеют корректно нормализовать длину документа. В результате в поисковой выдаче короткая заметка с многократным повтором одного слова часто оказывается выше фундаментальной статьи с глубоким контекстом.

В сентябре 2026 года разрыв между реляционной базой и специализированными поисковыми кластерами начал стремительно сокращаться: сразу два крупных игрока — PlanetScale и Google Cloud — представили решения по интеграции вероятностного алгоритма ранжирования Okapi BM25 прямо в ядро PostgreSQL.

Почему индустрия выбирает BM25

Алгоритм BM25 (Best Matching 25) остается золотым стандартом текстового поиска благодаря двум математическим принципам:

  1. Насыщение частоты термина (Term Frequency Saturation): в отличие от линейного подсчета, вес слова в BM25 не растет бесконечно при повторении. Десятое упоминание термина в документе добавляет к релевантности значительно меньше веса, чем первое.
  2. Штраф за избыточную длину (Document Length Normalization): алгоритм сравнивает длину текущей строки со средней длиной документов по всей коллекции, устраняя искусственное преимущество длинных текстов, где любое редкое слово может встретиться случайно.

В связке с современным векторным поиском (pgvector) наличие BM25 открывает путь к нативному гибридному поиску (Hybrid Search) внутри единой транзакционной базы без сложной синхронизации через ETL и внешние брокеры сообщений.

Два пути: TIN от PlanetScale и pg_textsearch от Google

Подходы к внедрению алгоритма у двух команд различаются с точки зрения доступности и открытости:

  • PlanetScale TIN: облачная платформа представила проприетарный высокопроизводительный поисковый индекс TIN, использующий оператор ==>. Для локальной разработки, тестирования и CI инженеры выпустили открытую утилиту Lead («медленную, но точную реализацию»), позволяющую отлаживать запросы без привязки к платному облаку.
  • Google Cloud pg_textsearch: команда Google объявила предварительный доступ (Preview) к нативному поиску BM25 для управляемых СУБД AlloyDB и Cloud SQL for PostgreSQL версий 17 и 18. Решение оформлено в виде открытого расширения pg_textsearch, регистрирующего новый метод доступа к индексам bm25 и оператор сопоставления <@>.

Ниже представлен первый блок кода: подключение расширения, создание таблицы статей и построение индекса BM25:

-- Подключение расширения и создание таблицы документации
CREATE EXTENSION IF NOT EXISTS pg_textsearch;

CREATE TABLE technical_articles (
  id BIGSERIAL PRIMARY KEY,
  title TEXT NOT NULL,
  content TEXT NOT NULL,
  embedding vector(768) -- Векторные эмбеддинги для семантического поиска
);

-- Создание специализированного индекса BM25 по полю содержимого
CREATE INDEX idx_articles_bm25 ON technical_articles
USING bm25 (content);

Гибридный поиск: объединение ключевых слов и векторов

Главное прикладное преимущество нативного BM25 в PostgreSQL — возможность объединения классического поиска по ключевым словам и семантического векторного поиска в рамках одного SQL-запроса через метод Reciprocal Rank Fusion (RRF).

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

-- Единый гибридный поиск: сопоставление по BM25 и векторному расстоянию
WITH text_matches AS (
  SELECT
    id,
    -- Оператор <@> вычисляет скор соответствия BM25
    content <@> 'kubernetes load testing metalLB' AS bm25_score
  FROM technical_articles
  WHERE content <@> 'kubernetes load testing metalLB' > 0.0
  ORDER BY bm25_score DESC
  LIMIT 20
),
vector_matches AS (
  SELECT
    id,
    -- Косинусное расстояние для семантического сходства
    1 - (embedding <=> '[0.012, -0.045, ...]'::vector) AS vector_score
  FROM technical_articles
  ORDER BY embedding <=> '[0.012, -0.045, ...]'::vector ASC
  LIMIT 20
)
-- Слияние рангов (RRF) в итоговую выдачу
SELECT
  a.id,
  a.title,
  COALESCE(1.0 / (60 + t.bm25_score), 0.0) +
  COALESCE(1.0 / (60 + v.vector_score), 0.0) AS combined_rank
FROM technical_articles a
LEFT JOIN text_matches t ON a.id = t.id
LEFT JOIN vector_matches v ON a.id = v.id
WHERE t.id IS NOT NULL OR v.id IS NOT NULL
ORDER BY combined_rank DESC
LIMIT 10;
Статус зрелости и переносимость

Возможность pg_textsearch в Google Cloud находится в статусе Preview и ограничена мажорными версиями PostgreSQL 17 и 18 в управляемых кластерах AlloyDB. Индекс TIN от PlanetScale является проприетарным облачным решением, а открытый Lead намеренно оптимизирован под функциональное тестирование в CI, а не под высокие боевые нагрузки. Не переносите эти конструкции в стандартный ванильный PostgreSQL без предварительной сборки соответствующих расширений из исходного кода.

Появление поддержки BM25 знаменует новый этап эволюции СУБД: разработчики получают возможность строить сложные системы текстового и гибридного поиска непосредственно в PostgreSQL, исключая расходы на содержание и сопровождение кластеров Elasticsearch.