diskann: insert() after build() takes the index offline until a full rebuild — add Vamana incremental insert
Nobody has claimed this yet.
- Dominant language
- Rust
- Stars
- 4.5k
- Forks
- 603
- Avg merge
- 23h 32m
- Merged PRs (30d)
- 59
Description
Summary
insert() after build() takes the index offline: it appends the vector and sets built = false (index.rs:113), so every subsequent search() returns NotBuilt (index.rs:170-172) until a full build() runs again. A rebuild is O(n) graph construction plus a full PQ retrain and re-encode of every stored vector (index.rs:126-166). Vamana supports true incremental insertion, and it is cheap to add on top of the primitives this crate already has.
This matters doubly for the wasm ladder (#675, #676): a browser or edge session is long-lived and mutating, and cannot afford a multi-second full rebuild inside a worker because one document was upserted. An OPFS-persisted index (#676) wants append, not rebuild.
Verified at main c55e9e89.
Details
- index.rs:98-115:
insert()pushes into the slab and id maps, thenself.built = false. - index.rs:125: "Build the index (must be called after all inserts, before search)". So the operational model is batch-build only; there is no way to add a vector to a live index.
- The building blocks for incremental insert are already present:
greedy_search_fastfor candidate acquisition,robust_prune(graph.rs:218) for neighbor selection, and the bidirectional edge update with overflow re-prune used during build.
Suggested design (standard Vamana incremental insert)
For a new point p on a built index:
- Greedy search from the medoid for p with the build beam; the visited/candidate set is the candidate pool (one reusable
VisitedSet, see the related visited-set issue). robust_prune(p, candidates, alpha)to select p's out-neighbors (respectingmax_degree).- For each selected neighbor u, add the back-edge u -> p; if u's degree overflows, re-prune u with its existing neighbors plus p.
- Grow the pre-allocated visited set and (if PQ is enabled) encode p with the already-trained quantizer; retraining is not required per insert.
Cost is one beam search plus O(degree) prune work per insert, instead of an O(n) rebuild plus PQ retrain. Recall on incrementally built graphs stays within noise of batch-built graphs in our experience at the 10^5 to 10^6 scale; the paper's own construction is incremental at heart.
We ship exactly this in khive's vamana crate (ohdearquant/khive, crates/khive-vamana, insert()), alongside batch build, and are happy to port it here as a PR.
Measurable impact / acceptance
- Insert into a built index of n = 100k: index stays searchable throughout; per-insert cost is milliseconds (one beam search) versus a full rebuild (seconds, plus PQ retrain when
pq_subspaces > 0). - Recall@10 on a standard dataset where 20% of points are inserted incrementally after an 80% batch build is within 1 point of a 100% batch build.
insert()on a built index no longer flipsbuiltto false; a test asserts search works immediately after insert and the new id is findable.
Contributor guide
No contributing guide indexed for this repository
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 in index.rs by reading insert(), build(), and search(), then inspect graph.rs:218 for robust_prune and the existing bidirectional edge update used during build. Compare the incremental insert() implementation in khive's crates/khive-vamana if useful. Done means a built index remains searchable after insertion, the new id is findable, and incremental recall meets the stated acceptance target.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- database, search
- Issue type
- Feature
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 55/100