Larry Xiong
Back to Blog

Hybrid Search: Give Exact Matches and Meaning a Vote

Larry Xiong · Published · ~11 min read

Why combining keyword search and semantic retrieval can improve RAG systems, how reciprocal rank fusion works, and what to measure before adding more complexity.

Bookshelves and hanging lights in a library
Cover photo: Unsplash · Unsplash License · Illustrative photograph

One of the challenges in building a reliable RAG system is making sure it retrieves the right information before sending anything to the language model.

Semantic search is powerful because it can understand the meaning behind a question, even when the user's words don't match the source documents.

But meaning isn't always enough.

Consider someone searching for an error code like ERR_CONNECTION_RESET. They probably want documentation about that exact error, not a general explanation of network failures.

Now consider another user asking, "Why does my connection keep dropping?"

This question doesn't contain a specific identifier. Finding the right information depends more on understanding intent than matching individual words.

Both questions are valid, but they benefit from different retrieval strategies.

That's where hybrid search becomes useful.

By combining traditional keyword search with semantic retrieval, we can cover a broader range of questions without forcing users to understand how the knowledge base works internally.

In this article, I'll explain how I approach hybrid retrieval, why I use reciprocal rank fusion (RRF), and what I evaluate before introducing a reranker.

1. Understand what each search method does well

Before combining retrieval methods, it's important to understand their strengths and limitations.

Keyword search with BM25

BM25 is a well-established ranking algorithm used in traditional information retrieval.

It considers factors such as term frequency, how common a term is across documents, and document length.

In practice, keyword search works well when users provide specific terms, including:

For example, if someone searches for POST /api/v1/documents, keyword retrieval can help find documentation containing that exact endpoint.

However, BM25 depends on how text is indexed and analyzed. Tokenization, punctuation handling, and field configuration can affect whether identifiers are preserved.

For important technical identifiers, I would consider dedicated exact-match fields or appropriate analyzers rather than assuming ordinary full-text search will always preserve them.

Semantic search with embeddings

Semantic search takes a different approach.

It converts queries and documents into vector representations that capture aspects of their meaning.

This allows the system to retrieve related content even when the wording is different.

For example:

User question: "How can I recover access to my account?"

Document heading: "Resetting forgotten credentials"

A semantic retriever may recognize the relationship even though the phrases share few words.

This is especially useful for natural-language questions, paraphrases, and documentation written in different styles.

However, semantic similarity doesn't guarantee factual relevance.

Two passages may discuss similar concepts but refer to different products, versions, or business rules.

That's why I don't treat vector search as a complete replacement for keyword retrieval.

2. Keep a lexical baseline

One mistake I try to avoid is introducing a more complex retrieval architecture before measuring a simpler one.

BM25 is a useful baseline because it is relatively inexpensive, explainable, and often surprisingly effective.

The BEIR research paper, first submitted in April 2021, evaluated ten retrieval systems across eighteen datasets.

The researchers found that BM25 remained a robust baseline, while reranking and late-interaction approaches generally achieved strong retrieval results at higher computational cost.

These findings don't mean BM25 is always better than modern embedding models. They show why retrieval decisions should be based on evaluation rather than assumptions.

For a document-heavy application, I would start by collecting representative questions and measuring keyword retrieval on its own.

Then I would evaluate semantic retrieval using the same questions.

The goal is to identify which types of queries each method handles well and where it fails.

For example, keyword search might perform better on product identifiers, while semantic search might find more relevant passages for loosely phrased questions.

Those differences are useful evidence when deciding whether hybrid retrieval is worth the added complexity.

3. Combine retrieval results with reciprocal rank fusion

Once keyword and semantic retrieval are working independently, the next challenge is combining their results.

A straightforward idea is to add their relevance scores together.

Unfortunately, that isn't always reliable.

BM25 scores and vector similarity scores are calculated differently. Their numerical ranges aren't directly comparable, so adding them without normalization can cause one search method to dominate the results.

One practical alternative is reciprocal rank fusion (RRF).

Instead of combining raw scores, RRF considers where each document appears in the ranked results.

A document that ranks highly in both search methods receives contributions from both lists.

A document appearing in only one list can still rank well if its position is strong enough.

The formula is:

RRF(d) = Σ (1 / (k + r)), for each rank r in R(d)

Where:

A commonly used starting value is k = 60, which is also the documented default in Elasticsearch.

That doesn't mean 60 is optimal for every dataset.

The constant and the number of candidates retrieved from each search method can influence the final ranking.

Elasticsearch RRF documentation

A simple Python implementation

Here's a standalone implementation that merges multiple ranked lists:

from collections import defaultdict def reciprocal_rank_fusion(rankings, rank_constant=60): if rank_constant < 1: raise ValueError("rank_constant must be positive") scores = defaultdict(float) for ranking in rankings: # Count each ID only once per retrieval list. unique_ids = dict.fromkeys(ranking) for rank, document_id in enumerate( unique_ids, start=1 ): scores[document_id] += 1.0 / ( rank_constant + rank ) return sorted( scores, key=lambda doc_id: (-scores[doc_id], str(doc_id)) )

The function accepts ranked document IDs from different retrievers and returns a combined ranking.

It removes duplicate IDs within each retrieval list while allowing the same document to receive contributions from different retrievers.

