lance-format / lance-format/lance
perf: accelerate online IVF centroid routing with HNSW
Nobody has claimed this yet.
- Dominant language
- Rust
- Stars
- 7.1k
- Forks
- 852
- Avg merge
- 3d 18h
- Merged PRs (30d)
- 272
Description
Problem
IVF query routing currently computes the distance from the query to every centroid before selecting maximum_nprobes partitions. Both the legacy and V2 query paths call IvfModel::find_partitions, which delegates to kmeans_find_partitions_arrow_array.
This is exact and inexpensive for a small number of partitions, but its cost grows with num_partitions * dimension. For high-dimensional embeddings and thousands or tens of thousands of partitions, centroid routing can become a noticeable part of query latency.
Lance already has SimpleIndex, an HNSW graph over centroids, for K-means membership and build-time partition assignment. It was introduced in #4089 and later extended in #6119 and #6336. However, it cannot be directly reused for online IVF routing because it currently:
- returns only the nearest centroid, while queries need Top-
nprobes; - is temporary and is not persisted or cached with the IVF model;
- uses a fixed query
ef = 15; - has no query-facing recall or configuration contract;
- would add a new partition-routing recall loss before the partition-local search begins.
Proposal
Add an optional HNSW-based centroid router for the online IVF find_partitions path.
The design should consider:
- returning Top-
maximum_nprobescentroid IDs and distances; - a separate centroid-routing
efparameter, distinct from theefused by partition-local HNSW; - persisting the centroid graph with the IVF index, or lazily building and session-caching it if that is faster overall;
- preserving the current cosine preprocessing and distance semantics;
- falling back to exact centroid scan for small centroid sets, unsupported types/metrics, or when approximate routing is disabled;
- keeping exact routing as the compatibility-safe default until an automatic threshold is justified by benchmarks;
- recording centroid-routing latency and distance-evaluation metrics separately from partition-local search.
An optimized exact baseline should keep only Top-nprobes centroids with a heap or equivalent selection algorithm. HNSW should not claim speedup that only comes from avoiding the current full-sort overhead.
API and format questions
- Should routing be selected by an index-build option, a query option, or an automatic mode?
- Should the graph be persisted or rebuilt once and cached per session?
- What should the parameter be called so it is not confused with partition-local HNSW
ef? - How should adaptive
minimum_nprobes/maximum_nprobesinteract with approximate centroid routing? - If persisted, where should the centroid router live in the current index format without extending legacy writers?
Suggested benchmark
Compare:
- exact centroid scan + optimized Top-
nprobesselection; - HNSW centroid routing using the same centroid array.
Recommended sweep:
- dimensions: 128, 768, 1024;
- partitions: 256, 1K, 4K, 16K;
nprobes: 4, 16, 64;- centroid HNSW
ef:nprobes,2x,4x,8x.
Record:
- centroid-routing p50/p95/p99 latency;
- number of query-to-centroid distance evaluations;
- partition recall against exact Top-
nprobes; - end-to-end Recall@K and p50/p95/p99 query latency;
- graph memory, build time, and load time.
Also run a 2x2 experiment to separate the two approximation layers:
| Centroid routing | Partition-local search |
|---|---|
| Exact | IVF_PQ scan |
| Exact | HNSW-PQ |
| HNSW | IVF_PQ scan |
| HNSW | HNSW-PQ |
Acceptance criteria
- Identify the
num_partitions * dimensionbreak-even point where centroid HNSW consistently beats an optimized exact baseline at the same end-to-end Recall@K. - Avoid query latency regression below the break-even point through exact fallback.
- Validate
centroid_ef >= maximum_nprobeswith a descriptive error. - Add recall and correctness coverage for supported metrics and multiple
nprobesvalues. - Preserve current behavior when the feature is not enabled.
Relevant code
rust/lance-index/src/vector/utils.rs: build-timeSimpleIndexrust/lance-index/src/vector/ivf.rs:IvfModel::find_partitionsrust/lance-index/src/vector/kmeans.rs: exact centroid distance computation and selectionrust/lance/src/index/vector/ivf.rs: legacy IVF query routingrust/lance/src/index/vector/ivf/v2.rs: V2 IVF query routing
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by reading rust/lance-index/src/vector/ivf.rs and rust/lance-index/src/vector/kmeans.rs, then compare the legacy and V2 routing paths in rust/lance/src/index/vector/ivf.rs and rust/lance/src/index/vector/ivf/v2.rs. Benchmark optimized exact Top-nprobes selection against HNSW routing across the proposed sweep, and define the configuration, fallback, persistence or caching, and recall behavior. Done means meeting the acceptance criteria without changing behavior when the feature is disabled.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- machine-learning, performance, search
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100