If you only read one thing, read this!
GraphIndexBuilder
M
parameter now represents the maximum degree of the graph, instead of half the maximum degree. (The former behavior was motivated by making it easy to make apples-to-apples comparisons with Lucene HNSW graphs.) So, if you were building a graph of M=16 with JVector2, you should build it with M=32 with JVector3.- Support for indexes over byte vectors has been removed. This is because the implementation was becoming increasingly specialized for float vectors, leaving byte vector support as a secondary concern. This specializes many structures that were previously generic over vector type.
- JVector 3 adds several optional features to the on-disk storage format, but remains compatible with indexes written by JVector 1 and 2.
- Experimental support for native code acceleration has been added. This currently only supports Linux x86-64
with certain AVX-512 extensions. This is opt-in and requires the use of MemorySegment
VectorFloat
/ByteSequence
representations. - Experimental support for fused ADC graph indexes has been added. These work best in concert with native code acceleration. Without the NativeVectorizationProvider, results using fused ADC will be valid but performance will degrade. This explores a design space allowing for packed representations of vectors fused into the graph in shapes optimal for approximate score calculation. This is a new feature of graph indexes and is opt-in. At this time, only graphs with a maximum degree of 32 and 256-cluster ProductQuantization can use fused ADC.
- Support for larger-than-memory graph construction by using quantized vectors + rerank for the searches performed during construction.
- Support for Anisotropic Product Quantization as described in "Accelerating Large-Scale Inference with Anisotropic Vector Quantization" (https://arxiv.org/abs/1908.10396)
GraphIndexBuilder.markNodeDeleted
is now threadsafeGraphIndexBuilder::removeDeletedNodes
is parallelized and significantly faster.
GraphIndexBuilder
andGraphSearcher
scoring are encapsulated byBuildScoreProvider
andSearchScoreProvider
, respectively.BuildScoreProvider.randomAccessScoreProvider()
andBuildScoreProvider.pqBuildScoreProvider()
offer convenient ways to construct a BSP from full-resolution vectors in memory or with PQ-compressed vectors with reranking, respectively.addGraphNode(int node, VectorFloat<?> vector)
is now the preferred way to construct a graph incrementally.GraphIndexSearcher::resume
is added to allow resuming a previous search from where it left off.ProductQuantization::refine
allows fine-tuning a new PQ object with additional vectors, starting with an existing PQ- Changes to KMeansPlusPlusClusterer to support Anisotropic PQ
VectorFloat
andByteSequence
are introduced as abstractions over float vectors and byte sequences. These are used in place offloat[]
andbyte[]
in many places in the API. This is to permit the possibility of alternative implementations of these types. This requires changes to many internal/external API surfaces.NodeSimilarity
has been removed.ScoreFunction
is now a top-level interface; grouping of functions for build and for search are now done byBuildScoreProvider
andSearchScoreProvider
.- BuildScoreProvider allows the creation of larger-than-memory indexes by using compressed vectors during graph construction.
- Reranking is done using
ExactScoreFunction::similarityTo(int[])
rather than with a Map parameter. The map change is because we discovered that (in contrast with the original DiskANN design) it is more performant to read vectors lazily from disk at reranking time, since this will only have to fetch vectors for the topK nodes instead of all nodes visited. Additionally, the extra method takingint[]
allows native implementations to perform more work per FFM call. example/Grid.java
shows how to use these.
OnDiskGraphIndex
,CachingGraphIndex
, andGraphCache
have moved to the packagejvector.graph.disk
- Writing graphs using the new feature (FusedADC) is performed with
OnDiskGraphIndexWriter
; seeOnDiskGraphIndex.write
for an example of how to use it RandomAccessVectorValues::vectorValue
is deprecated, replaced bygetVector
(which has the same semantics asvectorValue
) andgetVectorInto
. The latter allows JVector to avoid an unnecessary copy when there is a specific destination already created that needs the data.CompressedVectors::approximateScoreFunctionFor
is deprecated, replaced byprecomputedScoreFunctionFor
(which has the same semantics asapproximateScoreFunctionFor
) andscoreFunctionFor
, which does not precompute partial similarities across the codebooks and is more suitable for cases when only a few similarities will be calculated.VectorUtil.divInPlace
is replaced by its inverse,VectorUtil.scale
PoolingSupport
is removed in favor of direct usage ofExplicitThreadLocal
ExplicitThreadLocal
andGraphIndexBuilder
implement AutoCloseable to make it easier to clean up pooled Views
FixedBitSet.nextSetBit
behaves as expected- Removed vestigal references to node level in several places that were left over from old HNSW code
- Centering of binary quantization makes things worse, not better, and has been removed. Saved BQ and BQVectors that have centering data will ignore it on load.
- In-graph deletes are supported through
GraphIndexBuilder.markNodeDeleted
. Deleted nodes are removed whenGraphIndexBuilder.cleanup
is called (which is not threadsafe wrt other concurrent changes). To write a graph with deleted nodes to disk, aMap
must be supplied indicating what ordinals to change the remaining node ids to -- on-disk graphs may not contain "holes" in the ordinal sequence. GraphSearcher.search
now has an experimental overload that takes afloat threshold
parameter that may be used instead of topK; (approximately) all the nodes with simlarities greater than the given threshold will be returned.- Binary Quantization is available as an alternative to Product Quantization. Our tests show that it's primarily suitable for ada002 embedding vectors and loses too much accuracy with smaller embeddings.
GraphIndexBuilder.complete
is nowcleanup
.- The
Bits
parameter toGraphSearcher.search
is no longer nullable; passBits.ALL
instead ofnull
to indicate that all ordinals are acceptable.
NeighborQueue
,NeighborArray
, andNeighborSimilarity
have been renamed toNodeQueue
,NodeArray
, andNodeSimilarity
, respectively.