Hybrid search

Running keyword search and vector search at once and merging the hits, so you catch exact terms and reworded ideas alike.

keyword plus meaning searchuse both kinds of searchhybird searchhybrid retrievalcombine BM25 and vector searchsearch that finds the exact word and the ideawhy does vector search miss my product codeskeyword and semantic search together

See it

Live demo coming soon

What it is

Hybrid search runs two retrievers over the same corpus and merges what they return. The keyword side (BM25, or Postgres full-text search) is literal: it nails part numbers, error codes, function names, rare proper nouns. The vector side (embeddings) is semantic: it finds 'how do I cancel' when the doc says 'terminating your subscription'. Each one fails exactly where the other works, which is the whole argument for running both.

Reach for it the moment your RAG answers go vague on specifics. Classic tell: users search 'ERR_2041' and pure vector search hands back five chunks about error handling in general and never the one page that contains the string. Most vector stores (Weaviate, Qdrant, Pinecone) and Postgres with pgvector plus tsvector can do both halves.

Gotcha: you cannot just add the two scores together. A BM25 score of 14.2 and a cosine similarity of 0.83 live on unrelated scales, so naive weighting silently lets one side win everything. Use reciprocal rank fusion, which throws away the scores and merges on rank position (with a per-retriever weight if you want to lean one way), or normalise per query before applying an alpha weight. Second gotcha: hybrid search fixes recall, not junk. If your chunks are badly split, both retrievers return the same bad chunks faster.

Ask AI for it

Implement hybrid retrieval for this RAG pipeline. For each query, run two searches in parallel: a BM25 / full-text keyword search and a vector similarity search over the same chunk table, taking the top 25 from each. Merge the two result lists with weighted reciprocal rank fusion rather than adding the raw scores: for each chunk, sum keywordWeight / (60 + keywordRank) and vectorWeight / (60 + vectorRank), skipping the term for whichever list did not return it, with keywordWeight + vectorWeight = 1. Expose that pair as a single alpha config where keywordWeight = alpha and vectorWeight = 1 - alpha, defaulting alpha to 0.5 for an even blend, so raising alpha visibly pulls keyword hits up the merged list. Dedupe by chunk id, return the top 8, and log which retriever surfaced each winning chunk and at what rank.

You might have meant

semantic searchrerankingembeddingvector databasechunking

Go deeper