Skip to content

Commit 39e41c0

Browse files
committed
merging main
2 parents b98d4a8 + bc0e1d0 commit 39e41c0

File tree

45 files changed

+534
-502
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

45 files changed

+534
-502
lines changed

docs/changelog/126035.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
pr: 126035
2+
summary: Fix top level knn search with scroll
3+
area: Vector Search
4+
type: bug
5+
issues: []

docs/changelog/126629.yaml

Lines changed: 0 additions & 5 deletions
This file was deleted.

docs/reference/query-languages/esql/_snippets/functions/layout/st_xmax.md

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

docs/reference/query-languages/esql/_snippets/functions/layout/st_xmin.md

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

docs/reference/query-languages/esql/_snippets/functions/layout/st_ymax.md

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

docs/reference/query-languages/esql/_snippets/functions/layout/st_ymin.md

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

docs/reference/query-languages/esql/_snippets/lists/spatial-functions.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
* [`ST_X`](../../functions-operators/spatial-functions.md#esql-st_x)
77
* [`ST_Y`](../../functions-operators/spatial-functions.md#esql-st_y)
88
* [preview] [`ST_ENVELOPE`](../../functions-operators/spatial-functions.md#esql-st_envelope)
9-
* [preview] [`ST_XMAX`](../../functions-operators/spatial-functions.md#esql-st_xmax)
10-
* [preview] [`ST_XMIN`](../../functions-operators/spatial-functions.md#esql-st_xmin)
11-
* [preview] [`ST_YMAX`](../../functions-operators/spatial-functions.md#esql-st_ymax)
12-
* [preview] [`ST_YMIN`](../../functions-operators/spatial-functions.md#esql-st_ymin)
9+
* [preview] [`ST_XMAX`](../../functions-operators/spatial-functions.md#esql-st_xmax)
10+
* [preview] [`ST_XMIN`](../../functions-operators/spatial-functions.md#esql-st_xmin)
11+
* [preview] [`ST_YMAX`](../../functions-operators/spatial-functions.md#esql-st_ymax)
12+
* [preview] [`ST_YMIN`](../../functions-operators/spatial-functions.md#esql-st_ymin)

libs/entitlement/src/test/java/org/elasticsearch/entitlement/initialization/EntitlementInitializationTests.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import static org.hamcrest.Matchers.endsWith;
2727
import static org.hamcrest.Matchers.startsWith;
2828

29+
@ESTestCase.WithoutSecurityManager
2930
public class EntitlementInitializationTests extends ESTestCase {
3031

3132
private static PathLookup TEST_PATH_LOOKUP;

muted-tests.yml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -420,6 +420,15 @@ tests:
420420
- class: org.elasticsearch.xpack.esql.qa.single_node.EsqlSpecIT
421421
method: test {rrf.SimpleRrf ASYNC}
422422
issue: https://github.com/elastic/elasticsearch/issues/127063
423+
- class: org.elasticsearch.packaging.test.DockerTests
424+
method: test026InstallBundledRepositoryPlugins
425+
issue: https://github.com/elastic/elasticsearch/issues/127081
426+
- class: org.elasticsearch.multiproject.test.XpackWithMultipleProjectsClientYamlTestSuiteIT
427+
method: test {yaml=esql/10_basic/basic with documents_found}
428+
issue: https://github.com/elastic/elasticsearch/issues/127088
429+
- class: org.elasticsearch.xpack.esql.qa.single_node.EsqlClientYamlAsyncIT
430+
method: test {p0=esql/10_basic/basic with documents_found}
431+
issue: https://github.com/elastic/elasticsearch/issues/127080
423432

424433
# Examples:
425434
#
Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the "Elastic License
4+
* 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side
5+
* Public License v 1"; you may not use this file except in compliance with, at
6+
* your election, the "Elastic License 2.0", the "GNU Affero General Public
7+
* License v3.0 only", or the "Server Side Public License, v 1".
8+
*/
9+
10+
package org.elasticsearch.search;
11+
12+
import org.elasticsearch.action.search.SearchRequest;
13+
import org.elasticsearch.action.search.SearchResponse;
14+
import org.elasticsearch.client.internal.Client;
15+
import org.elasticsearch.common.settings.Settings;
16+
import org.elasticsearch.core.TimeValue;
17+
import org.elasticsearch.index.query.QueryBuilders;
18+
import org.elasticsearch.search.builder.SearchSourceBuilder;
19+
import org.elasticsearch.search.vectors.KnnSearchBuilder;
20+
import org.elasticsearch.search.vectors.KnnVectorQueryBuilder;
21+
import org.elasticsearch.test.ESIntegTestCase;
22+
import org.elasticsearch.xcontent.XContentBuilder;
23+
import org.elasticsearch.xcontent.XContentFactory;
24+
25+
import java.util.List;
26+
27+
import static org.hamcrest.Matchers.notNullValue;
28+
29+
@ESIntegTestCase.ClusterScope(minNumDataNodes = 2)
30+
public class KnnSearchIT extends ESIntegTestCase {
31+
32+
private static final String INDEX_NAME = "test_knn_index";
33+
private static final String VECTOR_FIELD = "vector";
34+
35+
private XContentBuilder createKnnMapping() throws Exception {
36+
return XContentFactory.jsonBuilder()
37+
.startObject()
38+
.startObject("properties")
39+
.startObject(VECTOR_FIELD)
40+
.field("type", "dense_vector")
41+
.field("dims", 2)
42+
.field("index", true)
43+
.field("similarity", "l2_norm")
44+
.startObject("index_options")
45+
.field("type", "hnsw")
46+
.endObject()
47+
.endObject()
48+
.startObject("category")
49+
.field("type", "keyword")
50+
.endObject()
51+
.endObject()
52+
.endObject();
53+
}
54+
55+
public void testKnnSearchWithScroll() throws Exception {
56+
final int numShards = randomIntBetween(1, 3);
57+
Client client = client();
58+
client.admin()
59+
.indices()
60+
.prepareCreate(INDEX_NAME)
61+
.setSettings(Settings.builder().put("index.number_of_shards", numShards))
62+
.setMapping(createKnnMapping())
63+
.get();
64+
65+
final int count = 100;
66+
for (int i = 0; i < count; i++) {
67+
XContentBuilder source = XContentFactory.jsonBuilder()
68+
.startObject()
69+
.field(VECTOR_FIELD, new float[] { i * 0.1f, i * 0.1f })
70+
.field("category", i >= 90 ? "last_ten" : null)
71+
.endObject();
72+
client.prepareIndex(INDEX_NAME).setSource(source).get();
73+
}
74+
refresh(INDEX_NAME);
75+
76+
final int k = randomIntBetween(11, 15);
77+
// test top level knn search
78+
{
79+
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
80+
sourceBuilder.knnSearch(List.of(new KnnSearchBuilder(VECTOR_FIELD, new float[] { 0, 0 }, k, 100, null, null)));
81+
executeScrollSearch(client, sourceBuilder, k);
82+
}
83+
// test top level knn search + another query
84+
{
85+
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
86+
sourceBuilder.knnSearch(List.of(new KnnSearchBuilder(VECTOR_FIELD, new float[] { 0, 0 }, k, 100, null, null)));
87+
sourceBuilder.query(QueryBuilders.existsQuery("category").boost(10));
88+
executeScrollSearch(client, sourceBuilder, k + 10);
89+
}
90+
91+
// test knn query
92+
{
93+
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
94+
sourceBuilder.query(new KnnVectorQueryBuilder(VECTOR_FIELD, new float[] { 0, 0 }, k, 100, null, null));
95+
executeScrollSearch(client, sourceBuilder, k * numShards);
96+
}
97+
// test knn query + another query
98+
{
99+
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
100+
sourceBuilder.query(
101+
QueryBuilders.boolQuery()
102+
.should(new KnnVectorQueryBuilder(VECTOR_FIELD, new float[] { 0, 0 }, k, 100, null, null))
103+
.should(QueryBuilders.existsQuery("category").boost(10))
104+
);
105+
executeScrollSearch(client, sourceBuilder, k * numShards + 10);
106+
}
107+
108+
}
109+
110+
private static void executeScrollSearch(Client client, SearchSourceBuilder sourceBuilder, int expectedNumHits) {
111+
SearchRequest searchRequest = new SearchRequest(INDEX_NAME);
112+
searchRequest.source(sourceBuilder).scroll(TimeValue.timeValueMinutes(1));
113+
114+
SearchResponse searchResponse = client.search(searchRequest).actionGet();
115+
int hitsCollected = 0;
116+
float prevScore = Float.POSITIVE_INFINITY;
117+
try {
118+
do {
119+
assertThat(searchResponse.getScrollId(), notNullValue());
120+
assertEquals(expectedNumHits, searchResponse.getHits().getTotalHits().value());
121+
// assert correct order of returned hits
122+
for (var searchHit : searchResponse.getHits()) {
123+
assert (searchHit.getScore() <= prevScore);
124+
prevScore = searchHit.getScore();
125+
hitsCollected += 1;
126+
}
127+
searchResponse.decRef();
128+
searchResponse = client().prepareSearchScroll(searchResponse.getScrollId()).setScroll(TimeValue.timeValueMinutes(1)).get();
129+
} while (searchResponse.getHits().getHits().length > 0);
130+
} finally {
131+
assertEquals(expectedNumHits, hitsCollected);
132+
clearScroll(searchResponse.getScrollId());
133+
searchResponse.decRef();
134+
}
135+
}
136+
137+
}

0 commit comments

Comments
 (0)