
Hybridsøk: BM25 vs. vektor (og hvorfor du trenger begge)
En kundestøtteagent skriver «SKU-4471» inn i RAG-chatboten din. Fire resultater kommer tilbake. Alle er skråsikkert feil. En generell embedding-modell har ingen grunn til å plassere den nøyaktige strengen nær seg selv i vektorrommet. Akkurat denne feilmodusen er grunnen til at hybridsøk finnes, og det er derfor team stadig stiller det samme spesifikke spørsmålet: hvordan kombinerer man egentlig BM25 og vektorsøk uten å måtte passe på en finjusteringsknott for alltid?
Hvis du vurderer RAG-verktøy mer generelt, dekker rundoppet vårt av de beste RAG-verktøyene resten av stacken.
Hovedpoeng
- BM25 finner nøyaktige nøkkelordtreff (SKU-er, feilkoder). Vektorsøk finner konseptuelt lignende tekst, ikke identiske strenger.
- Hybridsøk kombinerer begge, vanligvis via Reciprocal Rank Fusion (RRF), og slår begge alene på blandede spørringslaster.
- På WANDS-benchmarken scorer ren RRF 0,7068 NDCG (mot BM25s 0,6983). Finjustering løfter den til 0,7497, en økning på 7,4 %.
- Postgres/pgvector kan kjøre hybridsøk nativt via
ts_rank+ pgvector, uten en dedikert vektordatabase.
Hva er hybridsøk? (BM25 + vektor, kombinert)
Hybridsøk kjører BM25 og vektorsøk som to separate gjenfinningspass over samme spørring og slår deretter sammen de to rangerte resultatlistene til én utdata ved hjelp av en fusjonsalgoritme, oftest Reciprocal Rank Fusion. Det er ikke en tredje gjenfinningsmetode. Det er et orkestreringslag oppå to eksisterende.
Den distinksjonen betyr noe, fordi en god del av søketrafikken rundt dette temaet likestiller BM25 og vektorsøk som om de var samme ting. Det er de ikke. BM25 er en sparse, nøkkelordbasert scorefunksjon med røtter i informasjonsjenfinning fra 1970-tallet. Vektorsøk er tett, embedding-basert likhetssøk som først ble praktisk i stor skala det siste tiåret. Hybridsøk behandler dem som komplementære inndata, ikke konkurrerende teknikker, og fusjonerer utdataene deres i stedet for å kåre en vinner på forhånd.
BM25 vs. vektor vs. hybridsøk: rask sammenligning
| Dimensjon | BM25 (sparse/leksikalsk) | Vektorsøk (tett/semantisk) | Hybridsøk |
|---|---|---|---|
| Best på | Nøyaktige termer, sjeldne tokens, ID-er | Parafrasering, synonymer, konsepter | Begge spørringstyper |
| Feiler på | Omskrevne spørsmål, synonymer | SKU-er, feilkoder, akronymer | Korpus uten noen av mønstrene |
| Håndterer nøyaktige treff (SKU-er, ID-er, feilkoder) | Ja | Nei | Ja |
| Håndterer parafraser og synonymer | Nei | Ja | Ja |
| Krever embedding-modell | Nei | Ja | Ja |
| Krever finjustering | k1-, b-parametre | Chunking, modellvalg | Fusjonsmetode (RRF/alfa) |
| Typisk latensprofil | Submillisekund til lave ms | Lave til middels ms (ANN-avhengig) | Summen av begge, pluss fusjonsoverhead |
| Eksempler på nativ støtte | Elasticsearch, Postgres ts_rank | Qdrant, Pinecone, pgvector | Weaviate, Qdrant, Elasticsearch |
På WANDS-netthandelsbenchmarken scoret BM25 alene 0,6983 NDCG, og vektorsøk alene scoret 0,6953 (nesten likt). Ren RRF-fusjon, uten korpus-spesifikk finjustering, nådde 0,7068, en beskjeden økning på 1,2 % over BM25 alene. Doug Turnbulls benchmark testet også en finjustert variant som legger et produktnavn-boost oppå RRF, og den versjonen nådde 0,7497, en økning på 7,4 %. Det er verdt å være ærlig om hvilket tall du siterer: RRF alene gir deg en liten, reell fordel rett ut av boksen. Det større 7,4 %-tallet krevde ekstra domenespesifikk finjustering som de fleste team hopper over dag én. Verken BM25 eller vektorsøk dominerer alene. De dekker ulike feilmoduser, og å fusjonere dem tetter begge gapene samtidig.
BM25-mekanikk: hvordan nøkkelordsøk faktisk scorer relevans
BM25 scorer dokumenter etter termfrekvens, vektet mot hvor sjelden termen er i hele korpuset, og deretter normalisert for dokumentlengde. Robertson og Zaragoza la frem denne formaliseringen i 2009-artikkelen sin «The Probabilistic Relevance Framework: BM25 and Beyond». Den er en foredling av TF-IDF, ikke en erstatning.
To parametre styrer det meste av oppførselen til BM25. k1 (typisk 1,2–2,0) styrer termfrekvensmetning: den setter et tak på hvor mye gjentakelse av et ord løfter scoren, slik at et dokument som sier «invoice» 40 ganger ikke automatisk rangerer over et som sier det 4 ganger i et tettere, mer relevant avsnitt. b (standard 0,75) styrer dokumentlengdenormalisering: den bestemmer hvor hardt BM25 straffer lange dokumenter for naturlig å inneholde flere termtreff.
Å sette b feil er en reell og vanlig finjusteringstabbe. Korte tekniske dokumenter (feillogger, produkttitler) vil ha en lavere b, siden lengdevariansen er liten. Langt innhold (dokumentasjonssider, artikler) vil som regel ha b nærmere standardverdien. BM25s kjerne-svakhet er ordforråds-mismatch: hvis en bruker spør «hvordan får jeg pengene mine tilbake» og dokumentet bare sier «refund policy», finner BM25 null felles tokens og returnerer ingenting nyttig.
Mekanikken i tett vektorsøk (og hvor det svikter)
Vektorsøk mapper tekst til embeddinger med fast dimensjon ved hjelp av en modell og finner deretter nærliggende vektorer via cosinus-likhet eller prikkprodukt, vanligvis akselerert av en omtrentlig nærmeste-nabo-indeks. HNSW er den dominerende algoritmen hos Weaviate, Qdrant og Milvus, og bytter bort en liten mengde recall mot store hastighetsgevinster i skala.
Det er dette som fikser ordforråds-mismatch-problemet til BM25: «get my money back» og «refund policy» lander nær hverandre i embedding-rommet selv med null felles tokens, fordi modellen fanger mening, ikke overflateform. Å velge riktig modell betyr mye her. Se guiden vår om å velge riktig embedding-modell, og gjennomgangen vår av hvordan vi sammenlignet Voyage-, OpenAI- og Cohere-embeddings hvis du veier alternativer.
Men tett gjenfinning har sin egen blinde flekk, og den er speilbildet av BM25s. Når vi bygger RAG-systemer for kunder, er nøyaktig-treff-feilen vi oftest møter ikke eksotisk. Det er en kundestøtteagent som spør etter et spesifikt ordrenummer eller en SKU, og vektorindeksen som skråsikkert returnerer noe semantisk lignende, men feil. En generell embedding-modell har ingen grunn til å plassere «SKU-4471» eller «ERR_CONN_RST» nær seg selv i vektorrommet fremfor en relatert-men-feil token, fordi strenger som det sjelden opptrer som distinkte, isolerte konsepter i treningsdata. BigData Boutique dokumenterer akkurat dette feilmønsteret med sine egne SKU- og feilkodeeksempler. Det er et veletablert, uavhengig bekreftet fenomen på tvers av RAG-utrullinger, ikke en engangs-quirk.
Slik kombinerer du BM25 og vektorsøk: RRF vs. alfa-vektet fusjon
Det finnes to reelle måter å fusjonere BM25- og vektorresultater på, og nesten ingen som skriver om hybridsøk, kontrasterer dem tydelig. Reciprocal Rank Fusion (RRF), fra Cormack, Clarke og Buettchers 2009 SIGIR-artikkel, opererer på rangeringer: score = sum(1 / (k + rank_i)) på tvers av hver resultatliste, med k typisk satt til 60. Fordi den bare bryr seg om posisjon, ikke rå score, håndterer RRF skala-mismatch mellom BM25s ubegrensede scorer og cosinus-likhetens 0-til-1-område uten klager, og den trenger ingen korpus-spesifikk finjustering.
Alfa-vektet (konveks) fusjon fungerer annerledes: final = alpha * dense_score + (1 - alpha) * sparse_score, og opererer på normaliserte scorer i stedet for rangeringer. Den kan reflektere konfidens-magnitude bedre (et vektortreff på 0,95 likhet ser genuint sterkere ut enn et på 0,61), men den krever finjustering av alpha per korpus, og den finjusteringen brekker stille når scoredistribusjonene dine forskyver seg (ny embedding-modell, reindeksert korpus, annen spørringsmiks).
I praksis koker valget ned til hvor mye du stoler på score-kalibreringen din. Kjører du vanilla BM25 mot én enkelt, stabil embedding-modell, kan alfa-vekting klemme ut litt bedre rangering fordi den bruker det faktiske score-gapet, ikke bare posisjon. Men den kalibreringen driver mer enn folk forventer. Bytt inn en ny versjon av embedding-modellen, chunk dokumentene dine på nytt, eller legg til et reranking-pass oppstrøms, så forskyver distribusjonen av tettscorene dine seg. Ingen blir paget når alpha=0,6 slutter å være riktig verdi. Rangeringen blir bare stille litt dårligere, og det er lett å gå glipp av med mindre du kjører gjenfinningsevalueringer jevnlig. RRF unngår dette fullstendig fordi den aldri ser på rå scorer, bare rangeringsposisjon, så en reindeksering eller et modellbytte kan ikke bryte den stille på den måten det kan bryte alfa-vekting.
RRF trenger ingen finjustering per korpus. Alfa-vekting trenger konstant opppassing mens dataene dine endrer seg.
Motorene er uenige om standardene. Weaviate eksponerer både RRF og en alpha-parameter du setter eksplisitt. Elasticsearch leverer native RRF gjennom retriever-API-et sitt (bekreft nøyaktig versjons-gating i din egen utrulling; dette landet i 8.x-linjen). Qdrant støtter RRF nativt via Query API-et sitt. Pinecones hybridfunksjon lener seg typisk på alfa-vektet konveks kombinasjon i stedet for å eksponere RRF direkte. Er du usikker på hvilken du skal velge, start med RRF. Det er det mest vedlikeholdsvennlige standardvalget.
RRF fra bunnen av: et leverandøruavhengig Python-eksempel
Hver eneste RRF-kodebit vi fant i konkurrerende guider, er låst til én leverandørs SDK: Weaviates klient, Qdrants klient, Pinecones klient. Her er en rammeverkfri versjon du kan slippe inn i hvilken som helst stack, med k=60 som standard:
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}")Det er hele algoritmen. Ingen SDK, ingen leverandørlås, og den fungerer enten de to rangerte listene dine kom fra Elasticsearch og en Faiss-indeks, eller fra Postgres ts_rank og pgvector. Kjører du modellene selv i stedet for å treffe et API, se kjøre embedding-modeller lokalt med Ollama.
Postgres + pgvector: hybridsøk uten en dedikert vektordatabase
Du trenger ikke en dedikert vektordatabase for å kjøre hybridsøk. Ifølge en pg_textsearch/pgvector-benchmark av utvikleren Pedro Alonso (Postgres 17, pg_textsearch 1.3.0, pgvector 0.8.2, nomic-embed-text-embeddings, BEIR SciFact-datasettet) scoret én enkelt Postgres-instans med native ts_rank bare 0,07 NDCG@10, langt bak BM25s 0,69, pgvectors 0,66 og hybridens 0,70, alt i én instans, med hybrid-RRF på rundt 11,5 ms median.
Det 0,07-tallet er avsløringen: Postgres' innebygde ts_rank er en tetthetsbasert ranker, ikke ekte BM25. Vil du ha reell BM25-scoring i Postgres, trenger du en utvidelse. pg_textsearch, VectorChord og ParadeDB legger alle til skikkelig BM25-aktig rangering som native ts_rank ikke gir. Par en av dem med pgvector for tett likhet, fusjoner de to rangerte listene med RRF-funksjonen over, og du har hybridsøk i én enkelt Postgres-instans uten separat infrastruktur å drifte.
Her er omtrent hvordan den paringen ser ut i én enkelt spørring, som kombinerer en leksikalsk rang fra en BM25-kapabel utvidelse med en vektordistanse fra 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);Mat begge resultatsettene inn i RRF-funksjonen over, og du har hybridsøk i én Postgres-instans. Den ærlige begrensningen: dette holder godt ut i de lave millionene av rader, men Postgres er ikke bygget som en dedikert gjenfinningsmotor. Du eier din egen indeksfinjustering, ren ts_rank_cd er fortsatt ikke ekte BM25 uten en utvidelse, og du får ikke den innebygde rerankingen eller flervektor-støtten som Weaviate eller Milvus leverer nativt. Er korpuset lite til middels stort og du allerede kjører Postgres, sparer dette deg for en hel ekstra infrastrukturkomponent. Passerer du titalls millioner dokumenter, eller trenger avansert reranking, forsvarer en dedikert motor plassen sin.
Veier du Qdrant, Chroma eller pgvector for stacken din mer generelt, er det en separat beslutning fra selve fusjonsmetoden. Se sammenligningen vår av Qdrant, Chroma og pgvector for avveiningene.
Hvilke vektordatabaser støtter native hybridsøk?
De fleste moderne vektordatabaser leverer nå hybridsøk rett ut av boksen, men standard-fusjonsmetoden deres varierer meningsfullt.
| Motor | Native hybridstøtte | Fusjonsmetode | Merknader |
|---|---|---|---|
| Weaviate | Ja | RRF eller alfa-vektet | Eksponerer begge, du velger per spørring |
| Qdrant | Ja | RRF | Via Query API |
| Elasticsearch | Ja | RRF | Via retriever-API-et |
| OpenSearch | Ja | Normalisering + vektet sum | Bruker «normalization processors» |
| Vespa | Ja | Native fusjon | En av de tidligste motorene som støttet dette |
| Milvus | Ja | Flervektor + sparse BM25 | Hybrid via combined search API |
| pgvector + Postgres | Ja (med utvidelse) | Manuell RRF (se over) | Trenger ts_rank/BM25-utvidelse for ekte leksikalsk scoring |
Bekreft nøyaktig versjons-gating før du binder deg. Hybridfunksjoner har landet raskt på tvers av disse motorene gjennom 2026, og API-former endrer seg fra release til release. For en bredere kjøpsbeslutning utover selve fusjonsmekanikken, se rundoppet vårt av de beste vektordatabasene.
Er hybridsøk verdt kompleksiteten?
Hybridsøk er arkitektonisk korrekt når korpuset ditt har både nøyaktig-treff-mønstre (SKU-er, ID-er, sjeldne termer) og konseptuelle, parafraserte spørringer. Har korpuset ditt ingen av delene (rent narrativt innhold, ingen identifikatorer noen søker på med bokstavelig streng), legger du kanskje til fusjonskompleksitet for en gevinst du knapt merker.
Tenk på hva «bare narrativt» faktisk ser ut: et firmablogg-arkiv, en intern ingeniørwiki full av prosatunge runbooks, et dokumentasjonsnettsted ingen søker i med produkt-ID eller billettnummer. I de korpusene gir vektorsøk alene vanligvis det meste av verdien, og fusjonssteget legger bare til et andre gjenfinningspass og en parameter noen nå eier, for en gevinst som avrundes til støy. Sammenlign det med et kundestøttesystem eller en netthandelskatalog, der SKU-er, ordrenumre og modellkoder dukker opp i ekte brukerspørringer hele tiden. Det er den faktiske testen: hent ti reelle spørringer fra loggene dine og tell hvor mange som inneholder en nøyaktig identifikator en parafrase-basert embedding-modell aldri ville plassert riktig. Null, hopp over hybrid. Mer enn én eller to, bygg det.
Hybridsøk er ikke en universell oppgradering. Har korpuset ditt ingen SKU-er, ID-er eller sjeldne-term-oppslag, legger du kanskje til fusjonskompleksitet for en gevinst du aldri merker.
Kostnaden er reell, men begrenset: et andre gjenfinningspass, et fusjonssteg og en vektingsparameter noen nå eier. Vi siterer bevisst ikke noe latens-tall her, fordi tallene som sirkulerer kommer fra navnløse oppsett på navnløs maskinvare, og dine vil være annerledes. Mål det på ditt eget korpus før du bestemmer deg. To Hacker News-tråder fanger den reelle utøver-spenningen her: «Hybrid Search Is Just the Beginning: Optimizing the R in RAG» og «Better RAG Results with Reciprocal Rank Fusion and Hybrid Search». Begge trådene pusher tilbake mot å adoptere hybrid som cargo-cult-bestepraksis uten først å sjekke om korpuset ditt i det hele tatt har spørringsmønstrene den er ment å løse. Før du bygger den, er det verdt å forstå hvordan du faktisk måler gjenfinningskvalitet: NDCG- og recall@k-tall betyr bare noe mot ditt eget korpus, ikke et benchmark-datasett.
Vårt syn: sett hybrid som standard for ethvert RAG-system som håndterer kundestøtte, netthandel eller billettsystemer mot brukere. De arbeidslastene mikser nesten alltid identifikatorer med naturlig språk. Hopp over det for rent narrative korpus (langt innhold, narrative wikier) til du har målt et reelt gap som én-metode-gjenfinning lar stå åpent.
Om forfatteren
Mert Batur er medgrunnlegger av Techsy.io, der teamet leverer AI-agenter, automatiseringssystemer og tale-/SDR-pipelines for B2B-kunder. Han skriver om LLM-verktøy-stacken Techsy-teamet faktisk bruker i produksjon. Koble til på LinkedIn.
Ofte stilte spørsmål
Hva er hybridsøk i RAG?
Hybridsøk kjører BM25 (nøkkelord) og vektor (semantisk) gjenfinning som separate pass over samme spørring og slår deretter sammen de to rangerte listene med en fusjonsalgoritme, vanligvis Reciprocal Rank Fusion. Det fanger både nøyaktig-treff-spørringer og parafraserte konseptuelle spørringer, som ingen av metodene håndterer alene.
Er BM25 det samme som vektorsøk?
Nei. BM25 er sparse leksikalsk søk som scorer nøyaktig term-overlapp og sjeldenhet. Vektorsøk er tett semantisk søk med embeddings og likhetsmatematikk. De er to ulike gjenfinningsmetoder med motsatte styrker. Hybridsøk kombinerer dem i stedet for å erstatte noen av dem.
Hvordan kombinerer man BM25 og vektorsøk?
Kjør begge gjenfinningsmetodene uavhengig på samme spørring, og fusjoner deretter de to rangerte resultatlistene, oftest med Reciprocal Rank Fusion, som summerer 1 / (k + rank) på tvers av hver liste. Alfa-vektet score-kombinasjon er alternativet, men det trenger korpus-spesifikk finjustering som RRF slipper.
Hva er Reciprocal Rank Fusion (RRF)?
RRF er en fusjonsalgoritme fra Cormack, Clarke og Buettchers 2009 SIGIR-artikkel som kombinerer flere rangerte lister ved å summere 1 / (k + rank) for hvert dokument, med k typisk satt til 60. Den jobber på rangeringsposisjon, ikke rå scorer, så den forblir stabil på tvers av skala-mismatch mellom gjenfinningsmetoder.
Hva er forskjellen mellom RRF og alfa-vektet fusjon?
RRF kombinerer rangeringer og trenger ingen korpus-spesifikk finjustering. Alfa-vektet fusjon kombinerer normaliserte scorer med en justerbar alpha-parameter, som kan reflektere konfidens-magnitude bedre, men krever løpende omfinjustering hver gang scoredistribusjonene forskyver seg, for eksempel etter en reindeksering eller modellendring.
Når bør jeg bruke hybridsøk i stedet for bare vektorsøk?
Bruk hybridsøk når spørringene dine mikser nøyaktige identifikatorer (SKU-er, ordrenumre, feilkoder) med konseptuelle spørsmål på naturlig språk. Kundestøtte, netthandel og billettsystemer gjør typisk det. Hopp over det for rent narrativt innhold uten identifikatorer, der den ekstra fusjonskompleksiteten sannsynligvis ikke vil vise en målbar gevinst.
Hvorfor bommer vektorsøk på nøyaktige treff som SKU-er eller feilkoder?
Embedding-modeller lærer av generelle språkmønstre, og strenger som «SKU-4471» eller «ERR_CONN_RST» opptrer sjelden som distinkte, isolerte konsepter i treningsdata. Modellen har ingen sterk grunn til å plassere den nøyaktige strengen nærmere seg selv enn en semantisk relatert, men feil token.
Hvilke vektordatabaser støtter hybridsøk nativt?
Weaviate, Qdrant, Elasticsearch, OpenSearch, Vespa og Milvus leverer alle native hybridsøk per 2026, selv om standard-fusjonsmetodene deres varierer (RRF vs. alfa-vektet vs. normalisering). Postgres med pgvector kan også kjøre hybridsøk, men trenger en BM25-utvidelse siden native ts_rank ikke er ekte BM25.
Er hybridsøk verdt den ekstra kompleksiteten?
For korpus som mikser nøyaktige treff og konseptuelle spørringer, ja. Ren RRF slår allerede begge enkeltmetodene på WANDS-benchmarken (0,7068 mot BM25s 0,6983), og en finjustert variant når en økning på 7,4 % (0,7497). For rent narrative korpus uten identifikatorer kan det andre gjenfinningspasset og fusjonsfinjusteringen det krever, veie tyngre enn en gevinst du ikke merker. Mål før du binder deg.
Kan Postgres/pgvector gjøre hybridsøk uten en dedikert vektordatabase?
Ja. Par pgvector for tett likhet med en ekte BM25-utvidelse som pg_textsearch, VectorChord eller ParadeDB (native ts_rank alene scoret bare 0,07 NDCG@10 i Pedro Alonsos pg_textsearch/pgvector-benchmark, mot 0,70 for hybrid), og fusjoner deretter de to rangerte listene med RRF, alt inne i én Postgres-instans.
Begge gjenfinningsmetodene etterlater reelle gap når de kjøres alene: BM25 bommer på parafraser, vektorsøk bommer på nøyaktige identifikatorer, og å fusjonere dem med RRF er den mest vedlikeholdsvennlige måten å tette begge på. Veier du om du skal bygge dette selv eller hente inn et team som har levert RAG-gjenfinning før, dekker guiden vår til å bygge en RAG-applikasjon neste steg, eller ta kontakt hvis du heller vil ha Techsy med på byggingen.