Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
46 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
7880820
cuvs-lucene: per-segment filter bitsets and per-segment cache keying
jamxia155 Jul 22, 2026
29aa10d
cuvs-lucene: evict filter cache entries on segment close
jamxia155 Jul 22, 2026
d3e87b8
byte-budget filter cache with disable/clear controls
jamxia155 Jul 22, 2026
0fd1a9e
back filter bitset cache with a sized device pool
jamxia155 Jul 22, 2026
17fceeb
align workspace pool size to RMM's 256-byte requirement
jamxia155 Jul 22, 2026
361daf3
Update cuvs version
jamxia155 Jul 22, 2026
222d9a9
Merge remote-tracking branch 'origin/main' into multi-segment-cagra-s…
jamxia155 Jul 22, 2026
11fce3f
Add double-check for hardening
jamxia155 Jul 23, 2026
094fa78
Make filter bitset cache codec-local
jamxia155 Jul 23, 2026
f5f5d98
Merge remote-tracking branch 'origin/main' into multi-segment-cagra-s…
jamxia155 Jul 23, 2026
e7e50b5
Make async RMM initialization application-controlled
jamxia155 Jul 23, 2026
b77bfbf
Use fixed and explicitly configurable filter cache budgets
jamxia155 Jul 24, 2026
6d05bb8
Prevent resource leaks from invalid workspace pool sizes
jamxia155 Jul 24, 2026
9c55185
Temporary change for CI
jamxia155 Jul 24, 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
2 changes: 1 addition & 1 deletion RAPIDS_BRANCH
Original file line number Diff line number Diff line change
@@ -1 +1 @@
main
pull-request/2035
15 changes: 15 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,21 @@ The example below plugs the GPU-accelerated HNSW codec into a standard Lucene `I

Before running it, make sure cuVS is installed and available on your system library load path. The cuVS [tarball install instructions](https://docs.rapids.ai/api/cuvs/stable/build/#download-extract) show how to set this up.

### RMM async allocation for GPU search

Applications using `CuVS2510GPUSearchCodec` can opt into RMM's stream-ordered asynchronous device
allocator during startup:

```java
CuVSProvider.provider().enableRMMAsyncMemory();
```

Call this before creating any cuVS resources, codecs, writers, or readers. The setting affects the
entire process on the current CUDA device, so allocator policy belongs to the application rather
than an individual Lucene codec. Async allocation is optional for correctness and recommended for
GPU workloads with repeated device allocations, especially concurrent or multi-stream searches.
Applications that do not opt in use the default RMM device-memory resource.

In a Maven project that includes the `cuvs-lucene` dependency shown above, create `src/main/java/com/nvidia/cuvs/lucene/examples/HelloCuvsLucene.java`:

```java
Expand Down
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.10.0</version><!--CUVS_LUCENE#VERSION_UPDATE_MARKER_END-->
<!--CUVS_LUCENE#VERSION_UPDATE_MARKER_START--><version>26.10.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.10.0</version><!--CUVS_LUCENE#VERSION_UPDATE_MARKER_END-->
<!--CUVS_LUCENE#VERSION_UPDATE_MARKER_START--><version>26.10.0-SNAPSHOT</version><!--CUVS_LUCENE#VERSION_UPDATE_MARKER_END-->
</dependency>
<dependency>
<groupId>commons-io</groupId>
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.benchmarks;
Expand All @@ -9,6 +9,7 @@
import static com.nvidia.cuvs.lucene.benchmarks.Utils.index;

