Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
553 changes: 553 additions & 0 deletions conda/recipes/cuvs-bench/build_pylucene_10_2.sh

Large diffs are not rendered by default.

50 changes: 50 additions & 0 deletions conda/recipes/cuvs-bench/pylucene-10.2.0.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
--- a/Makefile
+++ b/Makefile
@@ -15,8 +15,8 @@
# site-packages directory.
#

-VERSION=10.0.0
-LUCENE_VER=10.0.0
+VERSION=10.2.0
+LUCENE_VER=10.2.0
PYLUCENE:=$(shell pwd)
LUCENE_SRC=lucene-java-$(LUCENE_VER)
LUCENE=$(LUCENE_SRC)/lucene
@@ -163,7 +163,7 @@
STEMPEL_JAR=$(LUCENE)/analysis/stempel/build/runtimeJars/lucene-analysis-stempel-$(LUCENE_VER)-SNAPSHOT.jar
SUGGEST_JAR=$(LUCENE)/suggest/build/runtimeJars/lucene-suggest-$(LUCENE_VER)-SNAPSHOT.jar

-ANTLR_JAR=$(LUCENE)/expressions/build/runtimeJars/antlr4-runtime-4.11.1.jar
+ANTLR_JAR=$(LUCENE)/expressions/build/runtimeJars/antlr4-runtime-4.13.2.jar
ASM_JAR=$(LUCENE)/expressions/build/runtimeJars/asm-9.6.jar
ASM_COMMONS_JAR=$(LUCENE)/expressions/build/runtimeJars/asm-commons-9.6.jar

