RaBitQ Library 0.8.2¶
This release shortens the Python workflow to three lines for every index —
construct, add, search — and makes adding vectors to IVF-RaBitQ much faster
when the index assigns their clusters. Two default changes alter the results of
existing code; see Changes to results.
index = IvfIndex(dim, num_clusters, metric="ip") # or HnswIndex(dim) / SymqgIndex(dim)
index.add(vectors) # the first add trains the index
ids, distances = index.search(queries, k=10)
Python changes¶
- The first
addon an untrainedIvfIndexorHnswIndextrains it on the added vectors, astrain(vectors)does, sotrainis needed only to train on a sample. If thataddfails, the index stays untrained and empty.addwithcluster_idsstill requires a trained index. IVF-RaBitQ needs at leastnum_clustersrows; HNSW-RaBitQ trains one centroid per row when given fewer rows thannum_clusters. An empty firstaddraisesRuntimeError. AnIvfIndexcreated in the 0.7max_elementsform is still filled only bybuild, and untrained HNSW-RaBitQ files saved by 0.7 needtrainbeforeadd; a 0.7-formHnswIndextrains on its firstadd. nbitsdefaults to 7 forIvfIndexandHnswIndex; the 0.7 HNSW-RaBitQ form keeps 8 and SymphonyQG keeps 32.IvfIndex.searchno longer requiresnprobe: omitted,Noneor 0 probesnum_clusters / 16clusters, rounded and at least one.kmay exceed the number of points. IVF-RaBitQ, HNSW-RaBitQ and SymphonyQG fill the missing slots with ID2**32 - 1and distanceinfinstead of raisingValueError; a trained index without points returns only such slots. Testnp.isfinite(distances)to find real results.train,addandsearchon every index acceptnum_threads=Nonefor their defaults: all CPUs fortrainandadd, one thread forsearch. When the firstaddtrains,Noneusesindex.cp.num_threadsfor training.SymqgIndex.addreturns the point IDs,HnswIndexreportsMandef_construction, andrabitqlib.__version__reports the package version.
Changes to results¶
HnswIndex.searchandSymqgIndex.searchwithoutefusemax(k, 64)instead ofmax(k, 10): recall rises and queries take longer. Passef=to keep the old window.IvfIndexandHnswIndextraining (index.cp) and the C++default_training_parametersrun 10 k-means iterations instead of 25, as Faiss IVF does. The same seed therefore no longer reproduces a 0.8.1 index; setindex.cp.niter = 25to restore the old training. The k-means classes keep 25.
Performance¶
IVF-RaBitQ add without cluster_ids assigns vectors to Flat-routed centroids
(the auto choice below 5,000 clusters) with the blocked exact assignment of
k-means instead of one centroid scan per vector. On GIST1M with 4,096 clusters,
nbits=5 and 48 threads, a separate A/B run (not part of the benchmark tables)
measured adding all vectors at 24–26 s in 0.8.1 and 6.4–6.7 s now, with
identical index files. Assignments can differ only at floating-point ties, where
the new result matches a float64 reference. See the refreshed
benchmarks, whose IVF-RaBitQ results now use this
default train and add path.
C++ changes¶
IVF::searchandQuantizedGraphsearches acceptkabove the point count and fill missing slots withkPidMaxand+infinstead of throwing.QuantizedGraph::search_with_scratchthrowsstd::invalid_argumentwhen the result pool's capacity is notk.default_training_parametersruns 10 iterations, as above.
Upgrading¶
From 0.8.1, index file formats, the stable core API v1 and the Python
signatures are compatible: every new default fills a parameter that was required
or adds a value that previously raised. Review searches that omit ef and
indexes trained with default settings, which change as described above. Rebuild
C++ consumers with matching headers and libraries; no cross-version C++ binary
ABI is promised.
When upgrading from 0.7, follow the 0.8.0 release notes and the migration guide.