Vector search is useful when a query and a document express the same idea with different words. It can be weaker when the user searches for an exact error code, product identifier, function name or version. BM25 keyword retrieval handles those lexical matches well. A hybrid retrieval pipeline combines both signals so a RAG system is less dependent on one retrieval method.
Why combine lexical and semantic retrieval?
BM25 scores documents using term frequency, inverse document frequency and document length. Dense retrieval embeds queries and passages into vectors, then compares semantic similarity. Each method has blind spots: BM25 may miss paraphrases, while embeddings can rank conceptually related but operationally incorrect passages highly.
Build two candidate lists
Normalize the query, apply tenant and access filters, then run lexical and vector retrieval in parallel. Retrieve a modest candidate pool from each. Do not remove authorization filters simply to improve recall; access control must apply before content reaches the model.
Fuse rankings
Reciprocal Rank Fusion is a practical baseline because it combines rank positions rather than incomparable raw scores. The usual form is:
RRF(d) = Σ 1 / (k + rank_i(d))
Choose a constant k, combine duplicate document IDs and keep the top candidates. Then use a cross-encoder or another reranker to score query-passage relevance more carefully. Reranking costs extra latency, so apply it to a bounded candidate set.
Example pipeline
lexical = bm25.search(query, top_k=30, filters=acl)
semantic = vector.search(embed(query), top_k=30, filters=acl)
candidates = reciprocal_rank_fusion(lexical, semantic)
final = reranker.rank(query, candidates[:40])[:8]
answer = generate(query, final)
Evaluate each stage separately
Measure Recall@k and MRR or nDCG for retrieval, then evaluate answer faithfulness and citation correctness for generation. Create test queries for exact identifiers, natural-language paraphrases, rare terms, recent documents and access-restricted content. Compare lexical-only, vector-only and hybrid configurations on the same frozen dataset.
Operational safeguards
- Keep metadata filters and tenant authorization in both retrieval paths.
- Deduplicate overlapping chunks before reranking.
- Version embeddings and rebuild indexes when dimensions or models change.
- Log document IDs and scores, not raw sensitive passages by default.
- Set latency budgets for each retrieval stage.
Hybrid search is not automatically better for every corpus. It is a testable design choice: measure whether the additional recall improves answer quality enough to justify its operational cost. Continue with our RAG chunking and reranking guide and vector database comparison.
Engineering considerations
Treat the corpus as a product dataset. Remove duplicate pages, navigation noise and obsolete versions, but preserve meaningful code blocks, tables, headings and command output. Attach stable document identifiers, source URLs, update timestamps, product versions and access metadata. Chunk along semantic boundaries such as headings and procedures rather than splitting blindly by character count. Stable chunk IDs make it possible to trace a retrieved passage to its source and replace it cleanly when documentation changes.
Implementation details
Technical search needs careful lexical analysis. Generic tokenizers may split package names, CLI flags, stack traces, class names and version strings in ways that damage exact matching. Test analyzers with real queries before indexing the whole corpus. Consider separate title, heading, body and code fields, with carefully chosen boosts for high-signal fields. Synonym dictionaries can connect product terminology, but broad expansions create false positives. Keep exact identifiers searchable even when semantic normalization is applied to natural-language text.
Security and reliability controls
Manage embedding versions explicitly. Record the embedding model, dimensions, normalization behavior and index generation. Query and document vectors must be compatible; do not mix different dimensions or model generations without a deliberate migration. When changing models, build a new collection, backfill it, compare it against a frozen evaluation set and switch traffic only after validation. Track indexing lag and failed documents so the vector index does not silently drift away from the source corpus.
Testing strategy
Reciprocal Rank Fusion is a strong baseline because it combines rank positions rather than pretending BM25 and cosine scores are directly comparable. Candidate depth and the fusion constant still affect results. If the candidate list is too short, a relevant document may be discarded before fusion; if too long, reranking latency rises. Measure recall at several depths and inspect queries where either retriever contributes a uniquely relevant passage. Add retriever weights only when evaluation shows a consistent improvement.
Operational monitoring
A cross-encoder reranker can judge the query and passage together, improving fine-grained relevance at additional compute cost. Keep the candidate set bounded and ensure passage length fits the model’s input budget. Never send unauthorized tenant content to an external reranker. Apply access filters before retrieval and revalidate authorization before context is assembled for generation. A relevance model is not an access-control mechanism and must never be treated as one.
Failure diagnosis
Build reliable update and deletion pipelines. Track source checksums, indexing status and tombstones so removed documents disappear from both lexical and vector indexes. Retry transient indexing failures without creating duplicate chunks. For fast-changing operational documentation, freshness can matter more than a small gain in semantic similarity. Monitor the age of indexed documents and compare it with source timestamps. If permissions change, invalidate old representations promptly rather than waiting for a routine full reindex.
Rollout and maintenance
When an answer is poor, debug the retrieval chain in order: confirm the source exists, check metadata filters, inspect lexical and vector candidates, inspect fusion, then inspect reranking. Log query IDs, document IDs, rank positions and filter decisions while keeping sensitive passages out of ordinary logs. Only after retrieval is validated should the generation prompt be changed. This staged diagnosis avoids expensive model changes that hide an indexing or authorization defect.
Operational handover
Before handing this capability to an operations team, document the configuration owner, supported versions, dependency map and escalation path. Include the commands or dashboard views needed to verify normal operation, along with the expected values and known limitations. Store configuration in version control, review changes through the normal deployment process and keep a tested rollback procedure. Schedule periodic reviews because upstream components, security requirements and workload patterns change. A short runbook should explain how to identify a failed component, what evidence to collect, which actions are safe to retry and when to escalate. Test that runbook during a maintenance exercise rather than waiting for an outage. Finally, measure the result against a baseline: reliability improvements should be visible in error rates, latency, resource consumption, recovery time or reduced manual work. This makes the implementation maintainable after the original developer has moved to another project.




