Embedding Models & Semantic Search
How embedding models power semantic search: bi-encoders vs cross-encoders, re-ranking, hybrid search combining keywords and vectors, and choosing embeddings for retrieval quality.
On this page
Embeddings turn text into vectors whose closeness reflects meaning — the foundation of semantic search and RAG. This tutorial goes deeper than "embeddings enable search": bi-encoders versus cross-encoders, why hybrid search wins, and how to actually choose an embedding model for retrieval quality.
Key Takeaways
- Bi-encoders embed query and document separately (fast, precomputable) — they power vector search.
- Cross-encoders score query-document pairs together (accurate, slow) — they power re-ranking.
- Hybrid search fuses keyword and vector search to cover each other's blind spots.
- Choose an embedding model by measuring retrieval hit rate on your data, not by benchmark.
Bi-encoders: fast, precomputable
A bi-encoder embeds the query and each document independently. Because documents are embedded ahead of time and stored, search is just comparing the query vector against stored vectors — fast enough for interactive use over millions of documents.
This is what every vector store uses. Its limitation is that query and document never "see" each other during embedding, so the relevance signal is coarser than it could be.
Cross-encoders: accurate, slow
A cross-encoder takes the query and a document together and outputs a relevance score. Because it processes them jointly, it captures subtle relevance a bi-encoder misses — but it cannot precompute anything, so scoring every document against a query is far too slow for first-pass retrieval.
The winning pattern: retrieve wide, re-rank narrow
Combine both. Use the bi-encoder to fetch a generous candidate set fast, then the cross-encoder to re-rank that small set accurately:
// 1. Bi-encoder retrieves 30 candidates cheaply from millions.
List<Document> candidates = vectorStore.search(query, 30);
// 2. Cross-encoder re-ranks those 30 accurately, keeping the best 5.
List<Document> best = reranker.rerank(query, candidates, 5);Hybrid search: keywords plus vectors
Vector search understands meaning but is blind to exact tokens — it will happily miss the error code
ERR_4021 because it does not "mean" anything semantically. Keyword search (BM25) catches exact
matches but misses paraphrases. Hybrid search runs both and fuses the results:
// Run keyword and vector search, then fuse rankings (e.g. reciprocal rank
// fusion). Recovers exact-identifier queries that pure vector search drops.
List<Document> keywordHits = bm25Search(query, 20);
List<Document> vectorHits = vectorStore.search(query, 20);
List<Document> fused = reciprocalRankFusion(keywordHits, vectorHits);Hybrid search is especially valuable for technical content full of exact identifiers — product SKUs, error codes, function names, API paths — where users often search for the exact string.
Choosing an embedding model
The decision is empirical, not theoretical:
- Shortlist by domain fit (general vs specialised), language coverage, dimension and cost.
- Build a question set of real queries with the passage that should answer each.
- Measure hit rate — for each candidate model, what fraction of questions retrieve the correct passage in the top k?
- Pick the winner on your data.
// The only benchmark that matters: your queries against your documents.
for (EmbeddingModel model : candidates) {
double hitRate = evaluateRetrieval(model, goldenQuestions);
log.info("model={} hitRate@5={}", model, hitRate);
}A model that tops a public embedding leaderboard can lose to a smaller one on your specialised corpus. Your hit rate is the ground truth. See testing AI applications.
Domain and multilingual considerations
- Specialised domains (legal, medical, code) sometimes do better with a domain-tuned embedding model than a general one — measure both.
- Multilingual content needs a multilingual embedding model, or retrieval across languages fails.
- Symmetric vs asymmetric — some models are tuned for short-query-to-long-document matching (asymmetric), which suits RAG better than models tuned for similar-length comparison.
Next
Frequently Asked Questions
What is the difference between a bi-encoder and a cross-encoder?
What is hybrid search and why does it help?
When should I add re-ranking to semantic search?
How do I choose an embedding model for retrieval?
Related tutorials
- Vector Databases Deep DiveHow vector databases work under the hood: the HNSW index, approximate nearest-neighbour search, cosine vs Euclidean distance, product quantization and metadata filtering — for Java developers.
- Prompt Engineering MasterclassAdvanced prompt engineering techniques: prompt chaining, meta-prompting, self-consistency, structured reasoning and prompt optimization — beyond the basics, for reliable production prompts.
- Fine-Tuning LLMs: LoRA & QLoRAUnderstand fine-tuning for engineers: LoRA and QLoRA, instruction tuning, RLHF and DPO, and the crucial decision of when to fine-tune versus when retrieval or prompting is the better tool.
- Tokenization & Context WindowsUnderstand tokens and context windows: how BPE tokenization works, why code costs more tokens, managing the context budget, and the token math behind LLM cost — for Java developers.