The final sort uses the document ID to resolve equal scores consistently.

This is an illustrative implementation. A production system also needs consistent document IDs, permission filtering, candidate limits, and suitable handling of deleted or outdated content.

4. Design hybrid search around real questions

A typical hybrid retrieval pipeline looks like this:

User Question → Keyword Search + Semantic Search → RRF → Relevant Passages → LLM

Both retrieval methods operate on the same authorized document collection.

The combined ranking determines which passages are considered for the final context.

That sounds simple, but several implementation details matter.

Document identity

Keyword and vector indexes must use consistent identifiers.

Otherwise, the same document can appear as unrelated results in the two retrieval lists.

For RAG, I usually want retrieval results tied to stable passage IDs and their parent documents.

Document versions

An outdated document may be semantically similar to a current one.

If both versions remain searchable without appropriate metadata, hybrid retrieval can promote obsolete information.

Document versioning and freshness rules need to be part of the retrieval design.

Access control

A document should never become available simply because it ranks highly.

User permissions must be enforced before restricted content is returned or passed to the LLM.

For permission-sensitive applications, access filtering is a correctness and security requirement, not a ranking preference.

Duplicate content

Documentation often contains repeated passages.

Multiple versions of the same instructions can occupy several positions in the final results and reduce the diversity of useful evidence.

Deduplication and document identity handling help prevent that problem.

These details aren't unique to hybrid search, but combining indexes makes them easier to overlook.

5. Evaluate lexical, semantic, and hybrid retrieval separately

I wouldn't deploy hybrid search based only on a few successful demonstrations.

Instead, I would compare three configurations using the same evaluation dataset:

  1. BM25-only retrieval
  2. Semantic-only retrieval
  3. Hybrid retrieval using RRF

The dataset should include questions that reflect actual user behavior.

For a technical knowledge base, that might include exact identifiers, paraphrased questions, version-specific requests, multi-document questions, and questions that cannot be answered from the available information.

I would measure several aspects of retrieval quality.

MetricWhat it helps measure
Recall@KHow much known relevant evidence appears in the top K results
Precision@KHow many of the top K results are relevant
MRRHow early the first relevant result appears
NDCG@KHow well results are ordered by graded relevance
Retrieval latencyHow long retrieval takes
Cost and resource usageInfrastructure or model expense

These metrics provide different views of the system.

Recall is useful when missing important evidence is the main risk.

Ranking metrics help determine whether the best passages appear early enough to fit within the model's context budget.

Latency and resource usage help establish whether the quality improvement is practical for the application.

I would also examine results by query category.

If hybrid retrieval improves paraphrased questions but consistently pushes exact API references lower, that regression deserves attention even when the overall average improves.

A better average score doesn't necessarily mean a better experience for every type of question.

6. Add a reranker only when it solves a measured problem

Hybrid retrieval improves candidate discovery, but the fused ranking isn't guaranteed to be optimal.

A reranker can provide an additional relevance check by evaluating each query against candidate passages more directly.

A common architecture is:

Keyword + Semantic Retrieval → RRF → Reranker → Top Passages → LLM

For example, the initial retrievers might produce several dozen candidates.

RRF combines them, and a reranking model then evaluates a smaller candidate set to select the most relevant passages.

This can improve ranking quality, particularly when the first-stage retrievers return several plausible results.

However, reranking introduces tradeoffs.

It adds inference time, consumes computational resources, and creates another component that needs monitoring.

The right question isn't simply whether a reranker improves a benchmark score.

It's whether the improvement is meaningful enough to justify the additional latency and cost.

I would compare retrieval quality before and after reranking, including the 95th-percentile response time and infrastructure cost.

I would also inspect whether the improvement comes from better ordering of useful passages or whether a deeper ingestion or indexing problem still needs attention.

A reranker cannot recover a relevant document that never made it into the candidate set.

That's why I prefer evaluating the initial retrieval stages first.

7. Keep the production architecture manageable

Hybrid search introduces additional moving parts.

Depending on the implementation, the system may maintain a full-text index, a vector index, document metadata, and separate retrieval configurations.

Those components need to stay consistent as documents are added, updated, and deleted.

In production, I would pay attention to:

Fallback behavior deserves particular attention.

If semantic retrieval becomes unavailable, the application might continue using keyword search, depending on the product's requirements.

However, it should not silently produce normal-looking responses if that fallback materially changes answer quality.

At a minimum, the system should record the degraded state so engineers can investigate it.

The goal is to make retrieval reliable and understandable, not just technically sophisticated.

Final thoughts

Hybrid search is valuable because users don't always ask questions in the same way.

Some questions need exact matches. Others depend on meaning, context, and natural language.

Combining BM25 with semantic retrieval gives both approaches an opportunity to contribute relevant evidence.

Reciprocal rank fusion offers a practical way to merge their rankings without directly combining incompatible relevance scores.

But hybrid search isn't automatically the best solution.

I would start with a lexical baseline, evaluate semantic retrieval independently, compare the combined results, and introduce reranking only when the measured improvement justifies the additional cost.

The real objective isn't to build the most complex retrieval pipeline.

It's to consistently deliver the right evidence to the language model while keeping the system fast, secure, and maintainable.

Good retrieval engineering is about finding the right information, understanding why it was selected, and knowing when a simpler approach is enough.