
Гібридний пошук: BM25 проти вектора (і чому потрібні обидва)
Оператор підтримки вводить "SKU-4471" у ваш RAG-чатбот. Повертаються чотири результати. Усі впевнено хибні. Універсальна модель ембедінгів не має жодних причин розташовувати цей точний рядок поруч із самим собою у векторному просторі. Саме цей тип збою є причиною існування гібридного пошуку, і саме тому команди ставлять одне й те саме запитання: як на практиці поєднати BM25 і векторний пошук, щоб не няньчити ручку налаштувань вічно?
Якщо ви оцінюєте інструменти для RAG ширше, наш огляд найкращих RAG-інструментів охоплює весь стек навколо.
Ключові висновки
- BM25 знаходить точні збіги ключових слів (SKU, коди помилок); векторний пошук знаходить концептуально схожий текст, а не ідентичні рядки.
- Гібридний пошук поєднує обидва підходи, зазвичай через Reciprocal Rank Fusion (RRF), і на змішаних навантаженнях запитів перевершує кожен з них окремо.
- На бенчмарку WANDS звичайний RRF дає 0,7068 NDCG (проти 0,6983 у BM25); налаштування піднімає результат до 0,7497, тобто на 7,4%.
- Postgres/pgvector здатний виконувати гібридний пошук нативно через
ts_rank+ pgvector, без окремої векторної бази даних.
Що таке гібридний пошук? (BM25 + вектор у поєднанні)
Гібридний пошук виконує BM25 і векторний пошук як два окремі проходи вибірки за одним і тим самим запитом, а потім об'єднує два ранжовані списки результатів у один вивід за допомогою алгоритму злиття, найчастіше Reciprocal Rank Fusion. Це не третій метод вибірки; це шар оркестрації над двома наявними.
Цей поділ важливий, бо чимала частина пошукового трафіку навколо цієї теми змішує BM25 і векторний пошук, наче це одне й те саме. Це не так. BM25 — розріджена функція оцінювання за ключовими словами, яка сягає корінням інформаційного пошуку 1970-х. Векторний пошук — щільний пошук за подібністю на основі ембедінгів, який став практичним у масштабі лише в останнє десятиліття. Гібридний пошук розглядає їх як взаємодоповнювані входи, а не конкурентні техніки, і зливає їхні результати, замість того щоб обирати переможця наперед.
BM25 проти вектора проти гібридного: швидке порівняння
| Вимір | BM25 (розріджений/лексичний) | Векторний пошук (щільний/семантичний) | Гібридний |
|---|---|---|---|
| Найкраще працює з | Точні терміни, рідкісні токени, ID | Перефразування, синоніми, концепції | Обидва типи запитів |
| Не справляється з | Перефразовані запитання, синонімія | SKU, коди помилок, абревіатури | Корпуси без обох патернів |
| Точні збіги (SKU, ID, коди помилок) | Так | Ні | Так |
| Перефразування та синоніми | Ні | Так | Так |
| Потребує моделі ембедінгів | Ні | Так | Так |
| Потребує налаштування | Параметри k1, b | Нарізка на фрагменти, вибір моделі | Метод злиття (RRF/альфа) |
| Типовий профіль затримки | Від субмілісекунд до низьких мс | Низькі-середні мс (залежно від ANN) | Сума обох плюс накладні витрати злиття |
| Приклади нативної підтримки | Elasticsearch, Postgres ts_rank | Qdrant, Pinecone, pgvector | Weaviate, Qdrant, Elasticsearch |
На бенчмарку електронної комерції WANDS сам BM25 дав 0,6983 NDCG, а сам векторний пошук — 0,6953 (майже нічия). Звичайне злиття RRF, без налаштування під конкретний корпус, досягло 0,7068, тобто скромного приросту в 1,2% над самим BM25. Бенчмарк Дага Тернбулла також перевірив налаштований варіант, який додає до RRF підсилення за назвою товару, і ця версія досягла 0,7497, приросту в 7,4%. Варто чесно сказати, яку саме цифру ви цитуєте: сам RRF дає невелику, але реальну перевагу з коробки; більша цифра 7,4% вимагає додаткового доменного налаштування, яке більшість команд пропускає першого дня. Ні BM25, ні векторний пошук не домінують самотужки; вони покривають різні типи збоїв, і їхнє злиття закриває обидві прогалини одразу.
Механіка BM25: як пошук за ключовими словами насправді оцінює релевантність
BM25 оцінює документи за частотою терміна, зваженою на те, наскільки рідкісний цей термін у всьому корпусі, а потім нормалізованою за довжиною документа. Робертсон і Сарагоса виклали цю формалізацію у своїй статті 2009 року "The Probabilistic Relevance Framework: BM25 and Beyond". Це вдосконалення TF-IDF, а не його заміна.
Два параметри керують більшістю поведінки BM25. k1 (типово 1,2-2,0) керує насиченням частоти терміна: він обмежує, наскільки повторення слова підвищує оцінку, тож документ, де слово "invoice" зустрічається 40 разів, автоматично не обійде той, де воно зустрічається 4 рази у щільнішому, релевантнішому уривку. b (типово 0,75) керує нормалізацією за довжиною документа: він визначає, наскільки суворо BM25 карає довгі документи за те, що вони природно містять більше збігів термінів.
Неправильний b — це реальна, поширена помилка налаштування. Короткі технічні документи (журнали помилок, назви товарів) потребують нижчого b, бо розкид довжин малий; довгі тексти (сторінки документації, статті) зазвичай потребують b, ближчого до типового. Головна слабкість BM25 — лексична невідповідність: якщо користувач питає "як мені повернути свої гроші", а документ лише каже "політика повернення коштів", BM25 не знаходить жодного спільного токена і не повертає нічого корисного.
Механіка щільного векторного пошуку (і де він ламається)
Векторний пошук відображає текст у ембедінги фіксованої розмірності за допомогою моделі, а потім знаходить близькі вектори через косинусну подібність або скалярний добуток, зазвичай прискорений індексом наближених найближчих сусідів. HNSW — домінантний алгоритм у Weaviate, Qdrant і Milvus, який обмінює невелику частку повноти на значний виграш у швидкості в масштабі.
Саме це виправляє проблему лексичної невідповідності BM25: "повернути мої гроші" і "політика повернення коштів" опиняються близько у просторі ембедінгів навіть за нульової кількості спільних токенів, бо модель захоплює значення, а не поверхневу форму. Вибір правильної моделі тут дуже важливий. Дивіться наш гід з вибору правильної моделі ембедінгів та наш розбір порівняння ембедінгів Voyage, OpenAI і Cohere, якщо ви зважуєте варіанти.
Але щільна вибірка має власне сліпе місце, і воно є дзеркальним відображенням слабкості BM25. Коли ми будуємо RAG-системи для клієнтів, найчастіший збій точного збігу, з яким ми стикаємось, не є екзотичним. Це оператор підтримки, який питає конкретний номер замовлення чи SKU, а векторний індекс впевнено повертає щось семантично схоже, але хибне. Універсальна модель ембедінгів не має причин розташовувати "SKU-4471" або "ERR_CONN_RST" ближче до самого себе, ніж до пов'язаного, але хибного токена, бо такі рядки рідко з'являються як окремі, ізольовані концепції в навчальних даних. BigData Boutique документує саме цей патерн збою на власних прикладах SKU та кодів помилок. Це добре встановлений, незалежно підтверджений феномен у RAG-розгортаннях, а не одноразова примха.
Як поєднати BM25 і векторний пошук: RRF проти злиття з альфа-вагою
Є два реальні способи злити результати BM25 і вектора, і майже ніхто з тих, хто пише про гібридний пошук, не протиставляє їх чітко. Reciprocal Rank Fusion (RRF), зі статті SIGIR 2009 року Кормака, Кларка і Бюттхера, працює з рангами: score = sum(1 / (k + rank_i)) по кожному списку результатів, де k типово дорівнює 60. Оскільки його цікавить лише позиція, а не сира оцінка, RRF без проблем витримує невідповідність масштабів між необмеженими оцінками BM25 і діапазоном косинусної подібності від 0 до 1, і не потребує налаштування під кожен корпус.
Злиття з альфа-вагою (опукле) працює інакше: final = alpha * dense_score + (1 - alpha) * sparse_score, оперуючи нормалізованими оцінками, а не рангами. Воно може краще відображати величину впевненості (векторний збіг із подібністю 0,95 справді виглядає сильнішим за збіг із 0,61), але потребує налаштування alpha під кожен корпус, і це налаштування ламається тихо, коли розподіл ваших оцінок зсувається (нова модель ембедінгів, переіндексований корпус, інший склад запитів).
На практиці вибір зводиться до того, наскільки ви довіряєте калібруванню своїх оцінок. Якщо ви женете ванільний BM25 проти однієї стабільної моделі ембедінгів, альфа-зважування може вижати трохи краще ранжування, бо використовує реальний розрив оцінок, а не лише позицію. Але це калібрування дрейфує більше, ніж люди очікують. Замініть версію моделі ембедінгів, перенаріжте документи на фрагменти чи додайте переранжування вище за потоком, і розподіл ваших щільних оцінок зсунеться. Ніхто не отримує пейджер, коли alpha=0.6 перестає бути правильним значенням; ранжування просто тихо стає трохи гіршим, і це легко пропустити, якщо ви не запускаєте оцінки вибірки регулярно. RRF уникає цього повністю, бо ніколи не дивиться на сирі оцінки, лише на позицію в рангу, тож переіндексація чи заміна моделі не можуть зламати його тихо так, як вони можуть зламати альфа-зважування.
RRF не потребує налаштування під кожен корпус; альфа-зважування потребує постійного догляду, коли ваші дані змінюються.
Рушії розходяться в типових налаштуваннях. Weaviate пропонує і RRF, і параметр alpha, який ви задаєте явно. Elasticsearch постачає нативний RRF через свій API retriever (перевірте точне обмеження версії у вашому розгортанні; це з'явилося в лінійці 8.x). Qdrant підтримує RRF нативно через свій Query API. Гібридна функція Pinecone типово спирається на опуклу комбінацію з альфа-вагою, а не пропонує RRF напряму. Якщо ви не певні, за що взятися, почніть з RRF. Це варіант із найменшими витратами на підтримку.
RRF з нуля: вендор-нейтральний приклад на Python
Кожен зразок коду RRF, який ми знайшли в конкурентних гідах, прив'язаний до SDK одного постачальника: клієнта Weaviate, клієнта Qdrant, клієнта Pinecone. Ось версія без фреймворку, яку можна вкинути в будь-який стек, зі стандартним типовим k=60:
def reciprocal_rank_fusion(result_lists, k=60):
"""
result_lists: list of ranked lists, each a list of document IDs
ordered from most to least relevant.
k: RRF constant (60 is the standard default from Cormack et al., 2009).
Returns: list of (doc_id, fused_score) sorted descending by score.
"""
scores = {}
for result_list in result_lists:
for rank, doc_id in enumerate(result_list, start=1):
scores[doc_id] = scores.get(doc_id, 0.0) + 1.0 / (k + rank)
return sorted(scores.items(), key=lambda item: item[1], reverse=True)
# Example usage:
bm25_hits = ["doc_9", "doc_2", "doc_14", "doc_1"]
vector_hits = ["doc_2", "doc_1", "doc_9", "doc_30"]
fused = reciprocal_rank_fusion([bm25_hits, vector_hits])
for doc_id, score in fused:
print(f"{doc_id}: {score:.4f}")Це весь алгоритм. Без SDK, без прив'язки до постачальника, і він працює незалежно від того, чи прийшли ваші два ранжовані списки з Elasticsearch та індексу Faiss, чи з Postgres ts_rank і pgvector. Якщо ви запускаєте моделі самостійно, а не звертаєтесь до API, дивіться запуск моделей ембедінгів локально з Ollama.
Postgres + pgvector: гібридний пошук без окремої векторної бази даних
Вам не потрібна окрема векторна база даних, щоб виконувати гібридний пошук. Згідно з бенчмарком pg_textsearch/pgvector розробника Педро Алонсо (Postgres 17, pg_textsearch 1.3.0, pgvector 0.8.2, ембедінги nomic-embed-text, датасет BEIR SciFact), один екземпляр Postgres із нативним ts_rank дав лише 0,07 NDCG@10, далеко позаду 0,69 у BM25, 0,66 у pgvector і 0,70 у гібридного, все в одному екземплярі, причому гібридний RRF приземлився біля медіани 11,5 мс.
Ця цифра 0,07 є показовою: вбудований ts_rank у Postgres — це ранжувач за щільністю покриття, а не справжній BM25. Якщо ви хочете справжнє оцінювання BM25 у Postgres, вам потрібне розширення. pg_textsearch, VectorChord і ParadeDB усі додають належне ранжування в стилі BM25, якого нативний ts_rank не забезпечує. Поєднайте одне з них із pgvector для щільної подібності, злийте два ранжовані списки функцією RRF вище, і ви маєте гібридний пошук в одному екземплярі Postgres, без окремої інфраструктури для запуску.
Ось приблизно як це поєднання виглядає в одному запиті, комбінуючи лексичний ранг із розширення, здатного на BM25, із векторною відстанню від pgvector:
WITH lexical AS (
SELECT id, ts_rank_cd(body_tsv, query) AS rank
FROM documents, plainto_tsquery('english', 'refund policy') query
WHERE body_tsv @@ query
ORDER BY rank DESC LIMIT 50
),
semantic AS (
SELECT id, embedding <=> '[0.012, -0.045, ...]' AS distance
FROM documents
ORDER BY distance LIMIT 50
)
SELECT * FROM lexical
FULL OUTER JOIN semantic USING (id);Подайте обидва набори результатів у функцію RRF вище, і ви маєте гібридний пошук в одному екземплярі Postgres. Чесне обмеження: це добре тримається до кількох мільйонів рядків, але Postgres не був створений як окремий рушій вибірки. Ви самі відповідаєте за налаштування індексів, звичайний ts_rank_cd все одно не є справжнім BM25 без розширення, і ви не отримуєте вбудованого переранжування чи підтримки кількох векторів, які Weaviate або Milvus постачають нативно. Якщо ваш корпус малий або середній і ви вже женете Postgres, це економить вам цілий другий шматок інфраструктури. Понад десятки мільйонів документів, або якщо вам потрібне просунуте переранжування, окремий рушій виправдовує своє утримання.
Якщо ви зважуєте Qdrant, Chroma чи pgvector для свого стека ширше, це окреме рішення від самого методу злиття. Дивіться наше порівняння Qdrant, Chroma і pgvector щодо компромісів.
Які векторні бази даних підтримують нативний гібридний пошук?
Більшість сучасних векторних баз даних тепер постачають гібридний пошук із коробки, але метод злиття, який вони використовують як типовий, суттєво відрізняється.
| Рушій | Нативна підтримка гібриду | Метод злиття | Примітки |
|---|---|---|---|
| Weaviate | Так | RRF або з альфа-вагою | Пропонує обидва, ваш вибір для кожного запиту |
| Qdrant | Так | RRF | Через Query API |
| Elasticsearch | Так | RRF | Через API retriever |
| OpenSearch | Так | Нормалізація + зважена сума | Використовує "процесори нормалізації" |
| Vespa | Так | Нативне злиття | Один із найраніших рушіїв із цією підтримкою |
| Milvus | Так | Кілька векторів + розріджений BM25 | Гібрид через комбінований search API |
| pgvector + Postgres | Так (з розширенням) | Ручний RRF (див. вище) | Потребує ts_rank/BM25-розширення для справжнього лексичного оцінювання |
Перевірте точне обмеження версії, перш ніж фіксувати рішення. Гібридні функції швидко з'являлися в цих рушіях протягом 2026 року, і форми API змінюються від релізу до релізу. Для ширшого рішення про покупку, поза механікою злиття, дивіться наш повний огляд найкращих векторних баз даних.
Чи вартий гібридний пошук своєї складності?
Гібридний пошук архітектурно правильний, коли ваш корпус має і патерни точного збігу (SKU, ID, рідкісні терміни), і концептуальні, перефразовані запити. Якщо ваш корпус не має ні того, ні іншого (чистий наративний контент, без ідентифікаторів, які хтось шукає за точним рядком), ви можете додати складність злиття заради приросту, якого майже не помітите.
Подумайте, як насправді виглядає "лише наратив": архів блогу компанії, внутрішня інженерна вікі з наповненими прозою ранбуками, сайт документації, який ніхто не шукає за ID товару чи номером тикета. У таких корпусах сам векторний пошук зазвичай дає вам більшу частину цінності, а крок злиття просто додає другий прохід вибірки і параметр, який тепер хтось має підтримувати, заради приросту, що округлюється до шуму. Порівняйте це з системою тикетів підтримки чи каталогом електронної комерції, де SKU, номери замовлень і коди моделей постійно з'являються в реальних запитах користувачів. Ось справжній тест: витягніть десять реальних запитів із власних журналів і порахуйте, скільки з них містять точний ідентифікатор, який модель ембедінгів на основі перефразування ніколи не розташує правильно. Нуль — пропустіть гібрид. Більше одного-двох — будуйте.
Гібридний пошук не є універсальним апгрейдом: якщо ваш корпус не має SKU, ID чи пошуку рідкісних термінів, ви можете додавати складність злиття заради приросту, якого ніколи не помітите.
Вартість реальна, але обмежена: другий прохід вибірки, крок злиття і параметр ваги, який тепер хтось має підтримувати. Ми свідомо не наводимо тут цифру затримки, бо числа, які гуляють, походять із неназваних конфігурацій на неназваному заліззі, а ваші відрізнятимуться. Виміряйте на власному корпусі, перш ніж вирішувати. Дві гілки на Hacker News фіксують реальну напругу серед практиків: "Hybrid Search Is Just the Beginning: Optimizing the R in RAG" і "Better RAG Results with Reciprocal Rank Fusion and Hybrid Search". Обидві гілки заперечують проти впровадження гібриду як карго-культ найкращої практики, без попередньої перевірки, чи ваш корпус узагалі має патерни запитів, які він покликаний розв'язати. Перш ніж будувати, варто зрозуміти, як насправді вимірювати якість вибірки: цифри NDCG і recall@k означають щось лише проти вашого власного корпусу, а не датасету бенчмарку.
Наш погляд: типово обирайте гібрид для будь-якої RAG-системи, яка обслуговує спрямовані на користувачів запити підтримки, електронної комерції чи тикетів. Ці навантаження майже завжди змішують ідентифікатори з природною мовою. Пропустіть його для суто наративних корпусів (довгі документи, наративні вікі), поки ви не виміряли реальну прогалину, яку лишає однометодна вибірка.
Про автора
Мерт Батур — співзасновник Techsy.io, де команда постачає AI-агентів, системи автоматизації та голосові/SDR-конвеєри для B2B-клієнтів. Він пише про стек інструментів LLM, який команда Techsy насправді використовує в продакшені. Зв'язатися в LinkedIn.
Часті запитання
Що таке гібридний пошук у RAG?
Гібридний пошук виконує вибірку BM25 (за ключовими словами) і векторну (семантичну) як окремі проходи за одним і тим самим запитом, а потім об'єднує два ранжовані списки алгоритмом злиття, зазвичай Reciprocal Rank Fusion. Він ловить і запити точного збігу, і перефразовані концептуальні, з якими жоден метод окремо не справляється.
Чи BM25 те саме, що векторний пошук?
Ні. BM25 — це розріджений лексичний пошук, який оцінює точний збіг і рідкісність термінів. Векторний пошук — це щільний семантичний пошук з використанням ембедінгів і математики подібності. Це два різні методи вибірки з протилежними сильними сторонами; гібридний пошук поєднує, а не замінює жоден із них.
Як поєднати BM25 і векторний пошук?
Запустіть обидва методи вибірки незалежно за одним запитом, а потім злийте два ранжовані списки результатів, найчастіше через Reciprocal Rank Fusion, який сумує 1 / (k + rank) по кожному списку. Комбінування оцінок з альфа-вагою є альтернативою, але воно потребує налаштування під кожен корпус, якого RRF не потребує.
Що таке Reciprocal Rank Fusion (RRF)?
RRF — це алгоритм злиття зі статті SIGIR 2009 року Кормака, Кларка і Бюттхера, який об'єднує кілька ранжованих списків, сумуючи 1 / (k + rank) для кожного документа, де k типово дорівнює 60. Він працює з позицією в рангу, а не з сирими оцінками, тож лишається стабільним попри невідповідність масштабів між методами вибірки.
У чому різниця між RRF і злиттям з альфа-вагою?
RRF об'єднує ранги і не потребує налаштування під кожен корпус. Злиття з альфа-вагою об'єднує нормалізовані оцінки за допомогою настроюваного параметра alpha, що може краще відображати величину впевненості, але потребує постійного переналаштування, коли розподіл оцінок зсувається, наприклад після переіндексації чи зміни моделі.
Коли використовувати гібридний пошук замість самого векторного?
Використовуйте гібридний пошук, коли ваші запити змішують точні ідентифікатори (SKU, номери замовлень, коди помилок) із природномовними, концептуальними запитаннями; підтримка, електронна комерція і системи тикетів типово так і роблять. Пропустіть його для суто наративного контенту без ідентифікаторів, де додана складність злиття, ймовірно, не покаже вимірюваного приросту.
Чому векторний пошук пропускає точні збіги, як-от SKU чи коди помилок?
Моделі ембедінгів навчаються на загальних мовних патернах, а рядки на кшталт "SKU-4471" або "ERR_CONN_RST" рідко з'являються як окремі, ізольовані концепції в навчальних даних. Модель не має вагомих причин розташовувати цей точний рядок ближче до самого себе, ніж до семантично пов'язаного, але хибного токена.
Які векторні бази даних підтримують гібридний пошук нативно?
Weaviate, Qdrant, Elasticsearch, OpenSearch, Vespa і Milvus усі постачають нативний гібридний пошук станом на 2026 рік, хоча їхні типові методи злиття відрізняються (RRF проти альфа-зважування проти нормалізації). Postgres із pgvector також може виконувати гібридний пошук, але потребує розширення BM25, оскільки нативний ts_rank не є справжнім BM25.
Чи вартий гібридний пошук доданої складності?
Для корпусів, які змішують запити точного збігу та концептуальні, так. Звичайний RRF уже перевершує будь-який окремий метод на бенчмарку WANDS (0,7068 проти 0,6983 у BM25), а налаштований варіант досягає приросту в 7,4% (0,7497). Для суто наративних корпусів без ідентифікаторів другий прохід вибірки і налаштування злиття, якого він потребує, можуть переважити приріст, якого ви не помітите. Виміряйте, перш ніж фіксувати рішення.
Чи може Postgres/pgvector робити гібридний пошук без окремої векторної бази даних?
Так. Поєднайте pgvector для щільної подібності зі справжнім розширенням BM25, як-от pg_textsearch, VectorChord або ParadeDB (сам нативний ts_rank дав лише 0,07 NDCG@10 в бенчмарку pg_textsearch/pgvector Педро Алонсо, проти 0,70 у гібридного), а потім злийте два ранжовані списки через RRF, усе всередині одного екземпляра Postgres.
Обидва методи вибірки лишають реальні прогалини, коли працюють окремо: BM25 пропускає перефразування, векторний пошук пропускає точні ідентифікатори, а їхнє злиття через RRF є найменш витратним у підтримці способом закрити обидві. Якщо ви зважуєте, будувати це самотужки чи залучити команду, яка вже постачала RAG-вибірку раніше, наш повний гід із побудови RAG-застосунку покриває наступний крок, або зв'яжіться з нами, якщо ви хочете, щоб Techsy побудував це разом з вами.