Skip to content

Commit e1baea2

Browse files
committed
Add ef_search fix
Signed-off-by: James Bourbeau <jbourbeau@nvidia.com>
1 parent 6ed6909 commit e1baea2

2 files changed

Lines changed: 37 additions & 50 deletions

File tree

python/cuvs_bench/cuvs_bench/backends/opensearch.py

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -825,9 +825,9 @@ def search(
825825
Search the OpenSearch k-NN index for nearest neighbors.
826826
827827
Iterates over every search-parameter combination defined in the index
828-
config, updating the index-level ``ef_search`` setting between runs.
829-
Returns one result per parameter set so the orchestrator can compute
830-
recall for each set independently.
828+
config, passing ``ef_search`` directly in every k-NN query. Returns one
829+
result per parameter set so the orchestrator can compute recall for
830+
each set independently.
831831
832832
Parameters
833833
----------
@@ -919,12 +919,6 @@ def search(
919919
for sp in search_params_list:
920920
ef_search = sp.get("ef_search", 100)
921921

922-
if engine == "faiss":
923-
self._client.indices.put_settings(
924-
index=index_name,
925-
body={"index.knn.algo_param.ef_search": ef_search},
926-
)
927-
928922
neighbors = np.full((n_queries, k), -1, dtype=np.int64)
929923
distances = np.zeros((n_queries, k), dtype=np.float32)
930924

@@ -942,6 +936,9 @@ def search(
942936
"vector": {
943937
"vector": q_vec.tolist(),
944938
"k": k,
939+
"method_parameters": {
940+
"ef_search": ef_search,
941+
},
945942
}
946943
}
947944
},

python/cuvs_bench/cuvs_bench/tests/test_opensearch.py

Lines changed: 31 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -190,47 +190,6 @@ def test_search_dry_run(self):
190190
[{"ef_search": 100}],
191191
]
192192

193-
def test_recall_is_computed_for_each_search_parameter(self):
194-
class FakeIndices:
195-
def __init__(self):
196-
self.ef_search = None
197-
198-
def put_settings(self, index, body):
199-
self.ef_search = body["index.knn.algo_param.ef_search"]
200-
201-
class FakeClient:
202-
def __init__(self):
203-
self.indices = FakeIndices()
204-
205-
def msearch(self, index, body):
206-
ids = [2, 3] if self.indices.ef_search == 50 else [0, 1]
207-
response = {
208-
"hits": {
209-
"hits": [
210-
{"_id": str(neighbor), "_score": 1.0}
211-
for neighbor in ids
212-
]
213-
}
214-
}
215-
return {"responses": [response for _ in body[::2]]}
216-
217-
dataset = Dataset(
218-
name="test",
219-
query_vectors=np.zeros((2, 4), dtype=np.float32),
220-
groundtruth_neighbors=np.array([[0, 1], [0, 1]]),
221-
)
222-
backend = _make_backend()
223-
backend._OpenSearchBackend__client = FakeClient()
224-
225-
results = backend.search(
226-
dataset, [_make_index_cfg()], k=2, batch_size=2
227-
)
228-
for result in results:
229-
BenchmarkOrchestrator._finalize_search_result(result, dataset, 2)
230-
231-
assert [result.recall for result in results] == [0.0, 1.0]
232-
assert all(result.neighbors.shape == (2, 2) for result in results)
233-
234193
def test_remote_build_requires_faiss_engine(self):
235194
backend = _make_backend({"engine": "lucene"})
236195
with pytest.raises(ValueError, match="faiss engine"):
@@ -559,6 +518,37 @@ def test_build_and_search(self, live_backend):
559518
assert search_result.queries_per_second > 0
560519
assert search_result.neighbors.shape == (10, k)
561520

521+
def test_recall_is_computed_for_each_search_parameter(self, live_backend):
522+
# Regression test for https://github.com/NVIDIA/cuvs/issues/2358
523+
k = 10
524+
dataset = _make_dataset(
525+
n_base=5_000,
526+
n_queries=100,
527+
dims=16,
528+
k=k,
529+
)
530+
idx = IndexConfig(
531+
name="test_index",
532+
algo="opensearch_faiss_hnsw",
533+
build_param={"m": 4, "ef_construction": 64},
534+
search_params=[{"ef_search": 10}, {"ef_search": 100}],
535+
file="",
536+
)
537+
538+
build_result = live_backend.build(dataset, [idx], force=True)
539+
assert build_result.success
540+
541+
results = live_backend.search(dataset, [idx], k=k)
542+
for result in results:
543+
BenchmarkOrchestrator._finalize_search_result(result, dataset, k)
544+
545+
assert [result.search_params for result in results] == [
546+
[{"ef_search": 10}],
547+
[{"ef_search": 100}],
548+
]
549+
assert all(result.neighbors.shape == (100, k) for result in results)
550+
assert results[0].recall < results[1].recall
551+
562552

563553
@pytest.mark.opensearch
564554
class TestOpenSearchRemoteIndexBuildIntegration:

0 commit comments

Comments
 (0)