From 4d8ada510b416c66525144774b843c5130e63c38 Mon Sep 17 00:00:00 2001 From: Dylan Bannon Date: Wed, 20 Mar 2024 12:33:19 -0400 Subject: [PATCH] expose multi-query in StringIndex (#58) * expose multi-query in StringIndex * clang format * PR feedback --- docs/java/allclasses-index.html | 4 +- docs/java/allpackages-index.html | 4 +- .../voyager/jni/Index.QueryResults.html | 4 +- .../spotify/voyager/jni/Index.SpaceType.html | 4 +- .../voyager/jni/Index.StorageDataType.html | 4 +- docs/java/com/spotify/voyager/jni/Index.html | 4 +- .../voyager/jni/StringIndex.QueryResults.html | 4 +- .../com/spotify/voyager/jni/StringIndex.html | 56 ++++++++++++++----- .../jni/class-use/Index.QueryResults.html | 4 +- .../jni/class-use/Index.SpaceType.html | 4 +- .../jni/class-use/Index.StorageDataType.html | 4 +- .../spotify/voyager/jni/class-use/Index.html | 4 +- .../class-use/StringIndex.QueryResults.html | 18 ++++-- .../voyager/jni/class-use/StringIndex.html | 4 +- .../spotify/voyager/jni/package-summary.html | 4 +- .../com/spotify/voyager/jni/package-tree.html | 4 +- .../com/spotify/voyager/jni/package-use.html | 4 +- .../voyager/jni/utils/JniLibExtractor.html | 4 +- .../spotify/voyager/jni/utils/TinyJson.html | 4 +- .../jni/utils/class-use/JniLibExtractor.html | 4 +- .../voyager/jni/utils/class-use/TinyJson.html | 4 +- .../voyager/jni/utils/package-summary.html | 4 +- .../voyager/jni/utils/package-tree.html | 4 +- .../voyager/jni/utils/package-use.html | 4 +- .../com/spotify/voyager/package-summary.html | 4 +- .../com/spotify/voyager/package-tree.html | 4 +- .../java/com/spotify/voyager/package-use.html | 4 +- docs/java/help-doc.html | 4 +- docs/java/index-all.html | 8 ++- docs/java/index.html | 4 +- docs/java/member-search-index.js | 2 +- docs/java/overview-summary.html | 4 +- docs/java/overview-tree.html | 4 +- .../com/spotify/voyager/jni/StringIndex.java | 31 +++++++++- .../spotify/voyager/jni/StringIndexTest.java | 32 +++++++++++ .../com/spotify/voyager/jni/TestUtils.java | 6 +- 36 files changed, 184 insertions(+), 85 deletions(-) diff --git a/docs/java/allclasses-index.html b/docs/java/allclasses-index.html index 5e69bdad..b7aae14f 100644 --- a/docs/java/allclasses-index.html +++ b/docs/java/allclasses-index.html @@ -1,11 +1,11 @@ - + All Classes and Interfaces (voyager 2.0.4 API) - + diff --git a/docs/java/allpackages-index.html b/docs/java/allpackages-index.html index 3f8297b4..524eb92a 100644 --- a/docs/java/allpackages-index.html +++ b/docs/java/allpackages-index.html @@ -1,11 +1,11 @@ - + All Packages (voyager 2.0.4 API) - + diff --git a/docs/java/com/spotify/voyager/jni/Index.QueryResults.html b/docs/java/com/spotify/voyager/jni/Index.QueryResults.html index 9b644a71..de97c7ba 100644 --- a/docs/java/com/spotify/voyager/jni/Index.QueryResults.html +++ b/docs/java/com/spotify/voyager/jni/Index.QueryResults.html @@ -1,11 +1,11 @@ - + Index.QueryResults (voyager 2.0.4 API) - + diff --git a/docs/java/com/spotify/voyager/jni/Index.SpaceType.html b/docs/java/com/spotify/voyager/jni/Index.SpaceType.html index 1bfe990e..1cd61454 100644 --- a/docs/java/com/spotify/voyager/jni/Index.SpaceType.html +++ b/docs/java/com/spotify/voyager/jni/Index.SpaceType.html @@ -1,11 +1,11 @@ - + Index.SpaceType (voyager 2.0.4 API) - + diff --git a/docs/java/com/spotify/voyager/jni/Index.StorageDataType.html b/docs/java/com/spotify/voyager/jni/Index.StorageDataType.html index 8c5907bb..adf2be9b 100644 --- a/docs/java/com/spotify/voyager/jni/Index.StorageDataType.html +++ b/docs/java/com/spotify/voyager/jni/Index.StorageDataType.html @@ -1,11 +1,11 @@ - + Index.StorageDataType (voyager 2.0.4 API) - + diff --git a/docs/java/com/spotify/voyager/jni/Index.html b/docs/java/com/spotify/voyager/jni/Index.html index 94dda8e0..17419e59 100644 --- a/docs/java/com/spotify/voyager/jni/Index.html +++ b/docs/java/com/spotify/voyager/jni/Index.html @@ -1,11 +1,11 @@ - + Index (voyager 2.0.4 API) - + diff --git a/docs/java/com/spotify/voyager/jni/StringIndex.QueryResults.html b/docs/java/com/spotify/voyager/jni/StringIndex.QueryResults.html index b28fa9ee..9ffa4c97 100644 --- a/docs/java/com/spotify/voyager/jni/StringIndex.QueryResults.html +++ b/docs/java/com/spotify/voyager/jni/StringIndex.QueryResults.html @@ -1,11 +1,11 @@ - + StringIndex.QueryResults (voyager 2.0.4 API) - + diff --git a/docs/java/com/spotify/voyager/jni/StringIndex.html b/docs/java/com/spotify/voyager/jni/StringIndex.html index 1f311a23..2b49eb86 100644 --- a/docs/java/com/spotify/voyager/jni/StringIndex.html +++ b/docs/java/com/spotify/voyager/jni/StringIndex.html @@ -1,11 +1,11 @@ - + StringIndex (voyager 2.0.4 API) - + @@ -190,29 +190,37 @@

Method Summary

Load a previously constructed index from the provided file location.
-
StringIndex.QueryResults
-
query(float[] queryVector, + +
query(float[][] queryVectors, int numNeighbors, - int ef)
+ int ef, + int numThreads)
-
Find the nearest neighbors of the provided embedding.
+
Query for against multiple target vectors in parallel.
-
void
-
saveIndex(OutputStream indexOutputStream, - OutputStream namesListOutputStream)
+
StringIndex.QueryResults
+
query(float[] queryVector, + int numNeighbors, + int ef)
-
Save the underlying HNSW index and JSON encoded names list to the provided output streams
+
Find the nearest neighbors of the provided embedding.
void
-
saveIndex(String outputDirectory)
+
saveIndex(OutputStream indexOutputStream, + OutputStream namesListOutputStream)
-
Save the underlying index and JSON encoded name list to the provided output directory
+
Save the underlying HNSW index and JSON encoded names list to the provided output streams
void
-
saveIndex(String outputDirectory, +
saveIndex(String outputDirectory)
+
+
Save the underlying index and JSON encoded name list to the provided output directory
+
+
void
+
saveIndex(String outputDirectory, String indexFilename, String nameListFilename)
-
 
+
 
@@ -457,6 +465,26 @@

query

  • +
    +

    query

    +
    public StringIndex.QueryResults[] query(float[][] queryVectors, + int numNeighbors, + int ef, + int numThreads)
    +
    Query for against multiple target vectors in parallel.
    +
    +
    Parameters:
    +
    queryVectors - Array of query vectors to search around
    +
    numNeighbors - Number of neighbors to get for each target
    +
    ef - Search depth in the graph
    +
    numThreads - Number of threads to use for the underlying index search. -1 uses all + available CPU cores
    +
    Returns:
    +
    Array of QueryResults, one for each target vector
    +
    +
    +
  • +
  • close

    public void close() diff --git a/docs/java/com/spotify/voyager/jni/class-use/Index.QueryResults.html b/docs/java/com/spotify/voyager/jni/class-use/Index.QueryResults.html index bd64d03b..5ed26f31 100644 --- a/docs/java/com/spotify/voyager/jni/class-use/Index.QueryResults.html +++ b/docs/java/com/spotify/voyager/jni/class-use/Index.QueryResults.html @@ -1,11 +1,11 @@ - + Uses of Class com.spotify.voyager.jni.Index.QueryResults (voyager 2.0.4 API) - + diff --git a/docs/java/com/spotify/voyager/jni/class-use/Index.SpaceType.html b/docs/java/com/spotify/voyager/jni/class-use/Index.SpaceType.html index 83a120fc..09e5287e 100644 --- a/docs/java/com/spotify/voyager/jni/class-use/Index.SpaceType.html +++ b/docs/java/com/spotify/voyager/jni/class-use/Index.SpaceType.html @@ -1,11 +1,11 @@ - + Uses of Enum com.spotify.voyager.jni.Index.SpaceType (voyager 2.0.4 API) - + diff --git a/docs/java/com/spotify/voyager/jni/class-use/Index.StorageDataType.html b/docs/java/com/spotify/voyager/jni/class-use/Index.StorageDataType.html index d00adb08..9e013918 100644 --- a/docs/java/com/spotify/voyager/jni/class-use/Index.StorageDataType.html +++ b/docs/java/com/spotify/voyager/jni/class-use/Index.StorageDataType.html @@ -1,11 +1,11 @@ - + Uses of Enum com.spotify.voyager.jni.Index.StorageDataType (voyager 2.0.4 API) - + diff --git a/docs/java/com/spotify/voyager/jni/class-use/Index.html b/docs/java/com/spotify/voyager/jni/class-use/Index.html index 97cab75f..8c85be17 100644 --- a/docs/java/com/spotify/voyager/jni/class-use/Index.html +++ b/docs/java/com/spotify/voyager/jni/class-use/Index.html @@ -1,11 +1,11 @@ - + Uses of Class com.spotify.voyager.jni.Index (voyager 2.0.4 API) - + diff --git a/docs/java/com/spotify/voyager/jni/class-use/StringIndex.QueryResults.html b/docs/java/com/spotify/voyager/jni/class-use/StringIndex.QueryResults.html index 389d8018..823355f8 100644 --- a/docs/java/com/spotify/voyager/jni/class-use/StringIndex.QueryResults.html +++ b/docs/java/com/spotify/voyager/jni/class-use/StringIndex.QueryResults.html @@ -1,11 +1,11 @@ - + Uses of Class com.spotify.voyager.jni.StringIndex.QueryResults (voyager 2.0.4 API) - + @@ -70,11 +70,19 @@

    Uses of Modifier and Type

    Method
    Description
    -
    -
    StringIndex.query(float[] queryVector, + +
    StringIndex.query(float[][] queryVectors, int numNeighbors, - int ef)
    + int ef, + int numThreads)
    +
    Query for against multiple target vectors in parallel.
    +
    + +
    StringIndex.query(float[] queryVector, + int numNeighbors, + int ef)
    +
    Find the nearest neighbors of the provided embedding.
    diff --git a/docs/java/com/spotify/voyager/jni/class-use/StringIndex.html b/docs/java/com/spotify/voyager/jni/class-use/StringIndex.html index 0bb3341f..099dc669 100644 --- a/docs/java/com/spotify/voyager/jni/class-use/StringIndex.html +++ b/docs/java/com/spotify/voyager/jni/class-use/StringIndex.html @@ -1,11 +1,11 @@ - + Uses of Class com.spotify.voyager.jni.StringIndex (voyager 2.0.4 API) - + diff --git a/docs/java/com/spotify/voyager/jni/package-summary.html b/docs/java/com/spotify/voyager/jni/package-summary.html index e8fea423..c190ef10 100644 --- a/docs/java/com/spotify/voyager/jni/package-summary.html +++ b/docs/java/com/spotify/voyager/jni/package-summary.html @@ -1,11 +1,11 @@ - + com.spotify.voyager.jni (voyager 2.0.4 API) - + diff --git a/docs/java/com/spotify/voyager/jni/package-tree.html b/docs/java/com/spotify/voyager/jni/package-tree.html index 400c1cda..da471f0a 100644 --- a/docs/java/com/spotify/voyager/jni/package-tree.html +++ b/docs/java/com/spotify/voyager/jni/package-tree.html @@ -1,11 +1,11 @@ - + com.spotify.voyager.jni Class Hierarchy (voyager 2.0.4 API) - + diff --git a/docs/java/com/spotify/voyager/jni/package-use.html b/docs/java/com/spotify/voyager/jni/package-use.html index 6fd42b41..8bb6054c 100644 --- a/docs/java/com/spotify/voyager/jni/package-use.html +++ b/docs/java/com/spotify/voyager/jni/package-use.html @@ -1,11 +1,11 @@ - + Uses of Package com.spotify.voyager.jni (voyager 2.0.4 API) - + diff --git a/docs/java/com/spotify/voyager/jni/utils/JniLibExtractor.html b/docs/java/com/spotify/voyager/jni/utils/JniLibExtractor.html index 0a0d318f..58a45d33 100644 --- a/docs/java/com/spotify/voyager/jni/utils/JniLibExtractor.html +++ b/docs/java/com/spotify/voyager/jni/utils/JniLibExtractor.html @@ -1,11 +1,11 @@ - + JniLibExtractor (voyager 2.0.4 API) - + diff --git a/docs/java/com/spotify/voyager/jni/utils/TinyJson.html b/docs/java/com/spotify/voyager/jni/utils/TinyJson.html index 3a7bafd0..4be4c790 100644 --- a/docs/java/com/spotify/voyager/jni/utils/TinyJson.html +++ b/docs/java/com/spotify/voyager/jni/utils/TinyJson.html @@ -1,11 +1,11 @@ - + TinyJson (voyager 2.0.4 API) - + diff --git a/docs/java/com/spotify/voyager/jni/utils/class-use/JniLibExtractor.html b/docs/java/com/spotify/voyager/jni/utils/class-use/JniLibExtractor.html index a3d82dbe..e720027a 100644 --- a/docs/java/com/spotify/voyager/jni/utils/class-use/JniLibExtractor.html +++ b/docs/java/com/spotify/voyager/jni/utils/class-use/JniLibExtractor.html @@ -1,11 +1,11 @@ - + Uses of Class com.spotify.voyager.jni.utils.JniLibExtractor (voyager 2.0.4 API) - + diff --git a/docs/java/com/spotify/voyager/jni/utils/class-use/TinyJson.html b/docs/java/com/spotify/voyager/jni/utils/class-use/TinyJson.html index f8708b1c..47e54ab5 100644 --- a/docs/java/com/spotify/voyager/jni/utils/class-use/TinyJson.html +++ b/docs/java/com/spotify/voyager/jni/utils/class-use/TinyJson.html @@ -1,11 +1,11 @@ - + Uses of Class com.spotify.voyager.jni.utils.TinyJson (voyager 2.0.4 API) - + diff --git a/docs/java/com/spotify/voyager/jni/utils/package-summary.html b/docs/java/com/spotify/voyager/jni/utils/package-summary.html index 1902c967..516251b0 100644 --- a/docs/java/com/spotify/voyager/jni/utils/package-summary.html +++ b/docs/java/com/spotify/voyager/jni/utils/package-summary.html @@ -1,11 +1,11 @@ - + com.spotify.voyager.jni.utils (voyager 2.0.4 API) - + diff --git a/docs/java/com/spotify/voyager/jni/utils/package-tree.html b/docs/java/com/spotify/voyager/jni/utils/package-tree.html index f1ef455a..e6a185a8 100644 --- a/docs/java/com/spotify/voyager/jni/utils/package-tree.html +++ b/docs/java/com/spotify/voyager/jni/utils/package-tree.html @@ -1,11 +1,11 @@ - + com.spotify.voyager.jni.utils Class Hierarchy (voyager 2.0.4 API) - + diff --git a/docs/java/com/spotify/voyager/jni/utils/package-use.html b/docs/java/com/spotify/voyager/jni/utils/package-use.html index be4daedf..295f53fe 100644 --- a/docs/java/com/spotify/voyager/jni/utils/package-use.html +++ b/docs/java/com/spotify/voyager/jni/utils/package-use.html @@ -1,11 +1,11 @@ - + Uses of Package com.spotify.voyager.jni.utils (voyager 2.0.4 API) - + diff --git a/docs/java/com/spotify/voyager/package-summary.html b/docs/java/com/spotify/voyager/package-summary.html index 4db475e4..fe2f6768 100644 --- a/docs/java/com/spotify/voyager/package-summary.html +++ b/docs/java/com/spotify/voyager/package-summary.html @@ -1,11 +1,11 @@ - + com.spotify.voyager (voyager 2.0.4 API) - + diff --git a/docs/java/com/spotify/voyager/package-tree.html b/docs/java/com/spotify/voyager/package-tree.html index 4b97bc8c..6d8e65be 100644 --- a/docs/java/com/spotify/voyager/package-tree.html +++ b/docs/java/com/spotify/voyager/package-tree.html @@ -1,11 +1,11 @@ - + com.spotify.voyager Class Hierarchy (voyager 2.0.4 API) - + diff --git a/docs/java/com/spotify/voyager/package-use.html b/docs/java/com/spotify/voyager/package-use.html index f2f174e9..40c33742 100644 --- a/docs/java/com/spotify/voyager/package-use.html +++ b/docs/java/com/spotify/voyager/package-use.html @@ -1,11 +1,11 @@ - + Uses of Package com.spotify.voyager (voyager 2.0.4 API) - + diff --git a/docs/java/help-doc.html b/docs/java/help-doc.html index 24648553..8f0bfaeb 100644 --- a/docs/java/help-doc.html +++ b/docs/java/help-doc.html @@ -1,11 +1,11 @@ - + API Help (voyager 2.0.4 API) - + diff --git a/docs/java/index-all.html b/docs/java/index-all.html index ef2d63de..d5a22edb 100644 --- a/docs/java/index-all.html +++ b/docs/java/index-all.html @@ -1,11 +1,11 @@ - + Index (voyager 2.0.4 API) - + @@ -298,6 +298,10 @@

    Q

    Query this Index for approximate nearest neighbors of multiple query vectors.
    +
    query(float[][], int, int, int) - Method in class com.spotify.voyager.jni.StringIndex
    +
    +
    Query for against multiple target vectors in parallel.
    +
    query(float[][], int, int, long) - Method in class com.spotify.voyager.jni.Index
    Query this Index for approximate nearest neighbors of multiple query vectors.
    diff --git a/docs/java/index.html b/docs/java/index.html index 241f7931..337b12e5 100644 --- a/docs/java/index.html +++ b/docs/java/index.html @@ -1,11 +1,11 @@ - + Overview (voyager 2.0.4 API) - + diff --git a/docs/java/member-search-index.js b/docs/java/member-search-index.js index 2499c325..f822635c 100644 --- a/docs/java/member-search-index.js +++ b/docs/java/member-search-index.js @@ -1 +1 @@ -memberSearchIndex = [{"p":"com.spotify.voyager.jni","c":"Index","l":"addItem(float[])"},{"p":"com.spotify.voyager.jni","c":"Index","l":"addItem(float[], long)","u":"addItem(float[],long)"},{"p":"com.spotify.voyager.jni","c":"StringIndex","l":"addItem(String, float[])","u":"addItem(java.lang.String,float[])"},{"p":"com.spotify.voyager.jni","c":"StringIndex","l":"addItem(String, List)","u":"addItem(java.lang.String,java.util.List)"},{"p":"com.spotify.voyager.jni","c":"Index","l":"addItems(float[][], int)","u":"addItems(float[][],int)"},{"p":"com.spotify.voyager.jni","c":"Index","l":"addItems(float[][], long[], int)","u":"addItems(float[][],long[],int)"},{"p":"com.spotify.voyager.jni","c":"StringIndex","l":"addItems(Map>)","u":"addItems(java.util.Map)"},{"p":"com.spotify.voyager.jni","c":"Index","l":"close()"},{"p":"com.spotify.voyager.jni","c":"StringIndex","l":"close()"},{"p":"com.spotify.voyager.jni","c":"Index.SpaceType","l":"Cosine"},{"p":"com.spotify.voyager.jni","c":"Index.QueryResults","l":"distances"},{"p":"com.spotify.voyager.jni","c":"Index.StorageDataType","l":"E4M3"},{"p":"com.spotify.voyager.jni","c":"Index.SpaceType","l":"Euclidean"},{"p":"com.spotify.voyager.jni.utils","c":"JniLibExtractor","l":"extractBinaries(String)","u":"extractBinaries(java.lang.String)"},{"p":"com.spotify.voyager.jni","c":"Index","l":"finalize()"},{"p":"com.spotify.voyager.jni","c":"Index.StorageDataType","l":"Float32"},{"p":"com.spotify.voyager.jni","c":"Index.StorageDataType","l":"Float8"},{"p":"com.spotify.voyager.jni","c":"StringIndex.QueryResults","l":"getDistance(int)"},{"p":"com.spotify.voyager.jni","c":"Index.QueryResults","l":"getDistances()"},{"p":"com.spotify.voyager.jni","c":"StringIndex.QueryResults","l":"getDistances()"},{"p":"com.spotify.voyager.jni","c":"Index","l":"getEf()"},{"p":"com.spotify.voyager.jni","c":"Index","l":"getEfConstruction()"},{"p":"com.spotify.voyager.jni","c":"Index","l":"getIDs()"},{"p":"com.spotify.voyager.jni","c":"Index.QueryResults","l":"getLabels()"},{"p":"com.spotify.voyager.jni","c":"Index","l":"getM()"},{"p":"com.spotify.voyager.jni","c":"Index","l":"getMaxElements()"},{"p":"com.spotify.voyager.jni","c":"StringIndex.QueryResults","l":"getName(int)"},{"p":"com.spotify.voyager.jni","c":"StringIndex.QueryResults","l":"getNames()"},{"p":"com.spotify.voyager.jni","c":"Index","l":"getNumDimensions()"},{"p":"com.spotify.voyager.jni","c":"Index","l":"getNumElements()"},{"p":"com.spotify.voyager.jni","c":"StringIndex.QueryResults","l":"getNumResults()"},{"p":"com.spotify.voyager.jni","c":"Index","l":"getNumThreads()"},{"p":"com.spotify.voyager.jni","c":"Index","l":"getSpace()"},{"p":"com.spotify.voyager.jni","c":"Index","l":"getVector(long)"},{"p":"com.spotify.voyager.jni","c":"Index","l":"getVectors(long[])"},{"p":"com.spotify.voyager.jni","c":"Index","l":"Index(Index.SpaceType, int)","u":"%3Cinit%3E(com.spotify.voyager.jni.Index.SpaceType,int)"},{"p":"com.spotify.voyager.jni","c":"Index","l":"Index(Index.SpaceType, int, long, long, long, long, Index.StorageDataType)","u":"%3Cinit%3E(com.spotify.voyager.jni.Index.SpaceType,int,long,long,long,long,com.spotify.voyager.jni.Index.StorageDataType)"},{"p":"com.spotify.voyager.jni","c":"Index.SpaceType","l":"InnerProduct"},{"p":"com.spotify.voyager.jni.utils","c":"JniLibExtractor","l":"JniLibExtractor()","u":"%3Cinit%3E()"},{"p":"com.spotify.voyager.jni","c":"Index.QueryResults","l":"labels"},{"p":"com.spotify.voyager.jni","c":"Index","l":"load(InputStream)","u":"load(java.io.InputStream)"},{"p":"com.spotify.voyager.jni","c":"Index","l":"load(InputStream, Index.SpaceType, int, Index.StorageDataType)","u":"load(java.io.InputStream,com.spotify.voyager.jni.Index.SpaceType,int,com.spotify.voyager.jni.Index.StorageDataType)"},{"p":"com.spotify.voyager.jni","c":"StringIndex","l":"load(InputStream, InputStream)","u":"load(java.io.InputStream,java.io.InputStream)"},{"p":"com.spotify.voyager.jni","c":"StringIndex","l":"load(InputStream, InputStream, Index.SpaceType, int, Index.StorageDataType)","u":"load(java.io.InputStream,java.io.InputStream,com.spotify.voyager.jni.Index.SpaceType,int,com.spotify.voyager.jni.Index.StorageDataType)"},{"p":"com.spotify.voyager.jni","c":"Index","l":"load(String)","u":"load(java.lang.String)"},{"p":"com.spotify.voyager.jni","c":"Index","l":"load(String, Index.SpaceType, int, Index.StorageDataType)","u":"load(java.lang.String,com.spotify.voyager.jni.Index.SpaceType,int,com.spotify.voyager.jni.Index.StorageDataType)"},{"p":"com.spotify.voyager.jni","c":"StringIndex","l":"load(String, String)","u":"load(java.lang.String,java.lang.String)"},{"p":"com.spotify.voyager.jni","c":"StringIndex","l":"load(String, String, Index.SpaceType, int, Index.StorageDataType)","u":"load(java.lang.String,java.lang.String,com.spotify.voyager.jni.Index.SpaceType,int,com.spotify.voyager.jni.Index.StorageDataType)"},{"p":"com.spotify.voyager.jni","c":"Index","l":"markDeleted(long)"},{"p":"com.spotify.voyager.jni","c":"Index","l":"query(float[], int)","u":"query(float[],int)"},{"p":"com.spotify.voyager.jni","c":"StringIndex","l":"query(float[], int, int)","u":"query(float[],int,int)"},{"p":"com.spotify.voyager.jni","c":"Index","l":"query(float[], int, long)","u":"query(float[],int,long)"},{"p":"com.spotify.voyager.jni","c":"Index","l":"query(float[][], int, int)","u":"query(float[][],int,int)"},{"p":"com.spotify.voyager.jni","c":"Index","l":"query(float[][], int, int, long)","u":"query(float[][],int,int,long)"},{"p":"com.spotify.voyager.jni","c":"Index.QueryResults","l":"QueryResults(long[], float[])","u":"%3Cinit%3E(long[],float[])"},{"p":"com.spotify.voyager.jni","c":"StringIndex.QueryResults","l":"QueryResults(String[], float[])","u":"%3Cinit%3E(java.lang.String[],float[])"},{"p":"com.spotify.voyager.jni.utils","c":"TinyJson","l":"readStringList(InputStream)","u":"readStringList(java.io.InputStream)"},{"p":"com.spotify.voyager.jni","c":"Index","l":"resizeIndex(long)"},{"p":"com.spotify.voyager.jni","c":"Index","l":"saveIndex(OutputStream)","u":"saveIndex(java.io.OutputStream)"},{"p":"com.spotify.voyager.jni","c":"StringIndex","l":"saveIndex(OutputStream, OutputStream)","u":"saveIndex(java.io.OutputStream,java.io.OutputStream)"},{"p":"com.spotify.voyager.jni","c":"Index","l":"saveIndex(String)","u":"saveIndex(java.lang.String)"},{"p":"com.spotify.voyager.jni","c":"StringIndex","l":"saveIndex(String)","u":"saveIndex(java.lang.String)"},{"p":"com.spotify.voyager.jni","c":"StringIndex","l":"saveIndex(String, String, String)","u":"saveIndex(java.lang.String,java.lang.String,java.lang.String)"},{"p":"com.spotify.voyager.jni","c":"Index","l":"setEf(long)"},{"p":"com.spotify.voyager.jni","c":"Index","l":"setNumThreads(int)"},{"p":"com.spotify.voyager.jni","c":"StringIndex","l":"StringIndex(Index.SpaceType, int)","u":"%3Cinit%3E(com.spotify.voyager.jni.Index.SpaceType,int)"},{"p":"com.spotify.voyager.jni","c":"StringIndex","l":"StringIndex(Index.SpaceType, int, long, long, long, long, Index.StorageDataType)","u":"%3Cinit%3E(com.spotify.voyager.jni.Index.SpaceType,int,long,long,long,long,com.spotify.voyager.jni.Index.StorageDataType)"},{"p":"com.spotify.voyager.jni.utils","c":"TinyJson","l":"TinyJson()","u":"%3Cinit%3E()"},{"p":"com.spotify.voyager.jni","c":"Index.QueryResults","l":"toString()"},{"p":"com.spotify.voyager.jni","c":"StringIndex.QueryResults","l":"toString()"},{"p":"com.spotify.voyager.jni","c":"Index","l":"unmarkDeleted(long)"},{"p":"com.spotify.voyager.jni","c":"Index.SpaceType","l":"valueOf(String)","u":"valueOf(java.lang.String)"},{"p":"com.spotify.voyager.jni","c":"Index.StorageDataType","l":"valueOf(String)","u":"valueOf(java.lang.String)"},{"p":"com.spotify.voyager.jni","c":"Index.SpaceType","l":"values()"},{"p":"com.spotify.voyager.jni","c":"Index.StorageDataType","l":"values()"},{"p":"com.spotify.voyager.jni.utils","c":"TinyJson","l":"writeStringList(Iterable, OutputStream)","u":"writeStringList(java.lang.Iterable,java.io.OutputStream)"}];updateSearchResults(); \ No newline at end of file +memberSearchIndex = [{"p":"com.spotify.voyager.jni","c":"Index","l":"addItem(float[])"},{"p":"com.spotify.voyager.jni","c":"Index","l":"addItem(float[], long)","u":"addItem(float[],long)"},{"p":"com.spotify.voyager.jni","c":"StringIndex","l":"addItem(String, float[])","u":"addItem(java.lang.String,float[])"},{"p":"com.spotify.voyager.jni","c":"StringIndex","l":"addItem(String, List)","u":"addItem(java.lang.String,java.util.List)"},{"p":"com.spotify.voyager.jni","c":"Index","l":"addItems(float[][], int)","u":"addItems(float[][],int)"},{"p":"com.spotify.voyager.jni","c":"Index","l":"addItems(float[][], long[], int)","u":"addItems(float[][],long[],int)"},{"p":"com.spotify.voyager.jni","c":"StringIndex","l":"addItems(Map>)","u":"addItems(java.util.Map)"},{"p":"com.spotify.voyager.jni","c":"Index","l":"close()"},{"p":"com.spotify.voyager.jni","c":"StringIndex","l":"close()"},{"p":"com.spotify.voyager.jni","c":"Index.SpaceType","l":"Cosine"},{"p":"com.spotify.voyager.jni","c":"Index.QueryResults","l":"distances"},{"p":"com.spotify.voyager.jni","c":"Index.StorageDataType","l":"E4M3"},{"p":"com.spotify.voyager.jni","c":"Index.SpaceType","l":"Euclidean"},{"p":"com.spotify.voyager.jni.utils","c":"JniLibExtractor","l":"extractBinaries(String)","u":"extractBinaries(java.lang.String)"},{"p":"com.spotify.voyager.jni","c":"Index","l":"finalize()"},{"p":"com.spotify.voyager.jni","c":"Index.StorageDataType","l":"Float32"},{"p":"com.spotify.voyager.jni","c":"Index.StorageDataType","l":"Float8"},{"p":"com.spotify.voyager.jni","c":"StringIndex.QueryResults","l":"getDistance(int)"},{"p":"com.spotify.voyager.jni","c":"Index.QueryResults","l":"getDistances()"},{"p":"com.spotify.voyager.jni","c":"StringIndex.QueryResults","l":"getDistances()"},{"p":"com.spotify.voyager.jni","c":"Index","l":"getEf()"},{"p":"com.spotify.voyager.jni","c":"Index","l":"getEfConstruction()"},{"p":"com.spotify.voyager.jni","c":"Index","l":"getIDs()"},{"p":"com.spotify.voyager.jni","c":"Index.QueryResults","l":"getLabels()"},{"p":"com.spotify.voyager.jni","c":"Index","l":"getM()"},{"p":"com.spotify.voyager.jni","c":"Index","l":"getMaxElements()"},{"p":"com.spotify.voyager.jni","c":"StringIndex.QueryResults","l":"getName(int)"},{"p":"com.spotify.voyager.jni","c":"StringIndex.QueryResults","l":"getNames()"},{"p":"com.spotify.voyager.jni","c":"Index","l":"getNumDimensions()"},{"p":"com.spotify.voyager.jni","c":"Index","l":"getNumElements()"},{"p":"com.spotify.voyager.jni","c":"StringIndex.QueryResults","l":"getNumResults()"},{"p":"com.spotify.voyager.jni","c":"Index","l":"getNumThreads()"},{"p":"com.spotify.voyager.jni","c":"Index","l":"getSpace()"},{"p":"com.spotify.voyager.jni","c":"Index","l":"getVector(long)"},{"p":"com.spotify.voyager.jni","c":"Index","l":"getVectors(long[])"},{"p":"com.spotify.voyager.jni","c":"Index","l":"Index(Index.SpaceType, int)","u":"%3Cinit%3E(com.spotify.voyager.jni.Index.SpaceType,int)"},{"p":"com.spotify.voyager.jni","c":"Index","l":"Index(Index.SpaceType, int, long, long, long, long, Index.StorageDataType)","u":"%3Cinit%3E(com.spotify.voyager.jni.Index.SpaceType,int,long,long,long,long,com.spotify.voyager.jni.Index.StorageDataType)"},{"p":"com.spotify.voyager.jni","c":"Index.SpaceType","l":"InnerProduct"},{"p":"com.spotify.voyager.jni.utils","c":"JniLibExtractor","l":"JniLibExtractor()","u":"%3Cinit%3E()"},{"p":"com.spotify.voyager.jni","c":"Index.QueryResults","l":"labels"},{"p":"com.spotify.voyager.jni","c":"Index","l":"load(InputStream)","u":"load(java.io.InputStream)"},{"p":"com.spotify.voyager.jni","c":"Index","l":"load(InputStream, Index.SpaceType, int, Index.StorageDataType)","u":"load(java.io.InputStream,com.spotify.voyager.jni.Index.SpaceType,int,com.spotify.voyager.jni.Index.StorageDataType)"},{"p":"com.spotify.voyager.jni","c":"StringIndex","l":"load(InputStream, InputStream)","u":"load(java.io.InputStream,java.io.InputStream)"},{"p":"com.spotify.voyager.jni","c":"StringIndex","l":"load(InputStream, InputStream, Index.SpaceType, int, Index.StorageDataType)","u":"load(java.io.InputStream,java.io.InputStream,com.spotify.voyager.jni.Index.SpaceType,int,com.spotify.voyager.jni.Index.StorageDataType)"},{"p":"com.spotify.voyager.jni","c":"Index","l":"load(String)","u":"load(java.lang.String)"},{"p":"com.spotify.voyager.jni","c":"Index","l":"load(String, Index.SpaceType, int, Index.StorageDataType)","u":"load(java.lang.String,com.spotify.voyager.jni.Index.SpaceType,int,com.spotify.voyager.jni.Index.StorageDataType)"},{"p":"com.spotify.voyager.jni","c":"StringIndex","l":"load(String, String)","u":"load(java.lang.String,java.lang.String)"},{"p":"com.spotify.voyager.jni","c":"StringIndex","l":"load(String, String, Index.SpaceType, int, Index.StorageDataType)","u":"load(java.lang.String,java.lang.String,com.spotify.voyager.jni.Index.SpaceType,int,com.spotify.voyager.jni.Index.StorageDataType)"},{"p":"com.spotify.voyager.jni","c":"Index","l":"markDeleted(long)"},{"p":"com.spotify.voyager.jni","c":"Index","l":"query(float[], int)","u":"query(float[],int)"},{"p":"com.spotify.voyager.jni","c":"StringIndex","l":"query(float[], int, int)","u":"query(float[],int,int)"},{"p":"com.spotify.voyager.jni","c":"Index","l":"query(float[], int, long)","u":"query(float[],int,long)"},{"p":"com.spotify.voyager.jni","c":"Index","l":"query(float[][], int, int)","u":"query(float[][],int,int)"},{"p":"com.spotify.voyager.jni","c":"StringIndex","l":"query(float[][], int, int, int)","u":"query(float[][],int,int,int)"},{"p":"com.spotify.voyager.jni","c":"Index","l":"query(float[][], int, int, long)","u":"query(float[][],int,int,long)"},{"p":"com.spotify.voyager.jni","c":"Index.QueryResults","l":"QueryResults(long[], float[])","u":"%3Cinit%3E(long[],float[])"},{"p":"com.spotify.voyager.jni","c":"StringIndex.QueryResults","l":"QueryResults(String[], float[])","u":"%3Cinit%3E(java.lang.String[],float[])"},{"p":"com.spotify.voyager.jni.utils","c":"TinyJson","l":"readStringList(InputStream)","u":"readStringList(java.io.InputStream)"},{"p":"com.spotify.voyager.jni","c":"Index","l":"resizeIndex(long)"},{"p":"com.spotify.voyager.jni","c":"Index","l":"saveIndex(OutputStream)","u":"saveIndex(java.io.OutputStream)"},{"p":"com.spotify.voyager.jni","c":"StringIndex","l":"saveIndex(OutputStream, OutputStream)","u":"saveIndex(java.io.OutputStream,java.io.OutputStream)"},{"p":"com.spotify.voyager.jni","c":"Index","l":"saveIndex(String)","u":"saveIndex(java.lang.String)"},{"p":"com.spotify.voyager.jni","c":"StringIndex","l":"saveIndex(String)","u":"saveIndex(java.lang.String)"},{"p":"com.spotify.voyager.jni","c":"StringIndex","l":"saveIndex(String, String, String)","u":"saveIndex(java.lang.String,java.lang.String,java.lang.String)"},{"p":"com.spotify.voyager.jni","c":"Index","l":"setEf(long)"},{"p":"com.spotify.voyager.jni","c":"Index","l":"setNumThreads(int)"},{"p":"com.spotify.voyager.jni","c":"StringIndex","l":"StringIndex(Index.SpaceType, int)","u":"%3Cinit%3E(com.spotify.voyager.jni.Index.SpaceType,int)"},{"p":"com.spotify.voyager.jni","c":"StringIndex","l":"StringIndex(Index.SpaceType, int, long, long, long, long, Index.StorageDataType)","u":"%3Cinit%3E(com.spotify.voyager.jni.Index.SpaceType,int,long,long,long,long,com.spotify.voyager.jni.Index.StorageDataType)"},{"p":"com.spotify.voyager.jni.utils","c":"TinyJson","l":"TinyJson()","u":"%3Cinit%3E()"},{"p":"com.spotify.voyager.jni","c":"Index.QueryResults","l":"toString()"},{"p":"com.spotify.voyager.jni","c":"StringIndex.QueryResults","l":"toString()"},{"p":"com.spotify.voyager.jni","c":"Index","l":"unmarkDeleted(long)"},{"p":"com.spotify.voyager.jni","c":"Index.SpaceType","l":"valueOf(String)","u":"valueOf(java.lang.String)"},{"p":"com.spotify.voyager.jni","c":"Index.StorageDataType","l":"valueOf(String)","u":"valueOf(java.lang.String)"},{"p":"com.spotify.voyager.jni","c":"Index.SpaceType","l":"values()"},{"p":"com.spotify.voyager.jni","c":"Index.StorageDataType","l":"values()"},{"p":"com.spotify.voyager.jni.utils","c":"TinyJson","l":"writeStringList(Iterable, OutputStream)","u":"writeStringList(java.lang.Iterable,java.io.OutputStream)"}];updateSearchResults(); \ No newline at end of file diff --git a/docs/java/overview-summary.html b/docs/java/overview-summary.html index e923a8d4..eff9184d 100644 --- a/docs/java/overview-summary.html +++ b/docs/java/overview-summary.html @@ -1,11 +1,11 @@ - + voyager 2.0.4 API - + diff --git a/docs/java/overview-tree.html b/docs/java/overview-tree.html index 10d5a7c8..bec3f9ec 100644 --- a/docs/java/overview-tree.html +++ b/docs/java/overview-tree.html @@ -1,11 +1,11 @@ - + Class Hierarchy (voyager 2.0.4 API) - + diff --git a/java/src/main/java/com/spotify/voyager/jni/StringIndex.java b/java/src/main/java/com/spotify/voyager/jni/StringIndex.java index 4f783707..d303e1ce 100644 --- a/java/src/main/java/com/spotify/voyager/jni/StringIndex.java +++ b/java/src/main/java/com/spotify/voyager/jni/StringIndex.java @@ -307,9 +307,34 @@ private void assignPrimitive(List vector, float[] target) { * distance from the query vector, sorted in ascending order of distance */ public QueryResults query(float[] queryVector, int numNeighbors, int ef) { - String[] resultNames = new String[numNeighbors]; - float[] distances = new float[numNeighbors]; - Index.QueryResults idxResults = index.query(queryVector, numNeighbors, ef); + return convertResult(index.query(queryVector, numNeighbors, ef)); + } + + /** + * Query for multiple target vectors in parallel. + * + * @param queryVectors Array of query vectors to search around + * @param numNeighbors Number of neighbors to get for each target + * @param numThreads Number of threads to use for the underlying index search. -1 uses all + * available CPU cores + * @param ef Search depth in the graph + * @return Array of QueryResults, one for each target vector + */ + public QueryResults[] query(float[][] queryVectors, int numNeighbors, int numThreads, int ef) { + QueryResults[] results = new QueryResults[queryVectors.length]; + Index.QueryResults[] idxResults = index.query(queryVectors, numNeighbors, numThreads, ef); + for (int i = 0; i < idxResults.length; i++) { + results[i] = this.convertResult(idxResults[i]); + } + + return results; + } + + private QueryResults convertResult(Index.QueryResults idxResults) { + int numResults = idxResults.distances.length; + String[] resultNames = new String[numResults]; + float[] distances = new float[numResults]; + for (int i = 0; i < idxResults.getLabels().length; i++) { long indexId = idxResults.getLabels()[i]; float dist = idxResults.getDistances()[i]; diff --git a/java/src/test/java/com/spotify/voyager/jni/StringIndexTest.java b/java/src/test/java/com/spotify/voyager/jni/StringIndexTest.java index 5f2b49bb..1823697c 100644 --- a/java/src/test/java/com/spotify/voyager/jni/StringIndexTest.java +++ b/java/src/test/java/com/spotify/voyager/jni/StringIndexTest.java @@ -31,8 +31,10 @@ import java.nio.file.Files; import java.nio.file.Paths; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import java.util.Map; +import java.util.Random; import java.util.function.Function; import java.util.stream.Collectors; import org.apache.commons.io.FileUtils; @@ -79,6 +81,36 @@ public void itFindsNeighbors() throws Exception { } } + @Test + public void itFindsNeighborsMultipleTargets() throws Exception { + List testVectors = TestUtils.getTestVectors(); + int numDimensions = testVectors.get(0).vector.length; + try (final StringIndex index = + new StringIndex( + SpaceType.Cosine, + numDimensions, + 20, + testVectors.size(), + 0, + testVectors.size(), + StorageDataType.E4M3)) { + for (Vector v : testVectors) { + index.addItem(v.name, v.vector); + } + + float[][] targetVectors = TestUtils.randomVectors(() -> new Random(0), 2, numDimensions); + + List> results = + Arrays.stream(index.query(targetVectors, 2, 1, testVectors.size())) + .map(RESULT_MAPPER) + .collect(Collectors.toList()); + + assertThat(results.stream().flatMap(List::stream)) + .extracting(CustomResult::getName) + .containsExactly("my-vector-59", "my-vector-58", "my-vector-59", "my-vector-58"); + } + } + @Test public void itAddsItemsInBatch() throws Exception { List testVectors = TestUtils.getTestVectors(); diff --git a/java/src/test/java/com/spotify/voyager/jni/TestUtils.java b/java/src/test/java/com/spotify/voyager/jni/TestUtils.java index 00d666bd..29adf78b 100644 --- a/java/src/test/java/com/spotify/voyager/jni/TestUtils.java +++ b/java/src/test/java/com/spotify/voyager/jni/TestUtils.java @@ -27,6 +27,7 @@ import java.util.Arrays; import java.util.List; import java.util.Random; +import java.util.function.Supplier; public class TestUtils { private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper(); @@ -74,12 +75,13 @@ public static float[] randomVector(int numDimensions) { * @return an array of float arrays, with numElements as the first dimension, and numDimensions as * the second. */ - public static float[][] randomVectors(int numElements, int numDimensions) { + public static float[][] randomVectors( + Supplier randomSupplier, int numElements, int numDimensions) { float[][] vectors = new float[numElements][numDimensions]; for (int i = 0; i < numElements; i++) { for (int j = 0; j < numDimensions; j++) { - vectors[i][j] = random.nextFloat() * 2 - 1; + vectors[i][j] = randomSupplier.get().nextFloat() * 2 - 1; } }