Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
ff9949f
Add GPU-optimized multi-segment CAGRA search in GPUKnnFloatVectorQuery
jamxia155 Mar 31, 2026
bdb8e66
Enable async memory resource and fix query vector upload in GPU search
jamxia155 Apr 2, 2026
7a8b26b
Expose CAGRA SearchAlgo parameter
jamxia155 Apr 13, 2026
aeda8bf
Add persistent kernel support and fix runner hash stability
jamxia155 Apr 13, 2026
2521261
Remove persistent kernel support; add workspace pool configuration
jamxia155 Apr 16, 2026
19773fa
Merge remote-tracking branch 'origin/main' into multi-segment-cagra-s…
jamxia155 May 9, 2026
9abe58a
Modify example to demo prefilter.
narangvivek10 May 6, 2026
92f4f3f
Enable GPU multi-segment search with explicit Lucene filter queries
jamxia155 May 16, 2026
c49a1a0
Adapt GPU search path to merged multi-partition cuVS API
jamxia155 May 21, 2026
7f394de
Allow rewrite() to use multi-partition path for k beyond 1024
jamxia155 May 30, 2026
1b0355a
Revert "Allow rewrite() to use multi-partition path for k beyond 1024"
jamxia155 Jun 1, 2026
05d61b4
Remove computeMaxIterations from GPUKnnFloatVectorQuery
jamxia155 Jun 1, 2026
2160b63
Drop k>1024 gate from GPUKnnFloatVectorQuery.rewrite()
jamxia155 Jun 2, 2026
32e07bf
Merge remote-tracking branch 'origin/main' into multi-segment-cagra-s…
jamxia155 Jun 10, 2026
51e03b1
Updates to pom to buidl snapshot
jolorunyomi Jun 25, 2026
7f99c97
Bump cuvs-lucene to 26.08.0-SNAPSHOT
jamxia155 Jun 26, 2026
f6a5542
Adapt to multi-partition CAGRA Java API refactor
jamxia155 Jun 30, 2026
c840848
Merge remote-tracking branch 'origin/main' into multi-segment-cagra-s…
jamxia155 Jun 30, 2026
91684e8
Fix duplicate <repositories> tag in pom.xml
jamxia155 Jul 1, 2026
bdf69dd
Expose CAGRA max_iterations as a configurable search setting
jamxia155 Jul 1, 2026
62f6302
Remove unnecessary formatting updates
jamxia155 Jul 1, 2026
480ae28
Adapt multi-partition filter to the offset-free cuVS API
jamxia155 Jul 3, 2026
672e03f
Stash FloatVectorValues per segment in multi-segment result mapping
jamxia155 Jul 16, 2026
ce0237e
Fix NPE when advance() precedes nextDoc() in docAndScoreQuery iterator
jamxia155 Jul 17, 2026
a8fa2d9
Reference-count and compute-once the filter bitset cache
jamxia155 Jul 17, 2026
863d38d
Gate per-segment CAGRA decode on the distance sentinel
jamxia155 Jul 18, 2026
c2b4fc0
Exercise the multi-partition GPU path in the filter concurrency test
jamxia155 Jul 18, 2026
4427afb
Fix per-segment prefilter dropping trailing ordinals under selective …
jamxia155 Jul 18, 2026
e32040f
Take the multi-partition path for PerField GPU segments, gated on gra…
jamxia155 Jul 18, 2026
8751542
Include boost in GPU search score explanation
jamxia155 Jul 18, 2026
21e28f3
Return a real max score to enable score-based pruning
jamxia155 Jul 18, 2026
d389dfc
Address review comments
jamxia155 Jul 18, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 8 additions & 3 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
# SPDX-FileCopyrightText: Copyright (c) 2025, NVIDIA CORPORATION.
# SPDX-License-Identifier: Apache-2.0

# Maven
*.jar
target
**/.DS_Store
bin
target/

# IDE - IntelliJ
.idea/
*.iml

# IDE - Eclipse
.project
cuvs-workdir
4 changes: 2 additions & 2 deletions bench/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

