← Back to Blog
AI / MLMarch 15, 20265 min read

Hybrid Search: BM25 + pgvector for RAG Retrieval

Combining Elasticsearch BM25 keyword search with pgvector semantic search for better RAG retrieval quality.

Two retrieval methods, one RAG pipeline

RAG retrieval quality depends on the search layer beneath it. BM25 via Elasticsearch handles exact matches: city names, hotel brands, attraction titles. pgvector handles semantic similarity: "romantic getaway" matching "honeymoon destination."

hybrid_retriever.pyPython
async def hybrid_search(query: str, top_k: int = 10):
    # BM25 keyword retrieval
    keyword_hits = await elasticsearch.search(query, top_k=top_k)

    # Vector semantic retrieval
    vector_hits = await pgvector.search(query, top_k=top_k)

    # Merge ranked results
    return reciprocal_rank_fusion(keyword_hits, vector_hits)[:top_k]

Better retrieval means better RAG context, which means better LLM answers. The search layer is where RAG quality is won or lost before the model ever sees a prompt.