Поиск редко сводится к одному универсальному сценарию. Пользователь, вводящий "cheap running shoes", хочет точных совпадений по ключевым словам, а пользователь, задающий "comfortable footwear for jogging", выражает то же намерение другими словами. Традиционный полнотекстовый поиск хорошо справляется с первым случаем. Векторный поиск решает второй. Гибридный поиск объединяет оба в одном запросе, так что вам не приходится выбирать.
В современных поисковых системах это часто описывается как комбинирование лексического (разреженного) поиска с семантическим (плотным) поиском. Разные термины, одна идея: точное совпадение плюс смысл.
Что такое гибридный поиск?
Гибридный поиск одновременно выполняет полнотекстовый (BM25) поиск и векторный (KNN) поиск, а затем объединяет два списка результатов в один. Документы, получившие высокий балл по любому из сигналов (или по обоим), поднимаются наверх.
Полнотекстовый поиск отлично работает с точными ключевыми словами, редкими терминами и идентификаторами. Векторный поиск понимает смысл — например, что "automobile" и "car" обозначают одну и ту же концепцию, — потому что их эмбеддинги находятся рядом в векторном пространстве.
У каждого метода есть свои слабые места:
- Полнотекстовый затрудняется с синонимами и естественным языком
- Векторный поиск затрудняется с точными токенами, такими как SKU, коды ошибок и идентификаторы
Гибридный поиск охватывает оба.
Как гибридный поиск вписывается в современные поисковые приложения
Гибридный поиск — это этап извлечения: часть системы, которая находит релевантных кандидатов в ваших данных.
Вместо того чтобы полагаться на один метод, гибридный поиск комбинирует совпадения по ключевым словам и семантическое сходство, чтобы сразу получать более сильный набор результатов.
На практике это означает:
- Лучшее покрытие (recall) для запросов на естественном языке
- Точное совпадение для идентификаторов, таких как SKU или коды ошибок
- Более релевантные результаты без сложной логики запросов
Цель проста: вернуть наилучших возможных кандидатов за один проход, используя оба сигнала вместе.
Когда следует использовать гибридный поиск?
Гибридный поиск подходит, когда:
- Ваши запросы сочетают намерение и детали. Поиск вроде
python error 403 forbiddenвыигрывает от точности по ключевому слову в коде ошибки и семантического понимания описания проблемы. - Вы создаёте конвейер RAG. Retrieval-Augmented Generation требует подачи самых релевантных фрагментов в LLM. Гибридное извлечение постоянно находит более релевантные документы, чем любой из методов по отдельности.
- Ваш каталог содержит как структурированные, так и неструктурированные данные. Товары электронной коммерции имеют точные названия и номера моделей (территория ключевых слов), но также описания, где смысл важнее точных формулировок.
- Вы не можете предсказать, как пользователи будут искать. Некоторые вставят точные фразы, другие опишут, что ищут, на естественном языке. Гибридный поиск элегантно справляется с обоими случаями.
Как это работает
Manticore использует Reciprocal Rank Fusion (RRF) для объединения результатов. Идея проста: вместо попытки сравнивать сырые оценки BM25 с расстояниями KNN, которые живут на совершенно разных шкалах, RRF смотрит на позиции в ранжировании. Документ, занявший #1 в текстовых результатах и #3 в результатах KNN, получает более высокий комбинированный балл, чем документ, появившийся только в одном списке.
Вот простой пример. Предположим, что текстовый поиск и поиск KNN возвращают свои топ‑3:
Результаты текстового поиска:
| Ранг | Документ |
|---|---|
| 1 | Doc A |
| 2 | Doc B |
| 3 | Doc C |
Результаты поиска KNN:
| Ранг | Документ |
|---|---|
| 1 | Doc C |
| 2 | Doc A |
| 3 | Doc D |
RRF оценивает каждый документ по формуле 1 / (rank_constant + rank). При значении по умолчанию rank_constant=60:
| Документ | Вклад текста | Вклад KNN | Балл RRF |
|---|---|---|---|
| Doc A | 1/(60+1) = 0.0164 | 1/(60+2) = 0.0161 | 0.0325 |
| Doc C | 1/(60+3) = 0.0159 | 1/(60+1) = 0.0164 | 0.0323 |
| Doc B | 1/(60+2) = 0.0161 | — | 0.0161 |
| Doc D | — | 1/(60+3) = 0.0159 | 0.0159 |
Doc A занимает первое место, потому что появляется почти вверху обоих списков. Doc C находится рядом по той же причине. Doc B и Doc D присутствуют только в одном списке, поэтому их баллы ниже.
Почему RRF?
Существует два распространённых способа объединения результатов:
- Слияние на основе рангов (RRF) — простое, надёжное, без необходимости нормализовать оценки
- Слияние на основе оценок — сначала нормализовать оценки, а затем объединять
Manticore использует RRF, потому что этот метод хорошо работает сразу из коробки и избавляет от проблем с калибровкой оценок.
Внутри гибридный запрос разбивается на независимые подзапросы: один для полнотекстового поиска, один или несколько для KNN. Они выполняются параллельно, а после завершения RRF объединяет их ранжированные списки результатов в один итоговый список.
Почему нельзя просто использовать один из методов?
Рассмотрим базу знаний поддержки со статьями о разных кодах ошибок — сбоях соединения, проблемах аутентификации и ошибках синхронизации. Пользователь видит ошибку E-5020 на экране и сообщает: "Не могу подключиться к серверу."
Векторный поиск понимает симптом, но не код ошибки. KNN по запросу "не могу подключиться к серверу" возвращает:
| # | Заголовок | Расстояние KNN |
|---|---|---|
| 1 | Ошибка E-5030: Ошибка разрешения DNS | 0.572 |
| 2 | Ошибка E-2091: Превышено время загрузки приложения | 0.583 |
| 3 | Ошибка E-5020: Несоответствие SSL‑сертификата | 0.605 |
| 4 | Ошибка E-5010: Сервис недоступен | 0.622 |
| 5 | Ошибка E-4001: Не удалось войти | 0.665 |
Правильная статья (E-5020) оказывается только на позиции #3. KNN ставит выше ошибки DNS и таймаутов, потому что их описания семантически ближе к фразе "не могу подключиться". Реальная проблема — несоответствие SSL‑сертификата — использует совсем другую лексику, поэтому получает более низкий балл.
Можно подумать: просто добавить код ошибки в запрос KNN. Но "E-5020" и "E-5010" — это произвольные идентификаторы без семантического значения, и эмбеддинги воспринимают их как почти одинаковые токены. KNN по запросу "E-5020 не могу подключиться к серверу" действительно поднимает E-5020 на позицию #1, но лишь потому, что добавленный текст меняет семантический контекст — сам код ошибки почти ничего не весит.
Гибридный поиск решает эту проблему, отправляя каждый сигнал туда, где он работает лучше всего: код ошибки — в полнотекстовый поиск, симптом — в KNN.
SELECT title, hybrid_score()
FROM support_articles
WHERE knn(embedding, 'can not connect to the server')
AND MATCH('E-5020')
LIMIT 5
OPTION fusion_method='rrf';
| # | Title | Hybrid score |
|---|---|---|
| 1 | Error E-5020: SSL Certificate Mismatch | 0.032 |
| 2 | Error E-5030: DNS Resolution Failed | 0.016 |
| 3 | Error E-2091: App Loading Timeout | 0.016 |
| 4 | Error E-5010: Service Unavailable | 0.016 |
| 5 | Error E-4001: Login Failed | 0.015 |
E-5020 поднимается с #3 на #1 и получает почти вдвое более высокий балл, чем остальные. Полнотекстовый поиск воспринимает «E-5020» как точную строку — не похожую на «E-5010», не "почти близкую", а просто другую. KNN при этом гарантирует, что связанные ошибки соединения всё равно остаются ниже для контекста.
Это основная ценность гибридного поиска:
- Идентификаторы → полнотекстовый поиск
- Смысл → векторный поиск
Каждый метод покрывает слепую зону другого.
С чего начать
Самый простой способ выполнить гибридный поиск — использовать hybrid_match(). Если в вашей таблице настроено автоматическое создание эмбеддингов, одна строка делает всё: поиск по тексту, генерацию эмбеддингов, поиск KNN и объединение через RRF.
SELECT id, hybrid_score()
FROM products
WHERE hybrid_match('running shoes');
JSON-эквивалент:
POST /search
{
"table": "products",
"hybrid": { "query": "running shoes" }
}
Manticore:
- генерирует эмбеддинги
- выполняет оба поиска параллельно
- объединяет результаты
Полный контроль: явный MATCH + KNN
Если вы хотите передавать собственные векторы или настраивать отдельные подзапросы, используйте явную форму с MATCH() и KNN() в условии WHERE:
SELECT id, hybrid_score()
FROM products
WHERE match('running shoes')
AND knn(embedding, (0.12, 0.45, 0.78, ...))
OPTION fusion_method='rrf';
POST /search
{
"table": "products",
"knn": {
"field": "embedding",
"query_vector": [0.12, 0.45, 0.78, "..."]
},
"query": { "match": { "title": "running shoes" } },
"options": { "fusion_method": "rrf" }
}
Каждый результат включает:
hybrid_score()— объединённый балл (используется для сортировки по умолчанию)weight()— балл BM25knn_dist()— векторное расстояние
Фильтры по атрибутам (AND category = 'footwear') применяются к обоим подзапросам.
Настройка
Поведение объединения настраивается тремя опциями:
rank_constant— контролирует, насколько верхние позиции доминируют в объединённом балле. Низкие значения (например, 10) делают позицию #1 значительно более значимой, чем позицию #5. Высокие значения сглаживают кривую. См. rank_constant .fusion_weights— позволяет задать разную важность каждому подзапросу. Если релевантность текста важнее, чем векторное сходство, задайте больший вес. См. fusion_weights .window_size— сколько результатов каждый подзапрос получает до объединения. По умолчанию Manticore вычисляет это автоматически из параметров KNN и LIMIT запроса. См. window_size .
Слияние нескольких векторов
Гибридный поиск не ограничивается одним текстовым поиском и одним поиском KNN. Можно объединять несколько векторных поисков — это полезно, когда в данных есть несколько разных семантических измерений. Например, у товара в e-commerce есть текстовое описание и фотография. Пользователь, ищущий «минималистичные белые кроссовки», опирается сразу на оба сигнала: название должно соответствовать стилю, а изображение товара — выглядеть так, как он это представляет. Если закодировать название и изображение в отдельных векторных пространствах, их можно искать одновременно и позволить RRF выводить наверх товары, которые соответствуют всем трём сигналам — ключевым словам, смыслу текста и визуальному сходству:
SELECT id, hybrid_score()
FROM products
WHERE match('running shoes') AS text
AND knn(title_vec, (0.12, 0.45, ...)) AS title_sim
AND knn(image_vec, (0.88, 0.21, ...)) AS image_sim
OPTION fusion_method='rrf',
fusion_weights=(text=0.5, title_sim=0.3, image_sim=0.2);
Все подзапросы выполняются параллельно и объединяются вместе через RRF.
Заключение
Гибридный поиск не должен заменять полнотекстовый или векторный поиск — его задача в том, чтобы использовать оба метода там, где каждый из них работает лучше всего.
Поиск по ключевым словам даёт точность для точных терминов и идентификаторов. Векторный поиск даёт гибкость для естественного языка и смысла. По отдельности у каждого метода есть пробелы. Вместе они стабильно дают лучшие результаты для широкого спектра запросов.
С гибридным поиском в Manticore вам не нужно выбирать между двумя подходами или строить сложную логику запросов для разных случаев. Вы можете запускать оба сигнала параллельно и получать единый, унифицированный набор результатов.
Если ваш поиск должен обрабатывать и точные совпадения, и намерение пользователя, — а это характерно для большинства реальных приложений, — гибридный поиск даёт простой способ повысить релевантность без лишней сложности.
