Классический полнотекстовый поиск в реляционной СУБД PostgreSQL исторически опирается на связку структур tsvector и tsquery с индексами GIN. Этот механизм отлично справляется с сопоставлением стеммированных лексем и булевой фильтрацией («найти все документы со словами А и Б»), однако драматически уступает специализированным поисковым движкам (Elasticsearch, OpenSearch) в качестве ранжирования.
Стандартные ранжировщики PostgreSQL (ts_rank и ts_rank_cd) не учитывают глобальное насыщение частоты терминов и не умеют корректно нормализовать длину документа. В результате в поисковой выдаче короткая заметка с многократным повтором одного слова часто оказывается выше фундаментальной статьи с глубоким контекстом.
В сентябре 2026 года разрыв между реляционной базой и специализированными поисковыми кластерами начал стремительно сокращаться: сразу два крупных игрока — PlanetScale и Google Cloud — представили решения по интеграции вероятностного алгоритма ранжирования Okapi BM25 прямо в ядро PostgreSQL.
Почему индустрия выбирает BM25
Алгоритм BM25 (Best Matching 25) остается золотым стандартом текстового поиска благодаря двум математическим принципам:
- Насыщение частоты термина (Term Frequency Saturation): в отличие от линейного подсчета, вес слова в BM25 не растет бесконечно при повторении. Десятое упоминание термина в документе добавляет к релевантности значительно меньше веса, чем первое.
- Штраф за избыточную длину (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.