<groupId>com.nvidia.cuvs.lucene.benchmarks</groupId>
<artifactId>cuvs-lucene-benchmarks</artifactId>
<!--CUVS_LUCENE#VERSION_UPDATE_MARKER_START--><version>26.08.0</version><!--CUVS_LUCENE#VERSION_UPDATE_MARKER_END-->
<!--CUVS_LUCENE#VERSION_UPDATE_MARKER_START--><version>26.08.0-SNAPSHOT</version><!--CUVS_LUCENE#VERSION_UPDATE_MARKER_END-->
<packaging>jar</packaging>

<name>cuvs-lucene-benchmarks</name>
Expand Down Expand Up @@ -85,7 +85,7 @@
<dependency>
<groupId>com.nvidia.cuvs.lucene</groupId>
<artifactId>cuvs-lucene</artifactId>
<!--CUVS_LUCENE#VERSION_UPDATE_MARKER_START--><version>26.08.0</version><!--CUVS_LUCENE#VERSION_UPDATE_MARKER_END-->
<!--CUVS_LUCENE#VERSION_UPDATE_MARKER_START--><version>26.08.0-SNAPSHOT</version><!--CUVS_LUCENE#VERSION_UPDATE_MARKER_END-->
</dependency>
<dependency>
<groupId>commons-io</groupId>
Expand Down
4 changes: 2 additions & 2 deletions build.sh
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
#!/bin/bash

# SPDX-FileCopyrightText: Copyright (c) 2025-2026, NVIDIA CORPORATION.
# SPDX-FileCopyrightText: Copyright (c) 2025-2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0

set -e -u -o pipefail

ARGS="$*"
NUMARGS=$#

VERSION="26.08.0" # Note: The version is updated automatically when ci/release/update-version.sh is invoked
VERSION="26.08.0-SNAPSHOT" # Note: The version is updated automatically when ci/release/update-version.sh is invoked
GROUP_ID="com.nvidia.cuvs.lucene"

