ML Systems Lab Open interactive version →
Advanced 22 min read semantic searchHNSWIVFembeddingsretrieval

Semantic Search & Embeddings

Bi-encoder vs cross-encoder, ANN indexes: HNSW / IVF

Keyword search breaks the moment the user's words don't match the document's. "heart attack symptoms" misses a page that says "myocardial infarction presentation" — same meaning, zero shared tokens, and BM25 has no idea. Semantic search maps queries and documents into an embedding space where *meaning* decides similarity.


Solving vocabulary creates a scale problem. The most accurate comparison is a cross-encoder — feed query and document in together so the model weighs every interaction. But it reruns per query-document pair, so it can't exceed a few hundred documents per query. Useless over 50M docs. The bi-encoder (two-tower) encodes each side separately: slightly less precise, but document embeddings are query-independent, so precompute them offline and retrieve with ANN (Approximate Nearest Neighbor) over billions in milliseconds.


Production uses both, in sequence. Bi-encoder retrieves the top few hundred from millions (fast); cross-encoder re-ranks just those hundreds (slow but precise, where the cost is affordable). Each does the job the other can't — the same recall-then-precision split as RecSys.


The encoder's pretraining objective decides whether its embeddings are usable. Raw BERT (trained with masked-LM) makes poor similarity embeddings; SBERT adds pooling + contrastive fine-tuning, and modern encoders (E5, BGE) trained with hard negatives push recall much higher — measured as recall@K, the fraction of queries whose correct document lands in the top K results returned. And every ANN index has a recall-vs-latency knob: HNSW's ef_search sets how many candidates stay in the search frontier during graph traversal (bigger ef_search = more of the graph explored = higher recall, higher latency), while IVF's nprobe sets how many inverted-list clusters get scanned per query (more clusters probed = more of the data actually checked = higher recall, higher latency). That knob must be calibrated on tail queries, not benchmarks — a 15ms P99 met on head queries will break on the tail.

Key points

Takeaway

Semantic search is the RecSys funnel for text: a bi-encoder retrieves cheaply over millions and a cross-encoder re-ranks precisely over the survivors, with embedding quality set by the encoder's contrastive pretraining and the recall/latency knob calibrated on tail queries.

Recap

Check your understanding

Q1. You need semantic search over 50M product descriptions with P99 < 15ms and recall@10 > 0.95. Which architecture fits?

Q2. A team uses raw `bert-base-uncased` [CLS] embeddings for semantic retrieval and gets poor recall. Why, and what's the minimal fix?

Q3. Select the two correct statements about why an HNSW index meets P99 in load tests but violates it for a minority of production queries.

Try it interactively

ML Systems Lab is a free interview-prep platform for ML engineers — work through the full interactive module, quizzes, and drills.

Open ML Systems Lab →