diff --git a/modules/percolator/src/internalClusterTest/java/org/elasticsearch/percolator/PercolatorQuerySearchIT.java b/modules/percolator/src/internalClusterTest/java/org/elasticsearch/percolator/PercolatorQuerySearchIT.java index 5e8ced116a1ff..9df294d3e6cf0 100644 --- a/modules/percolator/src/internalClusterTest/java/org/elasticsearch/percolator/PercolatorQuerySearchIT.java +++ b/modules/percolator/src/internalClusterTest/java/org/elasticsearch/percolator/PercolatorQuerySearchIT.java @@ -40,6 +40,7 @@ import java.util.Collections; import java.util.Map; +import static org.elasticsearch.index.mapper.vectors.DenseVectorFieldMapper.IVF_FORMAT; import static org.elasticsearch.index.query.QueryBuilders.boolQuery; import static org.elasticsearch.index.query.QueryBuilders.combinedFieldsQuery; import static org.elasticsearch.index.query.QueryBuilders.constantScoreQuery; @@ -1359,7 +1360,15 @@ public void testKnnQueryNotSupportedInPercolator() throws IOException { """); indicesAdmin().prepareCreate("index1").setMapping(mappings).get(); ensureGreen(); - QueryBuilder knnVectorQueryBuilder = new KnnVectorQueryBuilder("my_vector", new float[] { 1, 1, 1, 1, 1 }, 10, 10, 10f, null, null); + QueryBuilder knnVectorQueryBuilder = new KnnVectorQueryBuilder( + "my_vector", + new float[] { 1, 1, 1, 1, 1 }, + 10, + 10, + IVF_FORMAT.isEnabled() ? 10f : null, + null, + null + ); IndexRequestBuilder indexRequestBuilder = prepareIndex("index1").setId("knn_query1") .setSource(jsonBuilder().startObject().field("my_query", knnVectorQueryBuilder).endObject()); diff --git a/server/src/internalClusterTest/java/org/elasticsearch/index/store/DirectIOIT.java b/server/src/internalClusterTest/java/org/elasticsearch/index/store/DirectIOIT.java index e27ba0e141491..13be29a720611 100644 --- a/server/src/internalClusterTest/java/org/elasticsearch/index/store/DirectIOIT.java +++ b/server/src/internalClusterTest/java/org/elasticsearch/index/store/DirectIOIT.java @@ -36,6 +36,7 @@ import java.util.OptionalLong; import java.util.stream.IntStream; +import static org.elasticsearch.index.mapper.vectors.DenseVectorFieldMapper.IVF_FORMAT; import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked; import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertHitCount; import static org.hamcrest.Matchers.equalTo; @@ -124,7 +125,17 @@ public void testDirectIOUsed() { indexVectors(); // do a search - var knn = List.of(new KnnSearchBuilder("fooVector", new VectorData(null, new byte[64]), 10, 20, 10f, null, null)); + var knn = List.of( + new KnnSearchBuilder( + "fooVector", + new VectorData(null, new byte[64]), + 10, + 20, + IVF_FORMAT.isEnabled() ? 10f : null, + null, + null + ) + ); assertHitCount(prepareSearch("foo-vectors").setKnnSearch(knn), 10); mockLog.assertAllExpectationsMatched(); } diff --git a/server/src/internalClusterTest/java/org/elasticsearch/search/KnnSearchIT.java b/server/src/internalClusterTest/java/org/elasticsearch/search/KnnSearchIT.java index 17d6024145e22..3db790ce02973 100644 --- a/server/src/internalClusterTest/java/org/elasticsearch/search/KnnSearchIT.java +++ b/server/src/internalClusterTest/java/org/elasticsearch/search/KnnSearchIT.java @@ -24,6 +24,7 @@ import java.util.List; +import static org.elasticsearch.index.mapper.vectors.DenseVectorFieldMapper.IVF_FORMAT; import static org.hamcrest.Matchers.notNullValue; @ESIntegTestCase.ClusterScope(minNumDataNodes = 2) @@ -77,13 +78,17 @@ public void testKnnSearchWithScroll() throws Exception { // test top level knn search { SearchSourceBuilder sourceBuilder = new SearchSourceBuilder(); - sourceBuilder.knnSearch(List.of(new KnnSearchBuilder(VECTOR_FIELD, new float[] { 0, 0 }, k, 100, 10f, null, null))); + sourceBuilder.knnSearch( + List.of(new KnnSearchBuilder(VECTOR_FIELD, new float[] { 0, 0 }, k, 100, IVF_FORMAT.isEnabled() ? 10f : null, null, null)) + ); executeScrollSearch(client, sourceBuilder, k); } // test top level knn search + another query { SearchSourceBuilder sourceBuilder = new SearchSourceBuilder(); - sourceBuilder.knnSearch(List.of(new KnnSearchBuilder(VECTOR_FIELD, new float[] { 0, 0 }, k, 100, 10f, null, null))); + sourceBuilder.knnSearch( + List.of(new KnnSearchBuilder(VECTOR_FIELD, new float[] { 0, 0 }, k, 100, IVF_FORMAT.isEnabled() ? 10f : null, null, null)) + ); sourceBuilder.query(QueryBuilders.existsQuery("category").boost(10)); executeScrollSearch(client, sourceBuilder, k + 10); } @@ -91,7 +96,9 @@ public void testKnnSearchWithScroll() throws Exception { // test knn query { SearchSourceBuilder sourceBuilder = new SearchSourceBuilder(); - sourceBuilder.query(new KnnVectorQueryBuilder(VECTOR_FIELD, new float[] { 0, 0 }, k, 100, 10f, null, null)); + sourceBuilder.query( + new KnnVectorQueryBuilder(VECTOR_FIELD, new float[] { 0, 0 }, k, 100, IVF_FORMAT.isEnabled() ? 10f : null, null, null) + ); executeScrollSearch(client, sourceBuilder, k * numShards); } // test knn query + another query @@ -99,7 +106,17 @@ public void testKnnSearchWithScroll() throws Exception { SearchSourceBuilder sourceBuilder = new SearchSourceBuilder(); sourceBuilder.query( QueryBuilders.boolQuery() - .should(new KnnVectorQueryBuilder(VECTOR_FIELD, new float[] { 0, 0 }, k, 100, 10f, null, null)) + .should( + new KnnVectorQueryBuilder( + VECTOR_FIELD, + new float[] { 0, 0 }, + k, + 100, + IVF_FORMAT.isEnabled() ? 10f : null, + null, + null + ) + ) .should(QueryBuilders.existsQuery("category").boost(10)) ); executeScrollSearch(client, sourceBuilder, k * numShards + 10); diff --git a/server/src/internalClusterTest/java/org/elasticsearch/search/nested/VectorNestedIT.java b/server/src/internalClusterTest/java/org/elasticsearch/search/nested/VectorNestedIT.java index 0ff2b7336e654..b14d7a6f2c4f5 100644 --- a/server/src/internalClusterTest/java/org/elasticsearch/search/nested/VectorNestedIT.java +++ b/server/src/internalClusterTest/java/org/elasticsearch/search/nested/VectorNestedIT.java @@ -19,6 +19,7 @@ import java.util.List; import java.util.Map; +import static org.elasticsearch.index.mapper.vectors.DenseVectorFieldMapper.IVF_FORMAT; import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked; import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertHitCount; import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertNoFailuresAndResponse; @@ -73,7 +74,8 @@ public void testSimpleNested() throws Exception { assertResponse( prepareSearch("test").setKnnSearch( List.of( - new KnnSearchBuilder("nested.vector", new float[] { 1, 1, 1 }, 1, 1, 10f, null, null).innerHit(new InnerHitBuilder()) + new KnnSearchBuilder("nested.vector", new float[] { 1, 1, 1 }, 1, 1, IVF_FORMAT.isEnabled() ? 10f : null, null, null) + .innerHit(new InnerHitBuilder()) ) ).setAllowPartialSearchResults(false), response -> assertThat(response.getHits().getHits().length, greaterThan(0)) @@ -155,7 +157,15 @@ private void testNestedWithTwoSegments(boolean flush) { waitForRelocation(ClusterHealthStatus.GREEN); refresh(); - var knn = new KnnSearchBuilder("nested.vector", new float[] { -0.5f, 90.0f, -10f, 14.8f, -156.0f }, 2, 3, 10f, null, null); + var knn = new KnnSearchBuilder( + "nested.vector", + new float[] { -0.5f, 90.0f, -10f, 14.8f, -156.0f }, + 2, + 3, + IVF_FORMAT.isEnabled() ? 10f : null, + null, + null + ); var request = prepareSearch("test").addFetchField("name").setKnnSearch(List.of(knn)); assertNoFailuresAndResponse(request, response -> { assertHitCount(response, 2); diff --git a/server/src/internalClusterTest/java/org/elasticsearch/search/profile/dfs/DfsProfilerIT.java b/server/src/internalClusterTest/java/org/elasticsearch/search/profile/dfs/DfsProfilerIT.java index c84e955ec8ce5..5914f3d6e2f68 100644 --- a/server/src/internalClusterTest/java/org/elasticsearch/search/profile/dfs/DfsProfilerIT.java +++ b/server/src/internalClusterTest/java/org/elasticsearch/search/profile/dfs/DfsProfilerIT.java @@ -27,6 +27,7 @@ import java.util.List; import java.util.Map; +import static org.elasticsearch.index.mapper.vectors.DenseVectorFieldMapper.IVF_FORMAT; import static org.elasticsearch.search.profile.query.RandomQueryGenerator.randomQueryBuilder; import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked; import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertResponse; @@ -72,7 +73,7 @@ public void testProfileDfs() throws Exception { new float[] { randomFloat(), randomFloat(), randomFloat() }, randomIntBetween(5, 10), 50, - 10f, + IVF_FORMAT.isEnabled() ? 10f : null, randomBoolean() ? null : new RescoreVectorBuilder(randomFloatBetween(1.0f, 10.0f, false)), randomBoolean() ? null : randomFloat() ); diff --git a/server/src/internalClusterTest/java/org/elasticsearch/search/query/RescoreKnnVectorQueryIT.java b/server/src/internalClusterTest/java/org/elasticsearch/search/query/RescoreKnnVectorQueryIT.java index efffcb6951ae2..eeb035445a151 100644 --- a/server/src/internalClusterTest/java/org/elasticsearch/search/query/RescoreKnnVectorQueryIT.java +++ b/server/src/internalClusterTest/java/org/elasticsearch/search/query/RescoreKnnVectorQueryIT.java @@ -49,6 +49,7 @@ import java.util.function.Function; import java.util.stream.Collectors; +import static org.elasticsearch.index.mapper.vectors.DenseVectorFieldMapper.IVF_FORMAT; import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertHitCount; import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertNoFailuresAndResponse; import static org.hamcrest.Matchers.equalTo; @@ -129,7 +130,7 @@ public static TestParams generate() { randomVector(numDims), k, (int) (k * randomFloatBetween(1.0f, 10.0f, true)), - randomBoolean() ? null : randomFloatBetween(0.0f, 100.0f, true), + IVF_FORMAT.isEnabled() == false ? null : randomBoolean() ? null : randomFloatBetween(0.0f, 100.0f, true), new RescoreVectorBuilder(randomFloatBetween(1.0f, 100f, true)) ); } diff --git a/server/src/internalClusterTest/java/org/elasticsearch/search/retriever/RetrieverTelemetryIT.java b/server/src/internalClusterTest/java/org/elasticsearch/search/retriever/RetrieverTelemetryIT.java index 0996c5e3976c0..0b8ea3ec10239 100644 --- a/server/src/internalClusterTest/java/org/elasticsearch/search/retriever/RetrieverTelemetryIT.java +++ b/server/src/internalClusterTest/java/org/elasticsearch/search/retriever/RetrieverTelemetryIT.java @@ -27,6 +27,7 @@ import java.io.IOException; import java.util.List; +import static org.elasticsearch.index.mapper.vectors.DenseVectorFieldMapper.IVF_FORMAT; import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked; import static org.hamcrest.Matchers.equalTo; @@ -84,7 +85,9 @@ public void testTelemetryForRetrievers() throws IOException { // search#1 - this will record 1 entry for "retriever" in `sections`, and 1 for "knn" under `retrievers` { performSearch( - new SearchSourceBuilder().retriever(new KnnRetrieverBuilder("vector", new float[] { 1.0f }, null, 10, 15, 10f, null, null)) + new SearchSourceBuilder().retriever( + new KnnRetrieverBuilder("vector", new float[] { 1.0f }, null, 10, 15, IVF_FORMAT.isEnabled() ? 10f : null, null, null) + ) ); } @@ -99,7 +102,9 @@ public void testTelemetryForRetrievers() throws IOException { { performSearch( new SearchSourceBuilder().retriever( - new StandardRetrieverBuilder(new KnnVectorQueryBuilder("vector", new float[] { 1.0f }, 10, 15, 10f, null, null)) + new StandardRetrieverBuilder( + new KnnVectorQueryBuilder("vector", new float[] { 1.0f }, 10, 15, IVF_FORMAT.isEnabled() ? 10f : null, null, null) + ) ) ); } @@ -114,7 +119,9 @@ public void testTelemetryForRetrievers() throws IOException { // his will record 1 entry for "knn" in `sections` { performSearch( - new SearchSourceBuilder().knnSearch(List.of(new KnnSearchBuilder("vector", new float[] { 1.0f }, 10, 15, 10f, null, null))) + new SearchSourceBuilder().knnSearch( + List.of(new KnnSearchBuilder("vector", new float[] { 1.0f }, 10, 15, IVF_FORMAT.isEnabled() ? 10f : null, null, null)) + ) ); } diff --git a/server/src/main/java/org/elasticsearch/search/retriever/KnnRetrieverBuilder.java b/server/src/main/java/org/elasticsearch/search/retriever/KnnRetrieverBuilder.java index 862299c5cae1e..b05afe6418195 100644 --- a/server/src/main/java/org/elasticsearch/search/retriever/KnnRetrieverBuilder.java +++ b/server/src/main/java/org/elasticsearch/search/retriever/KnnRetrieverBuilder.java @@ -286,7 +286,7 @@ public void doToXContent(XContentBuilder builder, Params params) throws IOExcept builder.field(K_FIELD.getPreferredName(), k); builder.field(NUM_CANDS_FIELD.getPreferredName(), numCands); - if (visitPercentage != null) { + if (IVF_FORMAT.isEnabled() && visitPercentage != null) { builder.field(VISIT_PERCENTAGE_FIELD.getPreferredName(), visitPercentage); } diff --git a/server/src/main/java/org/elasticsearch/search/vectors/KnnSearchBuilder.java b/server/src/main/java/org/elasticsearch/search/vectors/KnnSearchBuilder.java index f455797e68d12..92256460f2c71 100644 --- a/server/src/main/java/org/elasticsearch/search/vectors/KnnSearchBuilder.java +++ b/server/src/main/java/org/elasticsearch/search/vectors/KnnSearchBuilder.java @@ -562,7 +562,7 @@ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws builder.field(K_FIELD.getPreferredName(), k); builder.field(NUM_CANDS_FIELD.getPreferredName(), numCands); - if (visitPercentage != null) { + if (IVF_FORMAT.isEnabled() && visitPercentage != null) { builder.field(VISIT_PERCENTAGE_FIELD.getPreferredName(), visitPercentage); } diff --git a/server/src/test/java/org/elasticsearch/action/search/DfsQueryPhaseTests.java b/server/src/test/java/org/elasticsearch/action/search/DfsQueryPhaseTests.java index f468c0c346aa5..1070c97430668 100644 --- a/server/src/test/java/org/elasticsearch/action/search/DfsQueryPhaseTests.java +++ b/server/src/test/java/org/elasticsearch/action/search/DfsQueryPhaseTests.java @@ -48,6 +48,7 @@ import java.util.List; import java.util.concurrent.atomic.AtomicReference; +import static org.elasticsearch.index.mapper.vectors.DenseVectorFieldMapper.IVF_FORMAT; import static org.hamcrest.Matchers.hasSize; import static org.hamcrest.Matchers.instanceOf; import static org.mockito.Mockito.mock; @@ -353,8 +354,8 @@ public void testRewriteShardSearchRequestWithRank() { SearchSourceBuilder ssb = new SearchSourceBuilder().query(bm25) .knnSearch( List.of( - new KnnSearchBuilder("vector", new float[] { 0.0f }, 10, 100, 10f, null, null), - new KnnSearchBuilder("vector2", new float[] { 0.0f }, 10, 100, 10f, null, null) + new KnnSearchBuilder("vector", new float[] { 0.0f }, 10, 100, IVF_FORMAT.isEnabled() ? 10f : null, null, null), + new KnnSearchBuilder("vector2", new float[] { 0.0f }, 10, 100, IVF_FORMAT.isEnabled() ? 10f : null, null, null) ) ) .rankBuilder(new TestRankBuilder(100)); diff --git a/server/src/test/java/org/elasticsearch/action/search/KnnSearchSingleNodeTests.java b/server/src/test/java/org/elasticsearch/action/search/KnnSearchSingleNodeTests.java index 0114d1994caf9..133e26da91d7e 100644 --- a/server/src/test/java/org/elasticsearch/action/search/KnnSearchSingleNodeTests.java +++ b/server/src/test/java/org/elasticsearch/action/search/KnnSearchSingleNodeTests.java @@ -26,6 +26,7 @@ import java.io.IOException; import java.util.List; +import static org.elasticsearch.index.mapper.vectors.DenseVectorFieldMapper.IVF_FORMAT; import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertHitCount; import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertResponse; import static org.hamcrest.Matchers.equalTo; @@ -63,7 +64,8 @@ public void testKnnSearchRemovedVector() throws IOException { client().prepareUpdate("index", "0").setDoc("vector", (Object) null).setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE).get(); float[] queryVector = randomVector(); - KnnSearchBuilder knnSearch = new KnnSearchBuilder("vector", queryVector, 20, 50, 10f, null, null).boost(5.0f); + KnnSearchBuilder knnSearch = new KnnSearchBuilder("vector", queryVector, 20, 50, IVF_FORMAT.isEnabled() ? 10f : null, null, null) + .boost(5.0f); assertResponse( client().prepareSearch("index") .setKnnSearch(List.of(knnSearch)) @@ -107,7 +109,9 @@ public void testKnnWithQuery() throws IOException { indicesAdmin().prepareRefresh("index").get(); float[] queryVector = randomVector(); - KnnSearchBuilder knnSearch = new KnnSearchBuilder("vector", queryVector, 5, 50, 10f, null, null).boost(5.0f).queryName("knn"); + KnnSearchBuilder knnSearch = new KnnSearchBuilder("vector", queryVector, 5, 50, IVF_FORMAT.isEnabled() ? 10f : null, null, null) + .boost(5.0f) + .queryName("knn"); assertResponse( client().prepareSearch("index") .setKnnSearch(List.of(knnSearch)) @@ -156,9 +160,8 @@ public void testKnnFilter() throws IOException { indicesAdmin().prepareRefresh("index").get(); float[] queryVector = randomVector(); - KnnSearchBuilder knnSearch = new KnnSearchBuilder("vector", queryVector, 5, 50, 10f, null, null).addFilterQuery( - QueryBuilders.termsQuery("field", "second") - ); + KnnSearchBuilder knnSearch = new KnnSearchBuilder("vector", queryVector, 5, 50, IVF_FORMAT.isEnabled() ? 10f : null, null, null) + .addFilterQuery(QueryBuilders.termsQuery("field", "second")); assertResponse(client().prepareSearch("index").setKnnSearch(List.of(knnSearch)).addFetchField("*").setSize(10), response -> { assertHitCount(response, 5); assertEquals(5, response.getHits().getHits().length); @@ -199,9 +202,8 @@ public void testKnnFilterWithRewrite() throws IOException { indicesAdmin().prepareRefresh("index").get(); float[] queryVector = randomVector(); - KnnSearchBuilder knnSearch = new KnnSearchBuilder("vector", queryVector, 5, 50, 10f, null, null).addFilterQuery( - QueryBuilders.termsLookupQuery("field", new TermsLookup("index", "lookup-doc", "other-field")) - ); + KnnSearchBuilder knnSearch = new KnnSearchBuilder("vector", queryVector, 5, 50, IVF_FORMAT.isEnabled() ? 10f : null, null, null) + .addFilterQuery(QueryBuilders.termsLookupQuery("field", new TermsLookup("index", "lookup-doc", "other-field"))); assertResponse(client().prepareSearch("index").setKnnSearch(List.of(knnSearch)).setSize(10), response -> { assertHitCount(response, 5); assertEquals(5, response.getHits().getHits().length); @@ -246,8 +248,10 @@ public void testMultiKnnClauses() throws IOException { indicesAdmin().prepareRefresh("index").get(); float[] queryVector = randomVector(20f, 21f); - KnnSearchBuilder knnSearch = new KnnSearchBuilder("vector", queryVector, 5, 50, 10f, null, null).boost(5.0f); - KnnSearchBuilder knnSearch2 = new KnnSearchBuilder("vector_2", queryVector, 5, 50, 10f, null, null).boost(10.0f); + KnnSearchBuilder knnSearch = new KnnSearchBuilder("vector", queryVector, 5, 50, IVF_FORMAT.isEnabled() ? 10f : null, null, null) + .boost(5.0f); + KnnSearchBuilder knnSearch2 = new KnnSearchBuilder("vector_2", queryVector, 5, 50, IVF_FORMAT.isEnabled() ? 10f : null, null, null) + .boost(10.0f); assertResponse( client().prepareSearch("index") .setKnnSearch(List.of(knnSearch, knnSearch2)) @@ -308,8 +312,8 @@ public void testMultiKnnClausesSameDoc() throws IOException { float[] queryVector = randomVector(); // Having the same query vector and same docs should mean our KNN scores are linearly combined if the same doc is matched - KnnSearchBuilder knnSearch = new KnnSearchBuilder("vector", queryVector, 5, 50, 10f, null, null); - KnnSearchBuilder knnSearch2 = new KnnSearchBuilder("vector_2", queryVector, 5, 50, 10f, null, null); + KnnSearchBuilder knnSearch = new KnnSearchBuilder("vector", queryVector, 5, 50, IVF_FORMAT.isEnabled() ? 10f : null, null, null); + KnnSearchBuilder knnSearch2 = new KnnSearchBuilder("vector_2", queryVector, 5, 50, IVF_FORMAT.isEnabled() ? 10f : null, null, null); assertResponse( client().prepareSearch("index") .setKnnSearch(List.of(knnSearch)) @@ -383,7 +387,7 @@ public void testKnnFilteredAlias() throws IOException { indicesAdmin().prepareRefresh("index").get(); float[] queryVector = randomVector(); - KnnSearchBuilder knnSearch = new KnnSearchBuilder("vector", queryVector, 10, 50, 10f, null, null); + KnnSearchBuilder knnSearch = new KnnSearchBuilder("vector", queryVector, 10, 50, IVF_FORMAT.isEnabled() ? 10f : null, null, null); final int expectedHitCount = expectedHits; assertResponse(client().prepareSearch("test-alias").setKnnSearch(List.of(knnSearch)).setSize(10), response -> { assertHitCount(response, expectedHitCount); @@ -420,7 +424,7 @@ public void testKnnSearchAction() throws IOException { float[] queryVector = randomVector(); assertResponse( client().prepareSearch("index1", "index2") - .setQuery(new KnnVectorQueryBuilder("vector", queryVector, 5, 5, 10f, null, null)) + .setQuery(new KnnVectorQueryBuilder("vector", queryVector, 5, 5, IVF_FORMAT.isEnabled() ? 10f : null, null, null)) .setSize(2), response -> { // The total hits is num_cands * num_shards, since the query gathers num_cands hits from each shard @@ -454,7 +458,8 @@ public void testKnnVectorsWith4096Dims() throws IOException { indicesAdmin().prepareRefresh("index").get(); float[] queryVector = randomVector(4096); - KnnSearchBuilder knnSearch = new KnnSearchBuilder("vector", queryVector, 3, 50, 10f, null, null).boost(5.0f); + KnnSearchBuilder knnSearch = new KnnSearchBuilder("vector", queryVector, 3, 50, IVF_FORMAT.isEnabled() ? 10f : null, null, null) + .boost(5.0f); assertResponse(client().prepareSearch("index").setKnnSearch(List.of(knnSearch)).addFetchField("*").setSize(10), response -> { assertHitCount(response, 3); assertEquals(3, response.getHits().getHits().length); diff --git a/server/src/test/java/org/elasticsearch/action/search/SearchRequestTests.java b/server/src/test/java/org/elasticsearch/action/search/SearchRequestTests.java index 25c4c1672e852..a377a59ed796e 100644 --- a/server/src/test/java/org/elasticsearch/action/search/SearchRequestTests.java +++ b/server/src/test/java/org/elasticsearch/action/search/SearchRequestTests.java @@ -48,6 +48,7 @@ import java.util.List; import static java.util.Collections.emptyMap; +import static org.elasticsearch.index.mapper.vectors.DenseVectorFieldMapper.IVF_FORMAT; import static org.elasticsearch.test.EqualsHashCodeTestUtils.checkEqualsAndHashCode; import static org.hamcrest.Matchers.equalTo; @@ -120,7 +121,7 @@ public void testSerializationMultiKNN() throws Exception { new float[] { 1, 2 }, 5, 10, - 10f, + IVF_FORMAT.isEnabled() ? 10f : null, randomRescoreVectorBuilder(), randomBoolean() ? null : randomFloat() ), @@ -129,7 +130,7 @@ public void testSerializationMultiKNN() throws Exception { new float[] { 4, 12, 41 }, 3, 5, - 10f, + IVF_FORMAT.isEnabled() ? 10f : null, randomRescoreVectorBuilder(), randomBoolean() ? null : randomFloat() ) @@ -153,7 +154,7 @@ public void testSerializationMultiKNN() throws Exception { new float[] { 1, 2 }, 5, 10, - 10f, + IVF_FORMAT.isEnabled() ? 10f : null, randomRescoreVectorBuilder(), randomBoolean() ? null : randomFloat() ) @@ -477,7 +478,11 @@ public QueryBuilder topDocsQuery() { SearchRequest searchRequest = new SearchRequest().source( new SearchSourceBuilder().rankBuilder(new TestRankBuilder(100)) .query(QueryBuilders.termQuery("field", "term")) - .knnSearch(List.of(new KnnSearchBuilder("vector", new float[] { 0f }, 10, 100, 10f, null, null))) + .knnSearch( + List.of( + new KnnSearchBuilder("vector", new float[] { 0f }, 10, 100, IVF_FORMAT.isEnabled() ? 10f : null, null, null) + ) + ) .size(0) ); ActionRequestValidationException validationErrors = searchRequest.validate(); @@ -489,7 +494,11 @@ public QueryBuilder topDocsQuery() { SearchRequest searchRequest = new SearchRequest().source( new SearchSourceBuilder().rankBuilder(new TestRankBuilder(1)) .query(QueryBuilders.termQuery("field", "term")) - .knnSearch(List.of(new KnnSearchBuilder("vector", new float[] { 0f }, 10, 100, 10f, null, null))) + .knnSearch( + List.of( + new KnnSearchBuilder("vector", new float[] { 0f }, 10, 100, IVF_FORMAT.isEnabled() ? 10f : null, null, null) + ) + ) .size(2) ); ActionRequestValidationException validationErrors = searchRequest.validate(); @@ -516,7 +525,11 @@ public QueryBuilder topDocsQuery() { SearchRequest searchRequest = new SearchRequest().source( new SearchSourceBuilder().rankBuilder(new TestRankBuilder(100)) .query(QueryBuilders.termQuery("field", "term")) - .knnSearch(List.of(new KnnSearchBuilder("vector", new float[] { 0f }, 10, 100, 10f, null, null))) + .knnSearch( + List.of( + new KnnSearchBuilder("vector", new float[] { 0f }, 10, 100, IVF_FORMAT.isEnabled() ? 10f : null, null, null) + ) + ) ).scroll(new TimeValue(1000)); ActionRequestValidationException validationErrors = searchRequest.validate(); assertNotNull(validationErrors); @@ -527,7 +540,11 @@ public QueryBuilder topDocsQuery() { SearchRequest searchRequest = new SearchRequest().source( new SearchSourceBuilder().rankBuilder(new TestRankBuilder(9)) .query(QueryBuilders.termQuery("field", "term")) - .knnSearch(List.of(new KnnSearchBuilder("vector", new float[] { 0f }, 10, 100, 10f, null, null))) + .knnSearch( + List.of( + new KnnSearchBuilder("vector", new float[] { 0f }, 10, 100, IVF_FORMAT.isEnabled() ? 10f : null, null, null) + ) + ) ); ActionRequestValidationException validationErrors = searchRequest.validate(); assertNotNull(validationErrors); @@ -541,7 +558,11 @@ public QueryBuilder topDocsQuery() { SearchRequest searchRequest = new SearchRequest().source( new SearchSourceBuilder().rankBuilder(new TestRankBuilder(3)) .query(QueryBuilders.termQuery("field", "term")) - .knnSearch(List.of(new KnnSearchBuilder("vector", new float[] { 0f }, 10, 100, 10f, null, null))) + .knnSearch( + List.of( + new KnnSearchBuilder("vector", new float[] { 0f }, 10, 100, IVF_FORMAT.isEnabled() ? 10f : null, null, null) + ) + ) .size(3) .from(4) ); @@ -552,7 +573,11 @@ public QueryBuilder topDocsQuery() { SearchRequest searchRequest = new SearchRequest().source( new SearchSourceBuilder().rankBuilder(new TestRankBuilder(100)) .query(QueryBuilders.termQuery("field", "term")) - .knnSearch(List.of(new KnnSearchBuilder("vector", new float[] { 0f }, 10, 100, 10f, null, null))) + .knnSearch( + List.of( + new KnnSearchBuilder("vector", new float[] { 0f }, 10, 100, IVF_FORMAT.isEnabled() ? 10f : null, null, null) + ) + ) .addRescorer(new QueryRescorerBuilder(QueryBuilders.termQuery("rescore", "another term"))) ); ActionRequestValidationException validationErrors = searchRequest.validate(); @@ -564,7 +589,11 @@ public QueryBuilder topDocsQuery() { SearchRequest searchRequest = new SearchRequest().source( new SearchSourceBuilder().rankBuilder(new TestRankBuilder(100)) .query(QueryBuilders.termQuery("field", "term")) - .knnSearch(List.of(new KnnSearchBuilder("vector", new float[] { 0f }, 10, 100, 10f, null, null))) + .knnSearch( + List.of( + new KnnSearchBuilder("vector", new float[] { 0f }, 10, 100, IVF_FORMAT.isEnabled() ? 10f : null, null, null) + ) + ) .suggest(new SuggestBuilder().setGlobalText("test").addSuggestion("suggestion", new TermSuggestionBuilder("term"))) ); ActionRequestValidationException validationErrors = searchRequest.validate(); diff --git a/server/src/test/java/org/elasticsearch/action/search/TransportSearchActionTests.java b/server/src/test/java/org/elasticsearch/action/search/TransportSearchActionTests.java index 21d21acd7f9a2..b15c80d907523 100644 --- a/server/src/test/java/org/elasticsearch/action/search/TransportSearchActionTests.java +++ b/server/src/test/java/org/elasticsearch/action/search/TransportSearchActionTests.java @@ -122,6 +122,7 @@ import java.util.function.Function; import static org.elasticsearch.action.search.SearchRequest.DEFAULT_PRE_FILTER_SHARD_SIZE; +import static org.elasticsearch.index.mapper.vectors.DenseVectorFieldMapper.IVF_FORMAT; import static org.elasticsearch.test.InternalAggregationTestCase.emptyReduceContextBuilder; import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.awaitLatch; import static org.hamcrest.CoreMatchers.containsString; @@ -1395,7 +1396,9 @@ public void testShouldMinimizeRoundtrips() throws Exception { { SearchRequest searchRequest = new SearchRequest(); SearchSourceBuilder source = new SearchSourceBuilder(); - source.knnSearch(List.of(new KnnSearchBuilder("field", new float[] { 1, 2, 3 }, 10, 50, 10f, null, null))); + source.knnSearch( + List.of(new KnnSearchBuilder("field", new float[] { 1, 2, 3 }, 10, 50, IVF_FORMAT.isEnabled() ? 10f : null, null, null)) + ); searchRequest.source(source); searchRequest.setCcsMinimizeRoundtrips(true); @@ -1410,7 +1413,9 @@ public void testAdjustSearchType() { // If the search includes kNN, we should always use DFS_QUERY_THEN_FETCH SearchRequest searchRequest = new SearchRequest(); SearchSourceBuilder source = new SearchSourceBuilder(); - source.knnSearch(List.of(new KnnSearchBuilder("field", new float[] { 1, 2, 3 }, 10, 50, 10f, null, null))); + source.knnSearch( + List.of(new KnnSearchBuilder("field", new float[] { 1, 2, 3 }, 10, 50, IVF_FORMAT.isEnabled() ? 10f : null, null, null)) + ); searchRequest.source(source); TransportSearchAction.adjustSearchType(searchRequest, randomBoolean()); diff --git a/server/src/test/java/org/elasticsearch/index/mapper/vectors/DenseVectorFieldMapperTests.java b/server/src/test/java/org/elasticsearch/index/mapper/vectors/DenseVectorFieldMapperTests.java index c69dc264eb076..98f1dd3216ebc 100644 --- a/server/src/test/java/org/elasticsearch/index/mapper/vectors/DenseVectorFieldMapperTests.java +++ b/server/src/test/java/org/elasticsearch/index/mapper/vectors/DenseVectorFieldMapperTests.java @@ -2555,7 +2555,7 @@ public void testByteVectorQueryBoundaries() throws IOException { VectorData.fromFloats(new float[] { 128, 0, 0 }), 3, 3, - 10f, + IVF_FORMAT.isEnabled() ? 10f : null, null, null, null, @@ -2575,7 +2575,7 @@ public void testByteVectorQueryBoundaries() throws IOException { VectorData.fromFloats(new float[] { 0.0f, 0f, -129.0f }), 3, 3, - 10f, + IVF_FORMAT.isEnabled() ? 10f : null, null, null, null, @@ -2595,7 +2595,7 @@ public void testByteVectorQueryBoundaries() throws IOException { VectorData.fromFloats(new float[] { 0.0f, 0.5f, 0.0f }), 3, 3, - 10f, + IVF_FORMAT.isEnabled() ? 10f : null, null, null, null, @@ -2615,7 +2615,7 @@ public void testByteVectorQueryBoundaries() throws IOException { VectorData.fromFloats(new float[] { 0, 0.0f, -0.25f }), 3, 3, - 10f, + IVF_FORMAT.isEnabled() ? 10f : null, null, null, null, @@ -2635,7 +2635,7 @@ public void testByteVectorQueryBoundaries() throws IOException { VectorData.fromFloats(new float[] { Float.NaN, 0f, 0.0f }), 3, 3, - 10f, + IVF_FORMAT.isEnabled() ? 10f : null, null, null, null, @@ -2652,7 +2652,7 @@ public void testByteVectorQueryBoundaries() throws IOException { VectorData.fromFloats(new float[] { Float.POSITIVE_INFINITY, 0f, 0.0f }), 3, 3, - 10f, + IVF_FORMAT.isEnabled() ? 10f : null, null, null, null, @@ -2672,7 +2672,7 @@ public void testByteVectorQueryBoundaries() throws IOException { VectorData.fromFloats(new float[] { 0, Float.NEGATIVE_INFINITY, 0.0f }), 3, 3, - 10f, + IVF_FORMAT.isEnabled() ? 10f : null, null, null, null, @@ -2709,7 +2709,7 @@ public void testFloatVectorQueryBoundaries() throws IOException { VectorData.fromFloats(new float[] { Float.NaN, 0f, 0.0f }), 3, 3, - 10f, + IVF_FORMAT.isEnabled() ? 10f : null, null, null, null, @@ -2726,7 +2726,7 @@ public void testFloatVectorQueryBoundaries() throws IOException { VectorData.fromFloats(new float[] { Float.POSITIVE_INFINITY, 0f, 0.0f }), 3, 3, - 10f, + IVF_FORMAT.isEnabled() ? 10f : null, null, null, null, @@ -2746,7 +2746,7 @@ public void testFloatVectorQueryBoundaries() throws IOException { VectorData.fromFloats(new float[] { 0, Float.NEGATIVE_INFINITY, 0.0f }), 3, 3, - 10f, + IVF_FORMAT.isEnabled() ? 10f : null, null, null, null, diff --git a/server/src/test/java/org/elasticsearch/index/mapper/vectors/DenseVectorFieldTypeTests.java b/server/src/test/java/org/elasticsearch/index/mapper/vectors/DenseVectorFieldTypeTests.java index 816551102beca..82ac6a76f5adf 100644 --- a/server/src/test/java/org/elasticsearch/index/mapper/vectors/DenseVectorFieldTypeTests.java +++ b/server/src/test/java/org/elasticsearch/index/mapper/vectors/DenseVectorFieldTypeTests.java @@ -253,7 +253,7 @@ public void testCreateNestedKnnQuery() { VectorData.fromFloats(queryVector), 10, 10, - 10f, + IVF_FORMAT.isEnabled() ? 10f : null, null, null, null, @@ -297,7 +297,7 @@ public void testCreateNestedKnnQuery() { vectorData, 10, 10, - 10f, + IVF_FORMAT.isEnabled() ? 10f : null, null, null, null, @@ -316,7 +316,7 @@ public void testCreateNestedKnnQuery() { vectorData, 10, 10, - 10f, + IVF_FORMAT.isEnabled() ? 10f : null, null, null, null, @@ -395,7 +395,7 @@ public void testFloatCreateKnnQuery() { VectorData.fromFloats(new float[] { 0.3f, 0.1f, 1.0f, 0.0f }), 10, 10, - 10f, + IVF_FORMAT.isEnabled() ? 10f : null, null, null, null, @@ -427,7 +427,7 @@ public void testFloatCreateKnnQuery() { VectorData.fromFloats(queryVector), 10, 10, - 10f, + IVF_FORMAT.isEnabled() ? 10f : null, null, null, null, @@ -455,7 +455,7 @@ public void testFloatCreateKnnQuery() { VectorData.fromFloats(new float[BBQ_MIN_DIMS]), 10, 10, - 10f, + IVF_FORMAT.isEnabled() ? 10f : null, null, null, null, @@ -488,7 +488,7 @@ public void testCreateKnnQueryMaxDims() { VectorData.fromFloats(queryVector), 10, 10, - 10f, + IVF_FORMAT.isEnabled() ? 10f : null, null, null, null, @@ -531,7 +531,7 @@ public void testCreateKnnQueryMaxDims() { vectorData, 10, 10, - 10f, + IVF_FORMAT.isEnabled() ? 10f : null, null, null, null, @@ -565,7 +565,7 @@ public void testByteCreateKnnQuery() { VectorData.fromFloats(new float[] { 0.3f, 0.1f, 1.0f }), 10, 10, - 10f, + IVF_FORMAT.isEnabled() ? 10f : null, null, null, null, @@ -593,7 +593,7 @@ public void testByteCreateKnnQuery() { VectorData.fromFloats(new float[] { 0.0f, 0.0f, 0.0f }), 10, 10, - 10f, + IVF_FORMAT.isEnabled() ? 10f : null, null, null, null, @@ -610,7 +610,7 @@ public void testByteCreateKnnQuery() { new VectorData(null, new byte[] { 0, 0, 0 }), 10, 10, - 10f, + IVF_FORMAT.isEnabled() ? 10f : null, null, null, null, @@ -640,7 +640,7 @@ public void testRescoreOversampleUsedWithoutQuantization() { new VectorData(null, new byte[] { 1, 4, 10 }), 10, 100, - 10f, + IVF_FORMAT.isEnabled() ? 10f : null, randomFloatBetween(1.0F, 10.0F, false), null, null, @@ -690,11 +690,20 @@ public void testRescoreOversampleModifiesNumCandidates() { ); // Total results is k, internal k is multiplied by oversample - checkRescoreQueryParameters(fieldType, 10, 200, 10f, 2.5F, 25, 200, 10); + checkRescoreQueryParameters(fieldType, 10, 200, IVF_FORMAT.isEnabled() ? 10f : null, 2.5F, 25, 200, 10); // If numCands < k, update numCands to k - checkRescoreQueryParameters(fieldType, 10, 20, 10f, 2.5F, 25, 25, 10); + checkRescoreQueryParameters(fieldType, 10, 20, IVF_FORMAT.isEnabled() ? 10f : null, 2.5F, 25, 25, 10); // Oversampling limits for k - checkRescoreQueryParameters(fieldType, 1000, 1000, 10f, 11.0F, OVERSAMPLE_LIMIT, OVERSAMPLE_LIMIT, 1000); + checkRescoreQueryParameters( + fieldType, + 1000, + 1000, + IVF_FORMAT.isEnabled() ? 10f : null, + 11.0F, + OVERSAMPLE_LIMIT, + OVERSAMPLE_LIMIT, + 1000 + ); } public void testRescoreOversampleQueryOverrides() { @@ -714,7 +723,7 @@ public void testRescoreOversampleQueryOverrides() { VectorData.fromFloats(new float[] { 1, 4, 10 }), 10, 100, - 10f, + IVF_FORMAT.isEnabled() ? 10f : null, 0f, null, null, @@ -744,7 +753,7 @@ public void testRescoreOversampleQueryOverrides() { VectorData.fromFloats(new float[] { 1, 4, 10 }), 10, 100, - 10f, + IVF_FORMAT.isEnabled() ? 10f : null, 2f, null, null, @@ -785,7 +794,7 @@ public void testFilterSearchThreshold() { VectorData.fromFloats(new float[] { 1, 4, 10 }), 10, 100, - 10f, + IVF_FORMAT.isEnabled() ? 10f : null, 0f, null, null, @@ -802,7 +811,7 @@ public void testFilterSearchThreshold() { VectorData.fromFloats(new float[] { 1, 4, 10 }), 10, 100, - 10f, + IVF_FORMAT.isEnabled() ? 10f : null, 0f, null, null, diff --git a/server/src/test/java/org/elasticsearch/index/query/NestedQueryBuilderTests.java b/server/src/test/java/org/elasticsearch/index/query/NestedQueryBuilderTests.java index 39520db299f65..87ea001c58106 100644 --- a/server/src/test/java/org/elasticsearch/index/query/NestedQueryBuilderTests.java +++ b/server/src/test/java/org/elasticsearch/index/query/NestedQueryBuilderTests.java @@ -43,6 +43,7 @@ import java.util.Map; import static org.elasticsearch.index.IndexSettingsTests.newIndexMeta; +import static org.elasticsearch.index.mapper.vectors.DenseVectorFieldMapper.IVF_FORMAT; import static org.elasticsearch.index.query.InnerHitBuilderTests.randomNestedInnerHits; import static org.hamcrest.CoreMatchers.containsString; import static org.hamcrest.CoreMatchers.equalTo; @@ -270,7 +271,7 @@ public void testKnnRewriteForInnerHits() throws IOException { new float[] { 1.0f, 2.0f, 3.0f }, null, 1, - 10f, + IVF_FORMAT.isEnabled() ? 10f : null, null, null ); diff --git a/server/src/test/java/org/elasticsearch/rest/action/search/RestSearchActionTests.java b/server/src/test/java/org/elasticsearch/rest/action/search/RestSearchActionTests.java index ef620896e941d..f2099964a4448 100644 --- a/server/src/test/java/org/elasticsearch/rest/action/search/RestSearchActionTests.java +++ b/server/src/test/java/org/elasticsearch/rest/action/search/RestSearchActionTests.java @@ -26,6 +26,7 @@ import java.util.List; import java.util.Map; +import static org.elasticsearch.index.mapper.vectors.DenseVectorFieldMapper.IVF_FORMAT; import static org.mockito.Mockito.mock; public final class RestSearchActionTests extends RestActionTestCase { @@ -83,7 +84,15 @@ public void testValidateSearchRequest() { .build(); SearchRequest searchRequest = new SearchRequest(); - KnnSearchBuilder knnSearch = new KnnSearchBuilder("vector", new float[] { 1, 1, 1 }, 10, 100, 10f, null, null); + KnnSearchBuilder knnSearch = new KnnSearchBuilder( + "vector", + new float[] { 1, 1, 1 }, + 10, + 100, + IVF_FORMAT.isEnabled() ? 10f : null, + null, + null + ); searchRequest.source(new SearchSourceBuilder().knnSearch(List.of(knnSearch))); Exception ex = expectThrows( diff --git a/server/src/test/java/org/elasticsearch/search/builder/SearchSourceBuilderTests.java b/server/src/test/java/org/elasticsearch/search/builder/SearchSourceBuilderTests.java index dc6328862254a..46fde26d4cf4c 100644 --- a/server/src/test/java/org/elasticsearch/search/builder/SearchSourceBuilderTests.java +++ b/server/src/test/java/org/elasticsearch/search/builder/SearchSourceBuilderTests.java @@ -77,6 +77,7 @@ import java.util.function.ToLongFunction; import static java.util.Collections.emptyMap; +import static org.elasticsearch.index.mapper.vectors.DenseVectorFieldMapper.IVF_FORMAT; import static org.hamcrest.CoreMatchers.containsString; import static org.hamcrest.CoreMatchers.instanceOf; import static org.hamcrest.Matchers.equalTo; @@ -826,7 +827,9 @@ public void testSearchSectionsUsageCollection() throws IOException { searchSourceBuilder.fetchField("field"); // these are not correct runtime mappings but they are counted compared to empty object searchSourceBuilder.runtimeMappings(Collections.singletonMap("field", "keyword")); - searchSourceBuilder.knnSearch(List.of(new KnnSearchBuilder("field", new float[] {}, 2, 5, 10f, null, null))); + searchSourceBuilder.knnSearch( + List.of(new KnnSearchBuilder("field", new float[] {}, 2, 5, IVF_FORMAT.isEnabled() ? 10f : null, null, null)) + ); searchSourceBuilder.pointInTimeBuilder(new PointInTimeBuilder(new BytesArray("pitid"))); searchSourceBuilder.docValueField("field"); searchSourceBuilder.storedField("field"); diff --git a/server/src/test/java/org/elasticsearch/search/dfs/DfsPhaseTests.java b/server/src/test/java/org/elasticsearch/search/dfs/DfsPhaseTests.java index ea5e7e6b7a488..34a074f468781 100644 --- a/server/src/test/java/org/elasticsearch/search/dfs/DfsPhaseTests.java +++ b/server/src/test/java/org/elasticsearch/search/dfs/DfsPhaseTests.java @@ -52,6 +52,7 @@ import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.atomic.AtomicLong; +import static org.elasticsearch.index.mapper.vectors.DenseVectorFieldMapper.IVF_FORMAT; import static org.elasticsearch.search.dfs.DfsPhase.executeKnnVectorQuery; public class DfsPhaseTests extends IndexShardTestCase { @@ -156,7 +157,17 @@ public DfsSearchResult dfsResult() { context.request() .source( new SearchSourceBuilder().knnSearch( - List.of(new KnnSearchBuilder("float_vector", new float[] { 0, 0, 0 }, numDocs, numDocs, 100f, null, null)) + List.of( + new KnnSearchBuilder( + "float_vector", + new float[] { 0, 0, 0 }, + numDocs, + numDocs, + IVF_FORMAT.isEnabled() ? 100f : null, + null, + null + ) + ) ) ); context.setTask(new SearchShardTask(123L, "", "", "", null, Collections.emptyMap())); diff --git a/server/src/test/java/org/elasticsearch/search/retriever/KnnRetrieverBuilderParsingTests.java b/server/src/test/java/org/elasticsearch/search/retriever/KnnRetrieverBuilderParsingTests.java index efe08cc62ab6e..2c8c780a712fa 100644 --- a/server/src/test/java/org/elasticsearch/search/retriever/KnnRetrieverBuilderParsingTests.java +++ b/server/src/test/java/org/elasticsearch/search/retriever/KnnRetrieverBuilderParsingTests.java @@ -33,6 +33,7 @@ import java.util.ArrayList; import java.util.List; +import static org.elasticsearch.index.mapper.vectors.DenseVectorFieldMapper.IVF_FORMAT; import static org.elasticsearch.search.vectors.KnnSearchBuilderTests.randomVector; import static org.hamcrest.Matchers.anyOf; import static org.hamcrest.Matchers.equalTo; @@ -52,7 +53,7 @@ public static KnnRetrieverBuilder createRandomKnnRetrieverBuilder() { float[] vector = randomVector(dim); int k = randomIntBetween(1, 100); int numCands = randomIntBetween(k + 20, 1000); - Float visitPercentage = randomBoolean() ? null : randomFloatBetween(0.0f, 100.0f, true); + Float visitPercentage = IVF_FORMAT.isEnabled() == false ? null : randomBoolean() ? null : randomFloatBetween(0.0f, 100.0f, true); Float similarity = randomBoolean() ? null : randomFloat(); RescoreVectorBuilder rescoreVectorBuilder = randomBoolean() ? null diff --git a/server/src/test/java/org/elasticsearch/search/retriever/RankDocsRetrieverBuilderTests.java b/server/src/test/java/org/elasticsearch/search/retriever/RankDocsRetrieverBuilderTests.java index 772088296f76f..1256a6f5d93f8 100644 --- a/server/src/test/java/org/elasticsearch/search/retriever/RankDocsRetrieverBuilderTests.java +++ b/server/src/test/java/org/elasticsearch/search/retriever/RankDocsRetrieverBuilderTests.java @@ -26,6 +26,7 @@ import java.util.List; import java.util.function.Supplier; +import static org.elasticsearch.index.mapper.vectors.DenseVectorFieldMapper.IVF_FORMAT; import static org.elasticsearch.search.vectors.KnnSearchBuilderTests.randomVector; import static org.hamcrest.Matchers.anyOf; import static org.hamcrest.Matchers.equalTo; @@ -70,7 +71,7 @@ private List innerRetrievers(QueryRewriteContext queryRewriteC null, randomInt(10), randomIntBetween(10, 100), - randomBoolean() ? null : randomFloatBetween(0.0f, 100.0f, true), + IVF_FORMAT.isEnabled() == false ? null : randomBoolean() ? null : randomFloatBetween(0.0f, 100.0f, true), randomBoolean() ? null : new RescoreVectorBuilder(randomFloatBetween(1.0f, 10.0f, false)), randomFloat() ); diff --git a/server/src/test/java/org/elasticsearch/search/vectors/AbstractKnnVectorQueryBuilderTestCase.java b/server/src/test/java/org/elasticsearch/search/vectors/AbstractKnnVectorQueryBuilderTestCase.java index c6725e9710f78..3b782031b0490 100644 --- a/server/src/test/java/org/elasticsearch/search/vectors/AbstractKnnVectorQueryBuilderTestCase.java +++ b/server/src/test/java/org/elasticsearch/search/vectors/AbstractKnnVectorQueryBuilderTestCase.java @@ -50,6 +50,7 @@ import java.util.stream.Stream; import static org.elasticsearch.index.mapper.vectors.DenseVectorFieldMapper.DEFAULT_OVERSAMPLE; +import static org.elasticsearch.index.mapper.vectors.DenseVectorFieldMapper.IVF_FORMAT; import static org.elasticsearch.index.mapper.vectors.DenseVectorFieldMapper.OVERSAMPLE_LIMIT; import static org.elasticsearch.search.SearchService.DEFAULT_SIZE; import static org.hamcrest.Matchers.anyOf; @@ -146,7 +147,7 @@ protected KnnVectorQueryBuilder doCreateTestQueryBuilder() { String fieldName = randomBoolean() ? VECTOR_FIELD : VECTOR_ALIAS_FIELD; int k = randomIntBetween(1, 100); int numCands = randomIntBetween(k + 20, 1000); - Float visitPercentage = randomBoolean() ? null : randomFloatBetween(0.0f, 100.0f, true); + Float visitPercentage = IVF_FORMAT.isEnabled() == false ? null : randomBoolean() ? null : randomFloatBetween(0.0f, 100.0f, true); KnnVectorQueryBuilder queryBuilder = createKnnVectorQueryBuilder( fieldName, k, @@ -287,7 +288,15 @@ protected void doAssertLuceneQuery(KnnVectorQueryBuilder queryBuilder, Query que public void testWrongDimension() { SearchExecutionContext context = createSearchExecutionContext(); - KnnVectorQueryBuilder query = new KnnVectorQueryBuilder(VECTOR_FIELD, new float[] { 1.0f, 2.0f }, 5, 10, 10f, null, null); + KnnVectorQueryBuilder query = new KnnVectorQueryBuilder( + VECTOR_FIELD, + new float[] { 1.0f, 2.0f }, + 5, + 10, + IVF_FORMAT.isEnabled() ? 10f : null, + null, + null + ); IllegalArgumentException e = expectThrows(IllegalArgumentException.class, () -> query.doToQuery(context)); assertThat( e.getMessage(), @@ -297,7 +306,15 @@ public void testWrongDimension() { public void testNonexistentField() { SearchExecutionContext context = createSearchExecutionContext(); - KnnVectorQueryBuilder query = new KnnVectorQueryBuilder("nonexistent", new float[] { 1.0f, 1.0f, 1.0f }, 5, 10, 10f, null, null); + KnnVectorQueryBuilder query = new KnnVectorQueryBuilder( + "nonexistent", + new float[] { 1.0f, 1.0f, 1.0f }, + 5, + 10, + IVF_FORMAT.isEnabled() ? 10f : null, + null, + null + ); context.setAllowUnmappedFields(false); QueryShardException e = expectThrows(QueryShardException.class, () -> query.doToQuery(context)); assertThat(e.getMessage(), containsString("No field mapping can be found for the field with name [nonexistent]")); @@ -305,7 +322,15 @@ public void testNonexistentField() { public void testNonexistentFieldReturnEmpty() throws IOException { SearchExecutionContext context = createSearchExecutionContext(); - KnnVectorQueryBuilder query = new KnnVectorQueryBuilder("nonexistent", new float[] { 1.0f, 1.0f, 1.0f }, 5, 10, 10f, null, null); + KnnVectorQueryBuilder query = new KnnVectorQueryBuilder( + "nonexistent", + new float[] { 1.0f, 1.0f, 1.0f }, + 5, + 10, + IVF_FORMAT.isEnabled() ? 10f : null, + null, + null + ); Query queryNone = query.doToQuery(context); assertThat(queryNone, instanceOf(MatchNoDocsQuery.class)); } @@ -317,7 +342,7 @@ public void testWrongFieldType() { new float[] { 1.0f, 1.0f, 1.0f }, 5, 10, - 10f, + IVF_FORMAT.isEnabled() ? 10f : null, null, null ); @@ -330,44 +355,102 @@ public void testNumCandsLessThanK() { int numCands = 3; IllegalArgumentException e = expectThrows( IllegalArgumentException.class, - () -> new KnnVectorQueryBuilder(VECTOR_FIELD, new float[] { 1.0f, 1.0f, 1.0f }, k, numCands, 10f, null, null) + () -> new KnnVectorQueryBuilder( + VECTOR_FIELD, + new float[] { 1.0f, 1.0f, 1.0f }, + k, + numCands, + IVF_FORMAT.isEnabled() ? 10f : null, + null, + null + ) ); assertThat(e.getMessage(), containsString("[num_candidates] cannot be less than [k]")); } @Override public void testValidOutput() { - KnnVectorQueryBuilder query = new KnnVectorQueryBuilder(VECTOR_FIELD, new float[] { 1.0f, 2.0f, 3.0f }, null, 10, 10f, null, null); - String expected = """ - { - "knn" : { - "field" : "vector", - "query_vector" : [ - 1.0, - 2.0, - 3.0 - ], - "num_candidates" : 10, - "visit_percentage" : 10.0 - } - }"""; + KnnVectorQueryBuilder query = new KnnVectorQueryBuilder( + VECTOR_FIELD, + new float[] { 1.0f, 2.0f, 3.0f }, + null, + 10, + IVF_FORMAT.isEnabled() ? 10f : null, + null, + null + ); + + String expected; + if (IVF_FORMAT.isEnabled()) { + expected = """ + { + "knn" : { + "field" : "vector", + "query_vector" : [ + 1.0, + 2.0, + 3.0 + ], + "num_candidates" : 10, + "visit_percentage" : 10.0 + } + }"""; + } else { + expected = """ + { + "knn" : { + "field" : "vector", + "query_vector" : [ + 1.0, + 2.0, + 3.0 + ], + "num_candidates" : 10 + } + }"""; + } assertEquals(expected, query.toString()); - KnnVectorQueryBuilder query2 = new KnnVectorQueryBuilder(VECTOR_FIELD, new float[] { 1.0f, 2.0f, 3.0f }, 5, 10, 10f, null, null); - String expected2 = """ - { - "knn" : { - "field" : "vector", - "query_vector" : [ - 1.0, - 2.0, - 3.0 - ], - "k" : 5, - "num_candidates" : 10, - "visit_percentage" : 10.0 - } - }"""; + KnnVectorQueryBuilder query2 = new KnnVectorQueryBuilder( + VECTOR_FIELD, + new float[] { 1.0f, 2.0f, 3.0f }, + 5, + 10, + IVF_FORMAT.isEnabled() ? 10f : null, + null, + null + ); + String expected2; + if (IVF_FORMAT.isEnabled()) { + expected2 = """ + { + "knn" : { + "field" : "vector", + "query_vector" : [ + 1.0, + 2.0, + 3.0 + ], + "k" : 5, + "num_candidates" : 10, + "visit_percentage" : 10.0 + } + }"""; + } else { + expected2 = """ + { + "knn" : { + "field" : "vector", + "query_vector" : [ + 1.0, + 2.0, + 3.0 + ], + "k" : 5, + "num_candidates" : 10 + } + }"""; + } assertEquals(expected2, query2.toString()); KnnVectorQueryBuilder query3 = new KnnVectorQueryBuilder(VECTOR_FIELD, new float[] { 1.0f, 2.0f, 3.0f }, 5, 10, null, null, null); @@ -537,7 +620,7 @@ public void testRewriteWithQueryVectorBuilder() throws Exception { new TestQueryVectorBuilderPlugin.TestQueryVectorBuilder(expectedArray), null, 5, - 10f, + IVF_FORMAT.isEnabled() ? 10f : null, 1f ); knnVectorQueryBuilder.boost(randomFloat()); diff --git a/server/src/test/java/org/elasticsearch/search/vectors/DiversifyingParentBlockQueryTests.java b/server/src/test/java/org/elasticsearch/search/vectors/DiversifyingParentBlockQueryTests.java index 4d9417c402700..63b1398398cee 100644 --- a/server/src/test/java/org/elasticsearch/search/vectors/DiversifyingParentBlockQueryTests.java +++ b/server/src/test/java/org/elasticsearch/search/vectors/DiversifyingParentBlockQueryTests.java @@ -28,6 +28,7 @@ import java.util.TreeMap; import static org.apache.lucene.index.VectorSimilarityFunction.EUCLIDEAN; +import static org.elasticsearch.index.mapper.vectors.DenseVectorFieldMapper.IVF_FORMAT; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.instanceOf; @@ -116,7 +117,7 @@ public void testRandom() throws IOException { VectorData.fromFloats(queries[i]), 10, 10, - 10f, + IVF_FORMAT.isEnabled() ? 10f : null, null, null, null, diff --git a/server/src/test/java/org/elasticsearch/search/vectors/KnnSearchBuilderTests.java b/server/src/test/java/org/elasticsearch/search/vectors/KnnSearchBuilderTests.java index 328b295f1f220..bf77781b69636 100644 --- a/server/src/test/java/org/elasticsearch/search/vectors/KnnSearchBuilderTests.java +++ b/server/src/test/java/org/elasticsearch/search/vectors/KnnSearchBuilderTests.java @@ -36,6 +36,7 @@ import java.util.Objects; import static java.util.Collections.emptyList; +import static org.elasticsearch.index.mapper.vectors.DenseVectorFieldMapper.IVF_FORMAT; import static org.elasticsearch.search.SearchService.DEFAULT_SIZE; import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.equalTo; @@ -52,7 +53,7 @@ public static KnnSearchBuilder randomTestInstance() { float[] vector = randomVector(dim); int k = randomIntBetween(1, 100); int numCands = randomIntBetween(k + 20, 1000); - Float visitPercentage = randomBoolean() ? null : randomFloatBetween(0.0f, 100.0f, true); + Float visitPercentage = IVF_FORMAT.isEnabled() == false ? null : randomBoolean() ? null : randomFloatBetween(0.0f, 100.0f, true); RescoreVectorBuilder rescoreVectorBuilder = randomBoolean() ? null : new RescoreVectorBuilder(randomFloatBetween(1.0f, 10.0f, false)); @@ -112,7 +113,7 @@ protected KnnSearchBuilder createTestInstance() { @Override protected KnnSearchBuilder mutateInstance(KnnSearchBuilder instance) { - return switch (random().nextInt(9)) { + return switch (IVF_FORMAT.isEnabled() ? random().nextInt(9) : random().nextInt(8)) { case 0 -> { String newField = randomValueOtherThan(instance.field, () -> randomAlphaOfLength(5)); yield new KnnSearchBuilder( @@ -207,10 +208,13 @@ yield new KnnSearchBuilder( instance.similarity ).addFilterQueries(instance.filterQueries).boost(instance.boost); case 8 -> { - Float newVisitPercentage = randomValueOtherThan( - instance.visitPercentage, - () -> ESTestCase.randomFloatBetween(0f, 100f, true) - ); + Float newVisitPercentage = null; + if (IVF_FORMAT.isEnabled()) { + newVisitPercentage = randomValueOtherThan( + instance.visitPercentage, + () -> ESTestCase.randomBoolean() ? null : ESTestCase.randomFloatBetween(0f, 100f, true) + ); + } yield new KnnSearchBuilder( instance.field, instance.queryVector, @@ -230,7 +234,7 @@ public void testToQueryBuilder() { float[] vector = randomVector(randomIntBetween(2, 30)); int k = randomIntBetween(1, 100); int numCands = randomIntBetween(k, 1000); - Float visitPercentage = randomBoolean() ? null : randomFloatBetween(0.0f, 100.0f, true); + Float visitPercentage = IVF_FORMAT.isEnabled() == false ? null : randomBoolean() ? null : randomFloatBetween(0.0f, 100.0f, true); Float similarity = randomBoolean() ? null : randomFloat(); RescoreVectorBuilder rescoreVectorBuilder = randomBoolean() ? null @@ -266,7 +270,7 @@ public void testToQueryBuilder() { public void testNumCandsLessThanK() { IllegalArgumentException e = expectThrows( IllegalArgumentException.class, - () -> new KnnSearchBuilder("field", randomVector(3), 50, 10, 10f, null, null) + () -> new KnnSearchBuilder("field", randomVector(3), 50, 10, IVF_FORMAT.isEnabled() ? 10f : null, null, null) ); assertThat(e.getMessage(), containsString("[num_candidates] cannot be less than [k]")); } @@ -274,12 +278,13 @@ public void testNumCandsLessThanK() { public void testNumCandsExceedsLimit() { IllegalArgumentException e = expectThrows( IllegalArgumentException.class, - () -> new KnnSearchBuilder("field", randomVector(3), 100, 10002, 10f, null, null) + () -> new KnnSearchBuilder("field", randomVector(3), 100, 10002, IVF_FORMAT.isEnabled() ? 10f : null, null, null) ); assertThat(e.getMessage(), containsString("[num_candidates] cannot exceed [10000]")); } public void testVisitPercentageLessThan0() { + assumeTrue("requires visit_percentage to be enabled", IVF_FORMAT.isEnabled()); IllegalArgumentException e = expectThrows( IllegalArgumentException.class, () -> new KnnSearchBuilder("field", randomVector(3), 50, 100, -190f, null, null) @@ -288,6 +293,7 @@ public void testVisitPercentageLessThan0() { } public void testVisitPercentageGreaterThan100() { + assumeTrue("requires visit_percentage to be enabled", IVF_FORMAT.isEnabled()); IllegalArgumentException e = expectThrows( IllegalArgumentException.class, () -> new KnnSearchBuilder("field", randomVector(3), 100, 1000, 100000f, null, null) @@ -298,7 +304,7 @@ public void testVisitPercentageGreaterThan100() { public void testInvalidK() { IllegalArgumentException e = expectThrows( IllegalArgumentException.class, - () -> new KnnSearchBuilder("field", randomVector(3), 0, 100, 10f, null, null) + () -> new KnnSearchBuilder("field", randomVector(3), 0, 100, IVF_FORMAT.isEnabled() ? 10f : null, null, null) ); assertThat(e.getMessage(), containsString("[k] must be greater than 0")); } @@ -306,7 +312,15 @@ public void testInvalidK() { public void testInvalidRescoreVectorBuilder() { IllegalArgumentException e = expectThrows( IllegalArgumentException.class, - () -> new KnnSearchBuilder("field", randomVector(3), 10, 100, 10f, new RescoreVectorBuilder(0.99F), null) + () -> new KnnSearchBuilder( + "field", + randomVector(3), + 10, + 100, + IVF_FORMAT.isEnabled() ? 10f : null, + new RescoreVectorBuilder(0.99F), + null + ) ); assertThat(e.getMessage(), containsString("[oversample] must be >= 1.0")); } @@ -319,7 +333,7 @@ public void testRewrite() throws Exception { new TestQueryVectorBuilderPlugin.TestQueryVectorBuilder(expectedArray), 5, 10, - 10f, + IVF_FORMAT.isEnabled() ? 10f : null, expectedRescore, 1f ); diff --git a/server/src/test/java/org/elasticsearch/search/vectors/KnnSearchRequestParserTests.java b/server/src/test/java/org/elasticsearch/search/vectors/KnnSearchRequestParserTests.java index 38b5bd8b4b475..574b9626261c2 100644 --- a/server/src/test/java/org/elasticsearch/search/vectors/KnnSearchRequestParserTests.java +++ b/server/src/test/java/org/elasticsearch/search/vectors/KnnSearchRequestParserTests.java @@ -37,6 +37,7 @@ import java.util.Map; import static java.util.Collections.emptyList; +import static org.elasticsearch.index.mapper.vectors.DenseVectorFieldMapper.IVF_FORMAT; import static org.elasticsearch.search.RandomSearchRequestGenerator.randomSearchSourceBuilder; import static org.hamcrest.Matchers.containsString; @@ -111,7 +112,7 @@ public void testParseSourceString() throws IOException { .field(KnnSearch.FIELD_FIELD.getPreferredName(), knnSearch.field) .field(KnnSearch.K_FIELD.getPreferredName(), knnSearch.k) .field(KnnSearch.NUM_CANDS_FIELD.getPreferredName(), knnSearch.numCands); - if (knnSearch.visitPercentage != null) { + if (IVF_FORMAT.isEnabled() && knnSearch.visitPercentage != null) { builder.field(KnnSearch.VISIT_PERCENTAGE_FIELD.getPreferredName(), knnSearch.visitPercentage); } builder.field(KnnSearch.QUERY_VECTOR_FIELD.getPreferredName(), knnSearch.queryVector); @@ -140,7 +141,7 @@ public void testParseSourceArray() throws IOException { .field(KnnSearch.FIELD_FIELD.getPreferredName(), knnSearch.field) .field(KnnSearch.K_FIELD.getPreferredName(), knnSearch.k) .field(KnnSearch.NUM_CANDS_FIELD.getPreferredName(), knnSearch.numCands); - if (knnSearch.visitPercentage != null) { + if (IVF_FORMAT.isEnabled() && knnSearch.visitPercentage != null) { builder.field(KnnSearch.VISIT_PERCENTAGE_FIELD.getPreferredName(), knnSearch.visitPercentage); } builder.field(KnnSearch.QUERY_VECTOR_FIELD.getPreferredName(), knnSearch.queryVector); @@ -176,11 +177,11 @@ public void testNumCandsLessThanK() throws IOException { .startObject(KnnSearchRequestParser.KNN_SECTION_FIELD.getPreferredName()) .field(KnnSearch.FIELD_FIELD.getPreferredName(), "field") .field(KnnSearch.K_FIELD.getPreferredName(), 100) - .field(KnnSearch.NUM_CANDS_FIELD.getPreferredName(), 80) - .field(KnnSearch.VISIT_PERCENTAGE_FIELD.getPreferredName(), 100.0f) - .field(KnnSearch.QUERY_VECTOR_FIELD.getPreferredName(), new float[] { 1.0f, 2.0f, 3.0f }) - .endObject() - .endObject(); + .field(KnnSearch.NUM_CANDS_FIELD.getPreferredName(), 80); + if (IVF_FORMAT.isEnabled()) { + builder.field(KnnSearch.VISIT_PERCENTAGE_FIELD.getPreferredName(), 100.0f); + } + builder.field(KnnSearch.QUERY_VECTOR_FIELD.getPreferredName(), new float[] { 1.0f, 2.0f, 3.0f }).endObject().endObject(); IllegalArgumentException e = expectThrows(IllegalArgumentException.class, () -> parseSearchRequest(builder)); assertThat(e.getMessage(), containsString("[num_candidates] cannot be less than [k]")); @@ -193,17 +194,18 @@ public void testNumCandsExceedsLimit() throws IOException { .startObject(KnnSearchRequestParser.KNN_SECTION_FIELD.getPreferredName()) .field(KnnSearch.FIELD_FIELD.getPreferredName(), "field") .field(KnnSearch.K_FIELD.getPreferredName(), 100) - .field(KnnSearch.NUM_CANDS_FIELD.getPreferredName(), 10002) - .field(KnnSearch.VISIT_PERCENTAGE_FIELD.getPreferredName(), 100.0f) - .field(KnnSearch.QUERY_VECTOR_FIELD.getPreferredName(), new float[] { 1.0f, 2.0f, 3.0f }) - .endObject() - .endObject(); + .field(KnnSearch.NUM_CANDS_FIELD.getPreferredName(), 10002); + if (IVF_FORMAT.isEnabled()) { + builder.field(KnnSearch.VISIT_PERCENTAGE_FIELD.getPreferredName(), 100.0f); + } + builder.field(KnnSearch.QUERY_VECTOR_FIELD.getPreferredName(), new float[] { 1.0f, 2.0f, 3.0f }).endObject().endObject(); IllegalArgumentException e = expectThrows(IllegalArgumentException.class, () -> parseSearchRequest(builder)); assertThat(e.getMessage(), containsString("[num_candidates] cannot exceed [10000]")); } public void testVisitPercnetageLessThan0() throws IOException { + assumeTrue("visit_percentage is only supported if IVF format is enabled", IVF_FORMAT.isEnabled()); XContentType xContentType = randomFrom(XContentType.values()); XContentBuilder builder = XContentBuilder.builder(xContentType.xContent()) .startObject() @@ -220,7 +222,8 @@ public void testVisitPercnetageLessThan0() throws IOException { assertThat(e.getMessage(), containsString("[visit_percentage] must be between 0 and 100")); } - public void testVisitPercnetageGreaterThan100() throws IOException { + public void testVisitPercentageGreaterThan100() throws IOException { + assumeTrue("visit_percentage is only supported if IVF format is enabled", IVF_FORMAT.isEnabled()); XContentType xContentType = randomFrom(XContentType.values()); XContentBuilder builder = XContentBuilder.builder(xContentType.xContent()) .startObject() @@ -244,11 +247,11 @@ public void testInvalidK() throws IOException { .startObject(KnnSearchRequestParser.KNN_SECTION_FIELD.getPreferredName()) .field(KnnSearch.FIELD_FIELD.getPreferredName(), "field") .field(KnnSearch.K_FIELD.getPreferredName(), 0) - .field(KnnSearch.NUM_CANDS_FIELD.getPreferredName(), 10) - .field(KnnSearch.VISIT_PERCENTAGE_FIELD.getPreferredName(), 100.0f) - .field(KnnSearch.QUERY_VECTOR_FIELD.getPreferredName(), new float[] { 1.0f, 2.0f, 3.0f }) - .endObject() - .endObject(); + .field(KnnSearch.NUM_CANDS_FIELD.getPreferredName(), 10); + if (IVF_FORMAT.isEnabled()) { + builder.field(KnnSearch.VISIT_PERCENTAGE_FIELD.getPreferredName(), 100.0f); + } + builder.field(KnnSearch.QUERY_VECTOR_FIELD.getPreferredName(), new float[] { 1.0f, 2.0f, 3.0f }).endObject().endObject(); IllegalArgumentException e = expectThrows(IllegalArgumentException.class, () -> parseSearchRequest(builder)); assertThat(e.getMessage(), containsString("[k] must be greater than 0")); @@ -281,7 +284,7 @@ private KnnSearch randomKnnSearch() { int k = randomIntBetween(1, 100); int numCands = randomIntBetween(k, 1000); - Float visitPercentage = randomBoolean() ? null : randomFloatBetween(0.0f, 100.0f, true); + Float visitPercentage = IVF_FORMAT.isEnabled() == false ? null : randomBoolean() ? null : randomFloatBetween(0.0f, 100.0f, true); return new KnnSearch(field, vector, k, numCands, visitPercentage); } @@ -305,7 +308,7 @@ private XContentBuilder createRequestBody(KnnSearch knnSearch, List