Semantic search (vector similarity) understands intent: 'how do I reset my password' matches a document about 'account recovery'. But it misses exact matches: a document containing the exact error code 'ERR_AUTH_0x80070005' may not rank highly for a query containing that error code. Keyword search (BM25) catches exact matches but misses intent. Hybrid search combines both, giving you the strengths of each without the weaknesses.
How Hybrid Search Works
Hybrid search runs two searches in parallel: semantic search (vector similarity) and keyword search (BM25 or similar). Each search produces a ranked list of results with relevance scores. The two lists are merged using a fusion algorithm (typically Reciprocal Rank Fusion or weighted score combination). The merged list is then reranked for final relevance. The result: documents that match either semantically or by keyword appear in the results, with documents that match both ranking highest.
When Each Search Type Wins
Semantic search wins for: intent-based queries ('how do I add a user'), conceptual questions ('what is the best practice for...'), and queries with synonyms ('billing' vs 'payment' vs 'invoice'). Keyword search wins for: exact term matches (error codes, product names, specific numbers), proper nouns (company names, person names), and queries with specific technical terms ('PostgreSQL pgvector HNSW index'). Most real-world queries benefit from both — users naturally mix intent-based language with specific terms.
Implementation in PostgreSQL
PostgreSQL supports hybrid search natively with pgvector + full-text search. The query combines vector similarity (pgvector's cosine distance) with full-text search (PostgreSQL's ts_rank) using a weighted combination. The weights determine the relative importance of semantic vs keyword matching. Typical weights: 0.6 semantic, 0.4 keyword for intent-heavy domains; 0.4 semantic, 0.6 keyword for technical domains with lots of specific terms. Tune the weights based on your retrieval evaluation metrics.
Pro Tip
Start with 0.6 semantic / 0.4 keyword weights and tune based on your evaluation dataset. The optimal weights depend on your domain and query patterns.
Conclusion
Hybrid search combines semantic and keyword search to catch both intent and exact matches. Implementation in PostgreSQL is straightforward with pgvector + full-text search. Tune the semantic/keyword weights based on your domain and evaluation metrics.
Key Takeaways
- Hybrid search = semantic (intent) + keyword (exact) — catches both in a single query
- Semantic wins for intent; keyword wins for exact terms; most queries benefit from both
- PostgreSQL: combine pgvector cosine distance with ts_rank using weighted fusion
- Typical weights: 0.6/0.4 (semantic/keyword) for intent-heavy domains
- Tune weights based on retrieval evaluation metrics — optimal weights are domain-specific