@@ -254,6 +254,7 @@
--package org.antlr.v4.runtime.atn \
--package org.apache.lucene.analysis.ko.dict \
--package org.apache.lucene.analysis.ja.dict \
+ --package org.apache.lucene.sandbox.facet.plain.histograms \
--exclude org.apache.lucene.sandbox.queries.regex.JakartaRegexpCapabilities \
--exclude org.apache.regexp.RegexpTunnel \
--exclude org.apache.lucene.misc.store.WindowsDirectory \
--- a/lucene-java-10.2.0/settings.gradle
+++ b/lucene-java-10.2.0/settings.gradle
@@ -69,6 +69,7 @@
include "lucene:distribution.tests"
include "lucene:documentation"
include "lucene:expressions"
+include "lucene:extensions"
include "lucene:facet"
include "lucene:grouping"
include "lucene:highlighter"
--- a/lucene-java-10.2.0/gradle/wrapper/gradle-wrapper.properties
+++ b/lucene-java-10.2.0/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,7 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.10-bin.zip
+distributionSha256Sum=5b9c5eb3f9fc2c94abaea57d90bd78747ca117ddbbf96c859d3741181a12bf2a
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
2 changes: 2 additions & 0 deletions fern/docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -575,6 +575,8 @@ navigation:
path: "./pages/lucene_api/lucene-api-com-nvidia-cuvs-lucene-gpuindex.md"
- page: "GPUSearchParams"
path: "./pages/lucene_api/lucene-api-com-nvidia-cuvs-lucene-gpusearchparams.md"
- page: "IndexSearcherTimingBridge"
path: "./pages/lucene_api/lucene-api-com-nvidia-cuvs-lucene-indexsearchertimingbridge.md"
- page: "LuceneProvider"
path: "./pages/lucene_api/lucene-api-com-nvidia-cuvs-lucene-luceneprovider.md"
- page: "ThreadLocalCuVSResourcesProvider"
Expand Down
1 change: 1 addition & 0 deletions fern/pages/lucene_api/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ For an introduction to the codecs, configuration, and tuning, see the [Lucene In
- [FilterCuVSServiceProvider](/api-reference/lucene-api-com-nvidia-cuvs-lucene-filtercuvsserviceprovider)
- [GPUIndex](/api-reference/lucene-api-com-nvidia-cuvs-lucene-gpuindex)
- [GPUSearchParams](/api-reference/lucene-api-com-nvidia-cuvs-lucene-gpusearchparams)
- [IndexSearcherTimingBridge](/api-reference/lucene-api-com-nvidia-cuvs-lucene-indexsearchertimingbridge)
- [LuceneProvider](/api-reference/lucene-api-com-nvidia-cuvs-lucene-luceneprovider)
- [ThreadLocalCuVSResourcesProvider](/api-reference/lucene-api-com-nvidia-cuvs-lucene-threadlocalcuvsresourcesprovider)
- [Utils](/api-reference/lucene-api-com-nvidia-cuvs-lucene-utils)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
---
slug: api-reference/lucene-api-com-nvidia-cuvs-lucene-indexsearchertimingbridge
---

# IndexSearcherTimingBridge

_Java package: `com.nvidia.cuvs.lucene`_

```java
public final class IndexSearcherTimingBridge implements Function<Map<String, Object>, Map<String, Object>>
```

Measures one `IndexSearcher#search(Query,int)` invocation inside the JVM.

The standard `Function` and `Map` types form a narrow bridge for generated Java
bindings that do not wrap this class directly. Each call still represents one ordinary Lucene
query; this class does not add batching or concurrency.

The request map must contain `searcher` (an `IndexSearcher`), `query` (a
`Query`), and `top_k` (an `Integer`). The response contains `top_docs` (a
`TopDocs`) and `elapsed_nanos` (a `Long`). An `IOException` from Lucene is
exposed as an `UncheckedIOException` because `Function.apply` cannot declare checked
exceptions.

_Source: `java/cuvs-lucene/src/main/java/com/nvidia/cuvs/lucene/IndexSearcherTimingBridge.java:29`_
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
/*
* SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.nvidia.cuvs.lucene;

import java.io.IOException;
import java.io.UncheckedIOException;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.TopDocs;

/**
* Measures one {@link IndexSearcher#search(Query,int)} invocation inside the JVM.
*
* <p>The standard {@link Function} and {@link Map} types form a narrow bridge for generated Java
* bindings that do not wrap this class directly. Each call still represents one ordinary Lucene
* query; this class does not add batching or concurrency.
*
* <p>The request map must contain {@code searcher} (an {@code IndexSearcher}), {@code query} (a
* {@code Query}), and {@code top_k} (an {@code Integer}). The response contains {@code top_docs} (a
* {@code TopDocs}) and {@code elapsed_nanos} (a {@code Long}). An {@code IOException} from Lucene is
* exposed as an {@code UncheckedIOException} because {@code Function.apply} cannot declare checked
* exceptions.
*/
public final class IndexSearcherTimingBridge
implements Function<Map<String, Object>, Map<String, Object>> {
public static final String SEARCHER_KEY = "searcher";
public static final String QUERY_KEY = "query";
public static final String TOP_K_KEY = "top_k";
public static final String TOP_DOCS_KEY = "top_docs";
public static final String ELAPSED_NANOS_KEY = "elapsed_nanos";

@Override
public Map<String, Object> apply(Map<String, Object> request) {
IndexSearcher searcher = requiredValue(request, SEARCHER_KEY, IndexSearcher.class);
Query query = requiredValue(request, QUERY_KEY, Query.class);
Integer topK = requiredValue(request, TOP_K_KEY, Integer.class);
if (topK < 1) {
throw new IllegalArgumentException("top_k must be positive");
}

long started = System.nanoTime();
TopDocs topDocs;
try {
topDocs = searcher.search(query, topK);
} catch (IOException error) {
throw new UncheckedIOException("IndexSearcher.search failed", error);
}
long elapsedNanos = System.nanoTime() - started;

Map<String, Object> response = new HashMap<>();
response.put(TOP_DOCS_KEY, topDocs);
response.put(ELAPSED_NANOS_KEY, elapsedNanos);
return response;
}

private static <T> T requiredValue(
Map<String, Object> values, String key, Class<T> expectedType) {
if (values == null) {
throw new IllegalArgumentException("request must not be null");
}
Object value = values.get(key);
if (!expectedType.isInstance(value)) {
throw new IllegalArgumentException(key + " must have type " + expectedType.getSimpleName());
}
return expectedType.cast(value);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
/*
* SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.nvidia.cuvs.lucene;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertThrows;
import static org.junit.Assert.assertTrue;

import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;
import org.apache.lucene.document.Document;
import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.MatchAllDocsQuery;
import org.apache.lucene.search.TopDocs;
import org.apache.lucene.store.ByteBuffersDirectory;
import org.junit.Test;

public class TestIndexSearcherTimingBridge {

@Test
public void testReturnsTopDocsAndInJvmElapsedTimeThroughStandardTypes() throws Exception {
try (var directory = new ByteBuffersDirectory();
var writer = new IndexWriter(directory, new IndexWriterConfig())) {
writer.addDocument(new Document());
writer.commit();

try (var reader = DirectoryReader.open(directory)) {
Function<Map<String, Object>, Map<String, Object>> bridge = new IndexSearcherTimingBridge();
Map<String, Object> request = new HashMap<>();
request.put(IndexSearcherTimingBridge.SEARCHER_KEY, new IndexSearcher(reader));
request.put(IndexSearcherTimingBridge.QUERY_KEY, new MatchAllDocsQuery());
request.put(IndexSearcherTimingBridge.TOP_K_KEY, 1);

Map<String, Object> response = bridge.apply(request);

TopDocs topDocs = (TopDocs) response.get(IndexSearcherTimingBridge.TOP_DOCS_KEY);
Long elapsedNanos = (Long) response.get(IndexSearcherTimingBridge.ELAPSED_NANOS_KEY);
assertNotNull(topDocs);
assertEquals(1, topDocs.scoreDocs.length);
assertNotNull(elapsedNanos);
assertTrue(elapsedNanos >= 0L);
}
}
}

@Test
public void testRejectsAnIncompleteRequestBeforeSearching() {
var request = new HashMap<String, Object>();
request.put(IndexSearcherTimingBridge.QUERY_KEY, new MatchAllDocsQuery());
request.put(IndexSearcherTimingBridge.TOP_K_KEY, 1);

IllegalArgumentException error =
assertThrows(
IllegalArgumentException.class, () -> new IndexSearcherTimingBridge().apply(request));

assertEquals("searcher must have type IndexSearcher", error.getMessage());
}
}
Loading
Loading