Skip to content

Commit 6a0afa2

Browse files
ldematteChrisHegarty
authored andcommitted
Add FlatFieldVectorsWriter#asKnnVectorValues (#16062)
FlatFieldVectorsWriter<T> exposes its accumulated vectors via List<T> getVectors(). This is both too generic and too prescriptive: List<T> binds the return type to specific vector representation (T = float[] / byte[] heap arrays, one vector per list element); if a FlatFieldVectorsWriter implementation is backed by a different data structure (off-heap / paged / memory-mapped storage), it has to materialize a heap array even when the downstream consumer would be happy with a non-materialized view. it does not carry enough information with it (e.g. encoding, dimensions for sub-byte packed types, etc.). In fact, current consumes have to wrap that list into a KnnVectorValues to feed the scoring / graph-building path (see e.g. Lucene99HnswVectorsWriter.FieldWriter). This PR proposes to move this step directly to FlatFieldVectorsWriter<T>, exposing its vectors also as KnnVectorValues. Why KnnVectorValues? KnnVectorValues is the shape current callers (e.g. scorers) actually use. This PR updates Lucene99HnswVectorsWriter to use the new function when it calls FlatVectorsScorer.getRandomVectorScorerSupplier, which already takes KnnVectorValues. No new Lucene type is needed; an alternative would be to introduce a new Lucene interface (e.g. FlatVectorsView). That would be very similar to KnnVectorValues with minor variations.
1 parent ef272d0 commit 6a0afa2

3 files changed

Lines changed: 30 additions & 16 deletions

File tree

lucene/CHANGES.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,9 @@ API Changes
3131

3232
* GITHUB#15990: Add experimental api to IndexWriter for columnar indexing. (Tim Brooks)
3333

34+
* GITHUB#16062: Add FlatFieldVectorsWriter.asKnnVectorValues to return directly a KnnVectorValues "view" over
35+
vectors to be written. (Lorenzo Dematte)
36+
3437
New Features
3538
---------------------
3639

lucene/core/src/java/org/apache/lucene/codecs/hnsw/FlatFieldVectorsWriter.java

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,11 @@
2020
import java.io.IOException;
2121
import java.util.List;
2222
import org.apache.lucene.codecs.KnnFieldVectorsWriter;
23+
import org.apache.lucene.index.ByteVectorValues;
2324
import org.apache.lucene.index.DocsWithFieldSet;
25+
import org.apache.lucene.index.FloatVectorValues;
26+
import org.apache.lucene.index.KnnVectorValues;
27+
import org.apache.lucene.index.VectorEncoding;
2428

2529
/**
2630
* Vectors' writer for a field
@@ -34,6 +38,25 @@ public abstract class FlatFieldVectorsWriter<T> extends KnnFieldVectorsWriter<T>
3438
*/
3539
public abstract List<T> getVectors();
3640

41+
/**
42+
* Returns a {@link KnnVectorValues} view over the vectors to be written.
43+
*
44+
* <p>This default implementation uses {@link #getVectors()} and wraps them via {@link
45+
* FloatVectorValues#fromFloats} / {@link ByteVectorValues#fromBytes}. Subclasses backed by
46+
* alternative storage may override to return a richer view (e.g. one that exposes capability
47+
* information to scorers, or avoids heap materialization).
48+
*
49+
* @param encoding the vector encoding/element type
50+
* @param dim the field's declared vector dimension
51+
*/
52+
@SuppressWarnings("unchecked")
53+
public KnnVectorValues asKnnVectorValues(VectorEncoding encoding, int dim) throws IOException {
54+
return switch (encoding) {
55+
case FLOAT32 -> FloatVectorValues.fromFloats((List<float[]>) getVectors(), dim);
56+
case BYTE -> ByteVectorValues.fromBytes((List<byte[]>) getVectors(), dim);
57+
};
58+
}
59+
3760
/**
3861
* @return the docsWithFieldSet for the field writer
3962
*/

lucene/core/src/java/org/apache/lucene/codecs/lucene99/Lucene99HnswVectorsWriter.java

Lines changed: 4 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -38,10 +38,8 @@
3838
import org.apache.lucene.codecs.hnsw.FlatVectorsReader;
3939
import org.apache.lucene.codecs.hnsw.FlatVectorsScorer;
4040
import org.apache.lucene.codecs.hnsw.FlatVectorsWriter;
41-
import org.apache.lucene.index.ByteVectorValues;
4241
import org.apache.lucene.index.DocsWithFieldSet;
4342
import org.apache.lucene.index.FieldInfo;
44-
import org.apache.lucene.index.FloatVectorValues;
4543
import org.apache.lucene.index.IndexFileNames;
4644
import org.apache.lucene.index.KnnVectorValues;
4745
import org.apache.lucene.index.MergeState;
@@ -739,20 +737,10 @@ static FieldWriter<?> create(
739737
this.flatFieldVectorsWriter = Objects.requireNonNull(flatFieldVectorsWriter);
740738
this.graphThreshold = tinySegmentsThreshold;
741739
this.scorerSupplier =
742-
switch (fieldInfo.getVectorEncoding()) {
743-
case BYTE ->
744-
scorer.getRandomVectorScorerSupplier(
745-
fieldInfo.getVectorSimilarityFunction(),
746-
ByteVectorValues.fromBytes(
747-
(List<byte[]>) flatFieldVectorsWriter.getVectors(),
748-
fieldInfo.getVectorDimension()));
749-
case FLOAT32 ->
750-
scorer.getRandomVectorScorerSupplier(
751-
fieldInfo.getVectorSimilarityFunction(),
752-
FloatVectorValues.fromFloats(
753-
(List<float[]>) flatFieldVectorsWriter.getVectors(),
754-
fieldInfo.getVectorDimension()));
755-
};
740+
scorer.getRandomVectorScorerSupplier(
741+
fieldInfo.getVectorSimilarityFunction(),
742+
flatFieldVectorsWriter.asKnnVectorValues(
743+
fieldInfo.getVectorEncoding(), fieldInfo.getVectorDimension()));
756744

757745
if (graphThreshold <= 0) {
758746
// Initialize graph builder if optimization is disabled

0 commit comments

Comments
 (0)