Retrieval Algorithms in RAG: Term-Based, Embedding-Based, and Hybrid Methods

Retrieval algorithms in RAG fall into three categories: term-based methods (BM25, Elasticsearch) for fast lexical matching, embedding-based methods (FAISS, HNSW) for semantic vector search, and hybrid approaches that combine both signals for higher accuracy.

Retrieval-augmented generation systems rely on specialized algorithms to fetch relevant context from external knowledge stores before generation occurs. According to the chiphuyen/aie-book repository, these algorithms determine the speed, accuracy, and scalability of RAG pipelines. Understanding the trade-offs between lexical and semantic retrieval methods is essential for production implementations.

Term-Based Retrieval Algorithms

Term-based retrievers index raw text as inverted lists of terms and score relevance using term frequency, inverse document frequency, and document length normalization.

BM25 (Best Match 25) is the classic probabilistic model that powers modern implementations. As noted in chapter-summaries.md, "Term-based retrievers, such as Elasticsearch and BM25, are much lighter to implement and can provide strong baselines" [L134]. These algorithms excel in specialized domains like code or legal text where exact term matching is critical.

Key characteristics include:

  • Extremely fast retrieval with minimal computational overhead
  • No GPU requirements—runs efficiently on CPU
  • Strong baseline performance without training data
  • Limited semantic understanding—misses conceptually related terms

Embedding-Based Retrieval Algorithms

Embedding-based retrievers convert document chunks into dense vectors using sentence-embedding models, then perform nearest-neighbor search in high-dimensional space.

As documented in chapter-summaries.md, "Embedding-based retrieval is powered by vector search, which is also the backbone of many core internet applications" [L136]. Common implementations include FAISS (Facebook AI Similarity Search), HNSW (Hierarchical Navigable Small World), ScaNN (Scalable Nearest Neighbors), IVF-PQ (Inverted File Product Quantization), Annoy (Approximate Nearest Neighbors Oh Yeah), and commercial solutions like Qdrant and Pinecone.

These algorithms leverage approximate-nearest-neighbor (ANN) techniques to balance speed and recall:

  • Capture semantic meaning beyond exact term matches
  • Handle conversational or "fuzzy" queries effectively
  • Require significant memory and compute resources (GPU/CPU)
  • Scale to millions of chunks with sub-second latency when properly tuned

Hybrid Retrieval Algorithms

Hybrid retrievers combine the lexical signal from term-based methods with the semantic signal from embeddings to create more robust result sets.

The repository highlights this approach in Figure 7-3 context: "After simple retrieval (such as term-based retrieval), whether to experiment with more complex retrieval (such as hybrid search)" [L148]. Implementation strategies include linear weighting of BM25 and vector scores, reciprocal rank fusion, and dense-sparse architectures like ColBERT-v2.

This architecture delivers:

  • Higher recall by capturing both exact matches and conceptual similarity
  • Mitigation of individual weaknesses—term-based misses synonyms while pure semantic misses precise terminology
  • Flexible scoring mechanisms that can be tuned for specific domains

Practical Implementation Examples

Below are production-ready implementations for each retrieval family using Python.

Term-Based Search with Elasticsearch

from elasticsearch import Elasticsearch, helpers

es = Elasticsearch("http://localhost:9200")

def index_documents(docs):
    actions = [
        {
            "_index": "rag-corpus",
            "_id": doc["id"],
            "_source": {"text": doc["text"]},
        }
        for doc in docs
    ]
    helpers.bulk(es, actions)

def bm25_search(query, top_k=5):
    body = {
        "size": top_k,
        "query": {
            "match": {
                "text": {"query": query, "operator": "and"}
            }
        },
    }
    response = es.search(index="rag-corpus", body=body)
    return [hit["_source"]["text"] for hit in response["hits"]["hits"]]

Embedding-Based Search with FAISS

import faiss
import numpy as np
from sentence_transformers import SentenceTransformer