function hasArg {
Expand Down
4 changes: 2 additions & 2 deletions examples/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

<groupId>com.nvidia.cuvs.lucene.examples</groupId>
<artifactId>examples</artifactId>
<!--CUVS_LUCENE#VERSION_UPDATE_MARKER_START--><version>26.08.0</version><!--CUVS_LUCENE#VERSION_UPDATE_MARKER_END-->
<!--CUVS_LUCENE#VERSION_UPDATE_MARKER_START--><version>26.08.0-SNAPSHOT</version><!--CUVS_LUCENE#VERSION_UPDATE_MARKER_END-->
<name>examples</name>

<properties>
Expand Down Expand Up @@ -100,7 +100,7 @@
<dependency>
<groupId>com.nvidia.cuvs.lucene</groupId>
<artifactId>cuvs-lucene</artifactId>
<!--CUVS_LUCENE#VERSION_UPDATE_MARKER_START--><version>26.08.0</version><!--CUVS_LUCENE#VERSION_UPDATE_MARKER_END-->
<!--CUVS_LUCENE#VERSION_UPDATE_MARKER_START--><version>26.08.0-SNAPSHOT</version><!--CUVS_LUCENE#VERSION_UPDATE_MARKER_END-->
</dependency>
</dependencies>

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: Copyright (c) 2025-2026, NVIDIA CORPORATION.
* SPDX-FileCopyrightText: Copyright (c) 2025-2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.nvidia.cuvs.lucene.examples;
Expand Down Expand Up @@ -30,9 +30,12 @@
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.index.LeafReader;
import org.apache.lucene.index.LeafReaderContext;
import org.apache.lucene.index.Term;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.KnnFloatVectorQuery;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.TermQuery;
import org.apache.lucene.search.TopDocs;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
Expand All @@ -56,6 +59,7 @@ public static void main(String[] args) throws Exception {
final int COMMIT_FREQ = 2000;
final String ID_FIELD = "id";
final String VECTOR_FIELD = "vector_field";
final String STATUS_FIELD = "status";

int numDocs = 2000;
int dimension = 32;
Expand All @@ -70,6 +74,9 @@ public static void main(String[] args) throws Exception {
Document document = new Document();
document.add(new StringField(ID_FIELD, Integer.toString(i), Field.Store.YES));
document.add(new KnnFloatVectorField(VECTOR_FIELD, dataset[i], EUCLIDEAN));
// Alternatively flip the status's for documents as an example.
document.add(
new StringField(STATUS_FIELD, i % 2 == 0 ? "active" : "in-active", Field.Store.YES));
indexWriter.addDocument(document);
count -= 1;
if (count == 0) {
Expand Down Expand Up @@ -103,8 +110,11 @@ public static void main(String[] args) throws Exception {
float[] queryVector = generateDataset(random, 1, dimension)[0];
log.log(Level.FINE, "Query vector: " + Arrays.toString(queryVector));

// Make a filter query
Query filter = new TermQuery(new Term(STATUS_FIELD, "active"));

KnnFloatVectorQuery query =
new GPUKnnFloatVectorQuery(VECTOR_FIELD, queryVector, topK, null, topK, 1);
new GPUKnnFloatVectorQuery(VECTOR_FIELD, queryVector, topK, filter, topK, 1);
TopDocs results = searcher.search(query, topK);

log.log(Level.FINE, "Search results (" + results.totalHits + " total hits):");
Expand All @@ -113,12 +123,15 @@ public static void main(String[] args) throws Exception {
ScoreDoc scoreDoc = results.scoreDocs[i];
Document doc = searcher.storedFields().document(scoreDoc.doc);
String id = doc.get(ID_FIELD);
String status = doc.get(STATUS_FIELD);
log.log(
Level.FINE,
" Rank "
+ (i + 1)
+ ": doc "
+ scoreDoc.doc
+ " status "
+ status
+ " (id="
+ id
+ "), score="
Expand Down
4 changes: 4 additions & 0 deletions license-header.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
/*
* SPDX-FileCopyrightText: Copyright (c) $YEAR, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
* SPDX-License-Identifier: Apache-2.0
*/
33 changes: 31 additions & 2 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
<groupId>com.nvidia.cuvs.lucene</groupId>
<artifactId>cuvs-lucene</artifactId>
<!-- NOTE: The version automatically gets updated when ci/release/update-version.sh is invoked. -->
<!--CUVS_LUCENE#VERSION_UPDATE_MARKER_START--><version>26.08.0</version><!--CUVS_LUCENE#VERSION_UPDATE_MARKER_END-->
<!--CUVS_LUCENE#VERSION_UPDATE_MARKER_START--><version>26.08.0-SNAPSHOT</version><!--CUVS_LUCENE#VERSION_UPDATE_MARKER_END-->
<name>cuvs-lucene</name>
<packaging>jar</packaging>

Expand All @@ -36,6 +36,18 @@
<url>https://github.com/rapidsai/cuvs-lucene</url>
</scm>

<developers>
<developer>
<id>rapidsai</id>
<name>rapidsai</name>
<email>cuvs@rapids.ai</email>
<roles>
<role>Maintainer</role>
<role>Committer</role>
</roles>
</developer>
</developers>

<properties>
<maven.compiler.target>22</maven.compiler.target>
<maven.compiler.source>22</maven.compiler.source>
Expand Down Expand Up @@ -68,6 +80,12 @@
<enabled>false</enabled>
</snapshots>
</repository>
<repository>
<id>central-snapshots</id>
<url>https://central.sonatype.com/repository/maven-snapshots/</url>
<snapshots><enabled>true</enabled></snapshots>
<releases><enabled>false</enabled></releases>
</repository>
</repositories>

<pluginRepositories>
Expand Down Expand Up @@ -129,10 +147,17 @@
<dependency>
<groupId>com.nvidia.cuvs</groupId>
<artifactId>cuvs-java</artifactId>
<!--CUVS_LUCENE#VERSION_UPDATE_MARKER_START--><version>26.08.0</version><!--CUVS_LUCENE#VERSION_UPDATE_MARKER_END-->
<!--CUVS_LUCENE#VERSION_UPDATE_MARKER_START--><version>26.08.0-SNAPSHOT</version><!--CUVS_LUCENE#VERSION_UPDATE_MARKER_END-->
</dependency>
</dependencies>

<distributionManagement>
<snapshotRepository>
<id>central</id>
<url>https://central.sonatype.com/repository/maven-snapshots/</url>
</snapshotRepository>
</distributionManagement>

<build>
<plugins>
<plugin>
Expand All @@ -158,6 +183,9 @@
<reflowLongStrings>true</reflowLongStrings>
<formatJavadoc>false</formatJavadoc>
</googleJavaFormat>
<licenseHeader>
<file>${project.basedir}/license-header.txt</file>
</licenseHeader>
</java>
</configuration>
</plugin>
Expand Down Expand Up @@ -219,6 +247,7 @@
<goal>jar</goal>
</goals>
<configuration>
<includePackageNames>com.nvidia.cuvs.lucene</includePackageNames>
<doclint>all,-missing</doclint>
<outputDirectory>${project.build.directory}/javadocs</outputDirectory>
</configuration>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
/*
* SPDX-FileCopyrightText: Copyright (c) 2025-2026, NVIDIA CORPORATION.
* SPDX-FileCopyrightText: Copyright (c) 2025-2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.nvidia.cuvs.lucene;

import static com.nvidia.cuvs.lucene.ThreadLocalCuVSResourcesProvider.assertIsSupported;

import com.nvidia.cuvs.LibraryException;
import com.nvidia.cuvs.spi.CuVSProvider;
import java.io.IOException;
import org.apache.lucene.codecs.KnnVectorsFormat;
import org.apache.lucene.codecs.KnnVectorsReader;
Expand Down Expand Up @@ -39,6 +40,7 @@ public class CuVS2510GPUVectorsFormat extends KnnVectorsFormat {

static {
try {
CuVSProvider.provider().enableRMMAsyncMemory();
LUCENE_PROVIDER = LuceneProvider.getInstance("99");
FLAT_VECTORS_FORMAT =
LUCENE_PROVIDER.getLuceneFlatVectorsFormatInstance(DefaultFlatVectorScorer.INSTANCE);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: Copyright (c) 2025-2026, NVIDIA CORPORATION.
* SPDX-FileCopyrightText: Copyright (c) 2025-2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.nvidia.cuvs.lucene;
Expand Down Expand Up @@ -430,7 +430,10 @@ public void search(String field, float[] target, KnnCollector knnCollector, Bits
}
}
topK = Math.min(knnCollector.k() + 10, mask[0].cardinality());
maskLength = mask[0].length();
// numDocs must be the total vector count so cuVS sizes the prefilter to cover every ordinal.
// BitSet.length() is (highest set bit + 1), which under a selective filter is smaller than the
// vector count, leaving the trailing ordinals outside the filter and thus default-accepted.
maskLength = acceptedOrds.length();
}

try {
Expand All @@ -443,6 +446,9 @@ public void search(String field, float[] target, KnnCollector knnCollector, Bits
new CagraSearchParams.Builder()
.withItopkSize(Math.max(collector.getiTopK(), topK))
.withSearchWidth(collector.getSearchWidth())
.withThreadBlockSize(collector.getThreadBlockSize())
.withMaxIterations(collector.getMaxIterations())
.withAlgo(collector.getSearchAlgo())
.build();
} else {
// Setting itopK as topK because in any case iTopK should be ATLEAST equal to topK
Expand Down Expand Up @@ -509,7 +515,11 @@ public void search(String field, float[] target, KnnCollector knnCollector, Bits
if (knnCollector.earlyTerminated()) {
break;
}
if (ord < 0) {
// Empty top-k slots (fewer than k passing candidates) carry a sentinel distance of FLT_MAX.
// Prefer this over the neighbor-index sentinel: the index sentinel is not uniform across
// CAGRA search algorithms (single-CTA emits 0x7FFFFFFF, multi-CTA 0xFFFFFFFF), so the
// distance is the reliable, algorithm-independent signal for an empty slot.
if (score == Float.MAX_VALUE) {
continue;
}
float correctedScore = scoreCorrectionFunction.apply(score);
Expand Down Expand Up @@ -600,6 +610,22 @@ private static void checkVersion(int versionMeta, int versionVectorData, IndexIn
}
}

/**
* Returns the {@link CagraIndex} for the given field, or {@code null} if unavailable
* (e.g., during a merge or when the field is missing).
*
* @param field the vector field name
* @return the CAGRA index, or {@code null}
*/
public CagraIndex getCagraIndexForField(String field) {
if (cuvsIndices == null) return null;
FieldInfo info = fieldInfos.fieldInfo(field);
if (info == null) return null;
GPUIndex gpuIndex = cuvsIndices.get(info.number);
if (gpuIndex == null) return null;
return gpuIndex.getCagraIndex();
}

/**
* Gets the instance of FieldInfos.
*
Expand Down
Loading
Loading