Explain exactly what the ef_search knob on an HNSW index controls at query time.
ef_search bounds the dynamic candidate list maintained during the HNSW greedy walk at the base layer. Larger = wider exploration = higher recall + more work per query. Set per query at runtime; typical range 40-500.
Imagine HNSW like a hiker hopping between viewpoints, always heading to whichever nearby viewpoint looks best. When HNSW searches for the closest vectors, it walks a graph by always jumping to the most promising node it can see. **ef_search is the size of its 'shortlist' of promising candidates to keep around.** A bigger shortlist means it considers more possibilities before settling, finding better answers but doing more work. A smaller shortlist is fast but sometimes commits to a so-so answer too early. You can change this number for every query: tiny number for cheap browsing, big number for important retrievals.
Detailed answer & concept explanation~4 min readEverything you need to truly understand this topic: intuition, mechanics, step by step explanation, code, formulas, and worked example. Click to expand.
Everything you need to truly understand this topic: intuition, mechanics, step by step explanation, code, formulas, and worked example. Click to expand.
Everything you need to truly understand this topic: intuition, mechanics, step by step explanation, code, formulas, and worked example.
Everything important, quickly.
2 min: name the dynamic-candidate-list mechanism + recall/latency tradeoff + distinguish from M and ef_construction + typical production range + Flat-ground-truth tuning.
| Knob | Phase | Tunable per query | Affects recall | Affects build cost | Affects per query latency |
|---|---|---|---|---|---|
| M | Build | No (rebuild required) | Yes (ceiling) | Yes (significant) | Modest |
| ef_construction | Build | No (rebuild required) | Yes (ceiling) | Yes (significant) | No |
| ef_search | Query | Yes | Yes (within ceiling) | No | Yes (linear) |
Real products, models, and research that use this idea.
- pgvector exposes ef_search via SET hnsw.ef_search = N per session; production RAG deployments commonly use 40-160.
- Qdrant lets ef_search be overridden per query, supporting tier based adaptive retrieval.
- Faiss HNSW indexes set index.hnsw.efSearch before each batch of queries.
- Production RAG at Notion, Glean, and similar B2B products tunes ef_search per workload tier (cheap autocomplete vs. high stakes retrieval).
- ANN-Benchmarks publishes recall-vs-latency curves swept over ef_search; the S-curve shape is visible across all HNSW implementations.
What an interviewer would ask next. Try answering before peeking at the approach.
QWhat is the right ratio between ef_search and ef_construction?
QHow does ef_search interact with a selective metadata filter on HNSW?
Don't say thisRed flags and common mistakes that signal junior thinking. Click to expand.
Red flags and common mistakes that signal junior thinking. Click to expand.
Conflating ef_search with M or ef_construction. M and ef_construction are build time, baked into the index. ef_search is runtime tunable per query; changing it does not require a rebuild.
The night-before-the-interview bullets. Scan these on the way to the call.
Primary sources. Skim if you want the original framing.
Same topic, related formats. Practice these next.