import com.nvidia.cuvs.lucene.CuVS2510GPUSearchCodec;
import com.nvidia.cuvs.spi.CuVSProvider;
import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
Expand Down Expand Up @@ -57,6 +58,7 @@ public class CagraIndexingBenchmarks {

@Setup(Level.Trial)
public void setup() throws Exception {
CuVSProvider.provider().enableRMMAsyncMemory();
random = new Random(222);
indexDirPath = Paths.get(UUID.randomUUID().toString());
codec = new CuVS2510GPUSearchCodec();
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.benchmarks;
Expand All @@ -11,6 +11,7 @@

import com.nvidia.cuvs.lucene.CuVS2510GPUSearchCodec;
import com.nvidia.cuvs.lucene.GPUKnnFloatVectorQuery;
import com.nvidia.cuvs.spi.CuVSProvider;
import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
Expand Down Expand Up @@ -62,6 +63,7 @@ public class CagraSearchBenchmarks {

@Setup(Level.Trial)
public void setup() throws Exception {
CuVSProvider.provider().enableRMMAsyncMemory();
random = new Random(222);
indexDirPath = Paths.get(UUID.randomUUID().toString());
codec = new CuVS2510GPUSearchCodec();
Expand Down
2 changes: 1 addition & 1 deletion build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ set -e -u -o pipefail
ARGS="$*"
NUMARGS=$#

VERSION="26.10.0" # Note: The version is updated automatically when ci/release/update-version.sh is invoked
VERSION="26.10.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.10.0</version><!--CUVS_LUCENE#VERSION_UPDATE_MARKER_END-->
<!--CUVS_LUCENE#VERSION_UPDATE_MARKER_START--><version>26.10.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.10.0</version><!--CUVS_LUCENE#VERSION_UPDATE_MARKER_END-->
<!--CUVS_LUCENE#VERSION_UPDATE_MARKER_START--><version>26.10.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 All @@ -10,6 +10,7 @@
import com.nvidia.cuvs.lucene.CuVS2510GPUSearchCodec;
import com.nvidia.cuvs.lucene.GPUKnnFloatVectorQuery;
import com.nvidia.cuvs.lucene.GPUSearchParams;
import com.nvidia.cuvs.spi.CuVSProvider;
import java.io.File;
import java.nio.file.Path;
import java.nio.file.Paths;
Expand All @@ -30,9 +31,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 @@ -46,6 +50,9 @@ public class IndexAndSearchonGPUExample {

public static void main(String[] args) throws Exception {

// Select the process-wide RMM allocator before creating any cuVS resources or codecs.
CuVSProvider.provider().enableRMMAsyncMemory();

GPUSearchParams params = new GPUSearchParams.Builder().build();
Codec codec = new CuVS2510GPUSearchCodec(params);
IndexWriterConfig config = new IndexWriterConfig().setCodec(codec).setUseCompoundFile(false);
Expand All @@ -56,6 +63,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 +78,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 +114,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 +127,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.10.0</version><!--CUVS_LUCENE#VERSION_UPDATE_MARKER_END-->
<!--CUVS_LUCENE#VERSION_UPDATE_MARKER_START--><version>26.10.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.10.0</version><!--CUVS_LUCENE#VERSION_UPDATE_MARKER_END-->
<!--CUVS_LUCENE#VERSION_UPDATE_MARKER_START--><version>26.10.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,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 @@ -29,8 +29,11 @@ public class CuVS2510GPUSearchCodec extends FilterCodec {
* @throws Exception
*/
public CuVS2510GPUSearchCodec() throws Exception {
this(NAME, LuceneProvider.getCodec("101"));
initializeFormat(new GPUSearchParams.Builder().build());
this(
NAME,
LuceneProvider.getCodec("101"),
new GPUSearchParams.Builder().build(),
FilterBitsetCacheConfig.DEFAULT);
}

/**
Expand All @@ -41,8 +44,11 @@ public CuVS2510GPUSearchCodec() throws Exception {
* @param delegate the delegate codec
*/
public CuVS2510GPUSearchCodec(String name, Codec delegate) {
super(name, delegate);
initializeFormat(new GPUSearchParams.Builder().build());
this(
name,
delegate,
new GPUSearchParams.Builder().build(),
FilterBitsetCacheConfig.DEFAULT);
}

/**
Expand All @@ -53,18 +59,48 @@ public CuVS2510GPUSearchCodec(String name, Codec delegate) {
* @throws Exception Exception raised when initializing the codec
*/
public CuVS2510GPUSearchCodec(GPUSearchParams params) throws Exception {
this(NAME, LuceneProvider.getCodec("101"));
initializeFormat(params);
this(NAME, LuceneProvider.getCodec("101"), params, FilterBitsetCacheConfig.DEFAULT);
}

/**
* Initialize the codec with GPU search and filter-bitset-cache parameters.
*
* @param params GPU index and search parameters
* @param filterCacheConfig filter-bitset-cache configuration
* @throws Exception Exception raised when initializing the codec
*/
public CuVS2510GPUSearchCodec(
GPUSearchParams params, FilterBitsetCacheConfig filterCacheConfig) throws Exception {
this(NAME, LuceneProvider.getCodec("101"), params, filterCacheConfig);
}

/**
* Initialize a named codec with explicit delegate, GPU search, and filter-cache parameters.
*
* @param name the name of the codec
* @param delegate the delegate codec
* @param params GPU index and search parameters
* @param filterCacheConfig filter-bitset-cache configuration
*/
public CuVS2510GPUSearchCodec(
String name,
Codec delegate,
GPUSearchParams params,
FilterBitsetCacheConfig filterCacheConfig) {
super(name, delegate);
initializeFormat(params, filterCacheConfig);
}

/**
* Initialize the {@link CuVS2510GPUVectorsFormat} instance using {@link GPUSearchParams}.
*
* @param params an instance of {@link GPUSearchParams}
* @param filterCacheConfig filter-bitset-cache configuration
*/
private void initializeFormat(GPUSearchParams params) {
private void initializeFormat(
GPUSearchParams params, FilterBitsetCacheConfig filterCacheConfig) {
try {
format = new CuVS2510GPUVectorsFormat(params);
format = new CuVS2510GPUVectorsFormat(params, filterCacheConfig);
setKnnFormat(format);
} catch (LibraryException ex) {
log.log(
Expand Down
Loading
Loading