Why do quantized vector indexes rescore a shortlist against full-precision vectors?
answer
- the cheap distance only shortlists
- ask for more candidates than k
- keep the original vectors somewhere
- re-rank the top few hundred exactly
- oversampling factor is the knob
basics
~20 sCompressed codes give noisy distances, so their ordering is unreliable near the top. Retrieving an oversized shortlist with the cheap distance and re-ranking it against the original full-precision vectors recovers most of the lost recall for a small extra cost.
solid answer
~50 sQuantization buys memory by discarding information, and the discarded part is exactly what separates the true top-10 from candidates ranked 11 to 200. So the standard pattern is two passes. Pass one uses the compressed representation as a *filter*: with binary quantization, for instance, one bit per dimension and a Hamming-distance scan over popcounts is extremely fast, and you pull an oversampled shortlist — say the top 200 for a k of 10. Pass two fetches those 200 full-precision vectors and recomputes exact distances to produce the final ordering. The tunable is the oversampling factor. Too small and the true neighbours never reach the shortlist, and no amount of rescoring invents them; too large and you pay hundreds of random vector fetches per query. Its cost is I/O and fetch latency, not memory, because the codes stay the size they were. The hard prerequisite: you must still have the full vectors somewhere — in RAM, on SSD, or memory-mapped.
go deeper
Know the shape: search the compressed index for more candidates than you need, then recompute exact distances on that small set to fix the ordering.
Be ready to explain why compressed distances are good enough to shortlist but not to rank, and to name the oversampling factor as the knob that controls the trade.
Demonstrate that you tune the shortlist against exact ground truth, recognize the capped-recall signature of an undersized shortlist, and have decided deliberately where the full-precision vectors live and what fetch latency that adds.
Own the cascade as an architecture: which tiers exist, what each one costs per candidate, and the storage commitment implied by keeping full-precision vectors alive for the lifetime of the index.
## The observation rescoring is built on Quantization error is not uniformly harmful. A compressed distance is good enough to answer "is this vector roughly in the right neighbourhood?" and bad at answering "which of these five is closest?" — the residual you threw away is on the same order as the gaps that separate top candidates. That asymmetry is exploitable: use the cheap representation for the coarse question, and the expensive representation only for the fine one, on a handful of candidates. ## The two-pass shape 1. **Shortlist.** Search the compressed index for the top `k * oversample` candidates. With binary codes this is a XOR and a popcount per candidate, running over a corpus that now fits in cache-friendly memory. With PQ codes it is a sum of lookups. 2. **Rescore.** Fetch the original vectors for exactly those candidates, compute the true distance for each, sort, and return the top k. The second pass touches maybe 200 vectors out of a billion, so its arithmetic cost is negligible. What it costs is *access*: 200 lookups into whatever store holds the full-precision vectors. ## A concrete configuration A common high-compression setup: binary quantization at one bit per dimension gives a 32x reduction, so 768-dimension vectors go from 3 KB to 96 bytes and a very large corpus becomes RAM-resident. Hamming scan produces the top 200. Full float32 vectors live on SSD or memory-mapped from disk — they are never needed for the scan, only for 200 reads. The float rescore reorders those 200, and the final top 10 is close to what exact search would have returned. Recall that would have been mediocre on binary codes alone typically climbs back into the high nineties. ## Tuning the oversampling factor This is the single knob, and it behaves like nprobe: sweep it and read the knee. - Below the knee, recall is capped by the shortlist itself. If the true nearest neighbour is ranked 340th by the compressed distance and you only retrieved 200, rescoring cannot help — the candidate was never in the room. This is the most common misconfiguration. - Above the knee, recall flattens and you are paying fetch latency for nothing. The right factor depends on how lossy the first pass is: binary codes need a much larger multiple (often 10x-30x of k) than an 8-bit scalar-quantized pass (often 2x-4x). Measure against exact ground truth on real queries; the value does not transfer between embedding models. ## Where the full vectors live, and what that costs Rescoring has a hard prerequisite that people forget when they design for minimum footprint: **the originals must still exist.** If you deleted the float vectors after encoding, the compressed ranking is the only ranking you will ever have. The placement choice is a real one: - **In RAM** — fastest, but then you are paying the memory you were trying to save. Sensible only if compression was for speed rather than capacity. - **On SSD / memory-mapped** — the usual answer. Random 3 KB reads at a few hundred per query are well within NVMe capability, and the OS page cache keeps hot vectors resident. Adds perhaps single-digit milliseconds. - **In a separate service or object store** — workable in batch, usually too slow for interactive traffic because of per-fetch round-trips. ## Cascades The pattern generalizes to more than two tiers: a binary Hamming pass to a few thousand, a PQ pass to a few hundred, then a float rescore to k. Each tier is cheaper per candidate and less accurate than the next, and each one's oversampling factor is tuned so the true neighbours survive to the following stage. The same logic reappears one layer up in retrieval systems that follow vector search with a heavier reranker — cheap recall first, expensive precision last. ## How to tell it is misconfigured The diagnostic signature is distinctive: recall is capped no matter how much you raise the first-pass effort, because the ceiling is the shortlist size, not the scan. Conversely, if raising the oversampling factor moves recall not at all, your first-pass representation is better than you assumed and you can shrink the shortlist to reclaim latency. Always evaluate recall@k of the *final* output against exact search, never the recall of the shortlist stage in isolation.
- How do you choose the oversampling factor?By sweeping it against exact ground truth on real queries and reading the knee of the recall curve. The lossier the first pass, the larger it must be — binary codes often need 10x-30x of k, an int8 scalar pass 2x-4x. If recall plateaus below target as you raise it, the first-pass representation is too weak; if it plateaus early, shrink the shortlist and reclaim latency.
- What is the symptom of a shortlist that is too small?Recall is hard-capped and refuses to move when you increase first-pass effort such as nprobe, because the true neighbours are being ranked outside the shortlist and never reach the rescoring stage. Rescoring can only reorder what it is given; it cannot recover a candidate that was excluded, so the fix is a bigger shortlist, not a bigger scan.
- Where should the full-precision vectors live if the compressed codes are in RAM?Usually on SSD or memory-mapped from disk. Rescoring touches only a few hundred vectors per query, so random NVMe reads add single-digit milliseconds while keeping the memory saving that motivated quantization in the first place, with the page cache absorbing hot vectors. Keeping originals in RAM defeats the purpose; putting them behind a network hop usually breaks interactive latency.
saying these in an interview costs you the question
- Thinks rescoring can recover candidates missing from the shortlist
- Discards the original vectors after quantizing them
- Sets the shortlist equal to k
- Believes rescoring costs memory rather than fetch I/O
- Measures recall of the shortlist instead of the final output