model = SentenceTransformer("all-MiniLM-L6-v2")
vectors = model.encode([doc["text"] for doc in documents], normalize_embeddings=True)
dimension = vectors.shape[1]

# IVF-PQ index for large-scale retrieval

quantizer = faiss.IndexFlatIP(dimension)
index = faiss.IndexIVFPQ(quantizer, dimension, nlist=100, m=8, nbits=8)
index.train(vectors)
index.add(vectors)

def faiss_search(query, k=5):
    query_vector = model.encode([query], normalize_embeddings=True)
    distances, indices = index.search(query_vector, k)
    return [documents[i]["text"] for i in indices[0]]

Hybrid Search Implementation

def hybrid_search(query, k=5, bm25_weight=0.5):
    # Stage 1: BM25 shortlist for high recall

    bm25_candidates = bm25_search(query, top_k=50)
    
    # Stage 2: Re-rank with embeddings

    candidate_vectors = model.encode(bm25_candidates, normalize_embeddings=True)
    distances, _ = index.search(candidate_vectors, 1)
    
    # Stage 3: Linear fusion of scores

    faiss_scores = distances.flatten()
    bm25_scores = np.linspace(1.0, 0.5, len(bm25_candidates))
    
    blended = []
    for i, text in enumerate(bm25_candidates):
        combined_score = (bm25_scores[i] * bm25_weight + 
                         faiss_scores[i] * (1 - bm25_weight))
        blended.append((combined_score, text))
    
    blended.sort(reverse=True)
    return [text for _, text in blended[:k]]

Summary

  • Term-based algorithms (BM25, Elasticsearch) provide fast, lightweight lexical retrieval that works well for exact match scenarios and specialized domains.
  • Embedding-based algorithms (FAISS, HNSW, Pinecone) enable semantic search through dense vector representations, requiring ANN indexing but delivering superior performance on conceptual queries.
  • Hybrid approaches combine both methodologies to maximize recall while maintaining latency constraints, using techniques like reciprocal rank fusion or linear score weighting.
  • The chapter-summaries.md file in the chiphuyen/aie-book repository explicitly documents these three families as the foundation of modern RAG architecture.

Frequently Asked Questions

What is the difference between BM25 and vector search in RAG?

BM25 is a probabilistic term-weighting scheme that ranks documents based on term frequency and inverse document frequency, making it ideal for exact keyword matching. Vector search converts text into dense embeddings and finds semantic neighbors in high-dimensional space, capturing conceptual similarity even when specific terms differ. BM25 requires no training and runs on minimal hardware, while vector search requires embedding models and ANN indexes but handles paraphrasing and synonyms.

When should I use hybrid retrieval instead of a single algorithm?

Use hybrid retrieval when your application requires both high precision for specific terminology and high recall for conceptual understanding. Legal or medical domains often benefit from hybrid approaches because they contain precise jargon (where BM25 excels) alongside complex conceptual relationships (where embeddings excel). According to the repository's architecture guidelines, hybrid search becomes necessary when simple retrieval proves insufficient for the query complexity.

What are the best vector databases for embedding-based retrieval?

The repository highlights FAISS for research and prototyping, HNSW for high-performance approximate search, and managed solutions like Pinecone or Qdrant for production deployments. ScaNN and IVF-PQ offer optimized quantization for massive scale, while Annoy provides memory-efficient trees for read-heavy workloads. Selection depends on your scale requirements, latency constraints, and operational preferences (self-hosted vs. managed).

How does reciprocal rank fusion work in hybrid RAG systems?

Reciprocal rank fusion (RRF) combines results from multiple retrieval algorithms by assigning scores based on the inverse of each result's rank position across different methods. Rather than normalizing raw scores from BM25 and vector search (which use incompatible scales), RRF calculates score = 1/(k + rank) for each result, then sums these scores across retrieval methods. This rank-based approach eliminates the need to tune score weights and naturally handles cases where one algorithm might dominate raw scoring scales.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →