Questions
2 of 14
1What does HNSW stand for, and at a high level, how does it achieve sub-linear approximate nearest-neighbor search?
2What do the HNSW parameters m and ef_construct control, and what trade-off do they represent?
3What does the query-time parameter ef (search breadth) control, and how would you use it to trade off recall against latency?
4Why might increasing m significantly improve recall on one dataset but barely help - or even hurt latency - on another?
5Why does Qdrant set m: 0 on a named vector used purely for reranking (e.g. a ColBERT multivector)?
6What problem does vector quantization solve, and what is the fundamental trade-off it introduces?
7Compare scalar quantization, product quantization, and binary quantization in Qdrant in terms of compression ratio and accuracy impact.
8What are oversampling and rescoring in the context of binary quantization, and why are they necessary?
9What newer quantization options - beyond the original scalar, product, and binary trio - has Qdrant introduced to fine-tune the compression/accuracy curve?
10What is Inline Storage, and how does embedding quantized vectors directly into HNSW graph nodes improve disk-based search performance?
11What is a multivector point, and how does it differ from a point with several named vectors?
12How does late-interaction scoring (as used by ColBERT-style models) with MaxSim differ from comparing two single dense vectors?
13Why is late-interaction reranking typically applied to a small candidate set rather than the entire collection?
14Design a three-stage retrieval pipeline using dense retrieval, sparse retrieval, fusion, and ColBERT reranking. What does each stage contribute?
02 / 14

What do the HNSW parameters m and ef_construct control, and what trade-off do they represent?

m is graph connectivity, ef_construct is build-time search breadth

m and ef_construct are both build-time parameters and they control two orthogonal things. m is the maximum number of outbound edges each node is allowed to keep on layers above 0; on layer 0 the cap is 2m because edges are stored bidirectionally. It is the graph connectivity, and it directly drives index memory: roughly 2m * 4 bytes per point on layer 0, plus the upper layers. ef_construct is the size of the dynamic candidate list used while inserting a new node. When a new point is added, HNSW runs a search from the entry point down to the new node level with a beam width of ef_construct, then applies the diversity heuristic to pick which of those candidates actually become edges. So m controls how many edges survive, and ef_construct controls how good a pool of candidates those edges are chosen from.

The mechanism matters because it explains why the two parameters are not interchangeable. If you raise m but leave ef_construct small, you are telling the graph to keep more edges but you are only giving it a shallow candidate pool to choose from - the extra edges tend to be redundant near neighbors rather than useful long-range links, so recall improves only marginally. If you raise ef_construct but leave m small, you give the algorithm a better view of the neighborhood at build time but it can only keep a few of those candidates, so the graph quality gain is capped by m. The two parameters work together: ef_construct determines the quality of the decision, m determines how much of that quality you can store. The diversity heuristic is what converts a wider ef_construct into genuinely better navigability, because a wider beam is more likely to surface a distant candidate that survives the heuristic and becomes a long-range edge.

  1. 1

    m: higher = denser graph, better recall, more memory, slower build, higher cache pressure at query time. Typical range is 16-64; the Qdrant default is 16.

  2. 2

    ef_construct: higher = better graph quality, slower build, no effect on query latency or memory. Typical range is 100-500; the Qdrant default is 100.

  3. 3

    Both require a re-index to change. Neither can be tuned per query.

  4. 4

    There is a hard trade-off between m and memory: doubling m roughly doubles graph memory on layer 0, which is often the dominant cost at scale.

The trade-off is therefore memory and build time against recall, with no free lunch. My rule of thumb is to set m based on memory budget first, then set ef_construct high enough that the graph is well connected (typically 2-4x m is a reasonable starting point, but measure). The common mistake is assuming ef_construct affects query performance. It does not - it is purely a build-time knob, and if you are trying to fix slow queries by lowering ef_construct you are just going to get a worse index for the same query cost. Another common mistake is setting m very high expecting linear recall gains. In practice recall vs m plateaus: once the graph is connected enough for the intrinsic dimensionality of the data, extra edges add memory and cache misses without improving recall. The alternative to raising m is to raise ef at query time instead, which costs latency but no memory and no rebuild - often the better lever when you cannot afford a re-index. If memory is the binding constraint, IVF-PQ is the alternative index family to consider, trading recall for a much smaller footprint.

javascript

Version-dependent: Qdrant has adjusted default m and ef_construct values across releases and the defaults differ by vector size, so read the effective config with client.get_collection() rather than assuming. The update_collection path for hnsw_config has been stable for several releases, but on very large collections the re-index can be effectively an outage, so the production-safe pattern is to create a new collection with the target config and migrate points rather than mutating in place.

Difficulty: 7/10
Topics: HNSW, Index Configuration, Vector Search Tuning

Scenario Questions

0-2 years experience
  1. 1

    You are creating a Qdrant collection for a small demo with 50k vectors. What m and ef_construct do you pick, and why does the choice barely matter at this scale?

  2. 2

    A teammate says the index is slow to build because m is too high and wants to lower it. Is that correct, and what else could be responsible for slow builds?

2-5 years experience
  1. 1

    You raise m from 16 to 48 on a 20M-point collection and memory usage triples while recall only goes from 0.91 to 0.93. Diagnose what is happening and propose a better use of that memory budget.

  2. 2

    Your team wants to add 5M new points per day to a collection with m=32. Explain how the build cost of HNSW interacts with your ingest rate and what you would change to keep up.

5-8 years experience
  1. 1

    Design an experiment that isolates the effect of m from ef_construct on recall and latency for a specific dataset. What do you measure, how many configurations, and how do you avoid confounding the two?

  2. 2

    You are asked to cut index memory by 50 percent without losing more than two points of recall@10. Walk through the levers (m, quantization, on-disk, dimensionality reduction) and the order in which you would try them.

8+ years experience
  1. 1

    You must build HNSW for a 2B-vector corpus under a strict build-time SLO and a fixed memory budget. Derive how you would choose m and ef_construct analytically from the SLO, and explain where the analytical model breaks down in practice.

  2. 2

    A vendor claims their HNSW variant dominates Qdrant at the same m and ef_construct. What would you measure to falsify that claim, and what hidden knobs (heuristic variants, entry point selection, pruning strategy) would you expect them to be exploiting?

Follow-up Questions

  • You have a fixed memory budget and a recall target. How do you decide whether to spend that budget on a higher m, on quantization to free up memory for a higher m, or on a higher ef at query time?
  • If ef_construct is doubled but m is unchanged, what specifically changes in the graph, and why does recall often improve much less than you would expect?