Skip to content

Commit 687b014

Browse files
authored
Add knn search parameter and remove knn query.
Original Pull Rrequest #2920 Closes #2919
1 parent 9d13929 commit 687b014

File tree

15 files changed

+576
-49
lines changed

15 files changed

+576
-49
lines changed

src/main/antora/modules/ROOT/pages/migration-guides/migration-guide-5.3-5.4.adoc

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,17 @@ This section describes breaking changes from version 5.3.x to 5.4.x and how remo
66
[[elasticsearch-migration-guide-5.3-5.4.breaking-changes]]
77
== Breaking Changes
88

9+
[[elasticsearch-migration-guide-5.3-5.4.breaking-changes.knn-search]]
10+
=== knn search
11+
The `withKnnQuery` method in `NativeQueryBuilder` has been replaced with `withKnnSearches` to build a `NativeQuery` with knn search.
12+
13+
`KnnQuery` and `KnnSearch` are two different classes in elasticsearch java client and are used for different queries, with different parameters supported:
14+
15+
- `KnnSearch`: is https://www.elastic.co/guide/en/elasticsearch/reference/8.13/search-search.html#search-api-knn[the top level `knn` query] in the elasticsearch request;
16+
- `KnnQuery`: is https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-knn-query.html[the `knn` query inside `query` clause];
17+
18+
If `KnnQuery` is still preferable, please be sure to construct it inside `query` clause manually, by means of `withQuery(co.elastic.clients.elasticsearch._types.query_dsl.Query query)` clause in `NativeQueryBuilder`.
19+
920
[[elasticsearch-migration-guide-5.3-5.4.deprecations]]
1021
== Deprecations
1122

src/main/java/org/springframework/data/elasticsearch/annotations/Field.java

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
* @author Brian Kimmig
3838
* @author Morgan Lutz
3939
* @author Sascha Woo
40+
* @author Haibo Liu
4041
*/
4142
@Retention(RetentionPolicy.RUNTIME)
4243
@Target({ ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.METHOD })
@@ -195,6 +196,27 @@
195196
*/
196197
int dims() default -1;
197198

199+
/**
200+
* to be used in combination with {@link FieldType#Dense_Vector}
201+
*
202+
* @since 5.4
203+
*/
204+
String elementType() default FieldElementType.DEFAULT;
205+
206+
/**
207+
* to be used in combination with {@link FieldType#Dense_Vector}
208+
*
209+
* @since 5.4
210+
*/
211+
KnnSimilarity knnSimilarity() default KnnSimilarity.DEFAULT;
212+
213+
/**
214+
* to be used in combination with {@link FieldType#Dense_Vector}
215+
*
216+
* @since 5.4
217+
*/
218+
KnnIndexOptions[] knnIndexOptions() default {};
219+
198220
/**
199221
* Controls how Elasticsearch dynamically adds fields to the inner object within the document.<br>
200222
* To be used in combination with {@link FieldType#Object} or {@link FieldType#Nested}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/*
2+
* Copyright 2024 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.springframework.data.elasticsearch.annotations;
17+
18+
/**
19+
* @author Haibo Liu
20+
* @since 5.4
21+
*/
22+
public final class FieldElementType {
23+
public final static String DEFAULT = "";
24+
public final static String FLOAT = "float";
25+
public final static String BYTE = "byte";
26+
}

src/main/java/org/springframework/data/elasticsearch/annotations/InnerField.java

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
* @author Aleksei Arsenev
3030
* @author Brian Kimmig
3131
* @author Morgan Lutz
32+
* @author Haibo Liu
3233
*/
3334
@Retention(RetentionPolicy.RUNTIME)
3435
@Target(ElementType.ANNOTATION_TYPE)
@@ -149,4 +150,25 @@
149150
* @since 4.2
150151
*/
151152
int dims() default -1;
153+
154+
/**
155+
* to be used in combination with {@link FieldType#Dense_Vector}
156+
*
157+
* @since 5.4
158+
*/
159+
String elementType() default FieldElementType.DEFAULT;
160+
161+
/**
162+
* to be used in combination with {@link FieldType#Dense_Vector}
163+
*
164+
* @since 5.4
165+
*/
166+
KnnSimilarity knnSimilarity() default KnnSimilarity.DEFAULT;
167+
168+
/**
169+
* to be used in combination with {@link FieldType#Dense_Vector}
170+
*
171+
* @since 5.4
172+
*/
173+
KnnIndexOptions[] knnIndexOptions() default {};
152174
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
/*
2+
* Copyright 2024 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.springframework.data.elasticsearch.annotations;
17+
18+
/**
19+
* @author Haibo Liu
20+
* @since 5.4
21+
*/
22+
public enum KnnAlgorithmType {
23+
HNSW("hnsw"),
24+
INT8_HNSW("int8_hnsw"),
25+
FLAT("flat"),
26+
INT8_FLAT("int8_flat"),
27+
DEFAULT("");
28+
29+
private final String type;
30+
31+
KnnAlgorithmType(String type) {
32+
this.type = type;
33+
}
34+
35+
public String getType() {
36+
return type;
37+
}
38+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/*
2+
* Copyright 2024 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.springframework.data.elasticsearch.annotations;
17+
18+
/**
19+
* @author Haibo Liu
20+
* @since 5.4
21+
*/
22+
public @interface KnnIndexOptions {
23+
24+
KnnAlgorithmType type() default KnnAlgorithmType.DEFAULT;
25+
26+
/**
27+
* Only applicable to {@link KnnAlgorithmType#HNSW} and {@link KnnAlgorithmType#INT8_HNSW} index types.
28+
*/
29+
int m() default -1;
30+
31+
/**
32+
* Only applicable to {@link KnnAlgorithmType#HNSW} and {@link KnnAlgorithmType#INT8_HNSW} index types.
33+
*/
34+
int efConstruction() default -1;
35+
36+
/**
37+
* Only applicable to {@link KnnAlgorithmType#INT8_HNSW} and {@link KnnAlgorithmType#INT8_FLAT} index types.
38+
*/
39+
float confidenceInterval() default -1F;
40+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
/*
2+
* Copyright 2024 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.springframework.data.elasticsearch.annotations;
17+
18+
/**
19+
* @author Haibo Liu
20+
* @since 5.4
21+
*/
22+
public enum KnnSimilarity {
23+
L2_NORM("l2_norm"),
24+
DOT_PRODUCT("dot_product"),
25+
COSINE("cosine"),
26+
MAX_INNER_PRODUCT("max_inner_product"),
27+
DEFAULT("");
28+
29+
private final String similarity;
30+
31+
KnnSimilarity(String similarity) {
32+
this.similarity = similarity;
33+
}
34+
35+
public String getSimilarity() {
36+
return similarity;
37+
}
38+
}

src/main/java/org/springframework/data/elasticsearch/client/elc/NativeQuery.java

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
*/
1616
package org.springframework.data.elasticsearch.client.elc;
1717

18-
import co.elastic.clients.elasticsearch._types.KnnQuery;
1918
import co.elastic.clients.elasticsearch._types.KnnSearch;
2019
import co.elastic.clients.elasticsearch._types.SortOptions;
2120
import co.elastic.clients.elasticsearch._types.aggregations.Aggregation;
@@ -30,7 +29,6 @@
3029
import java.util.Map;
3130

3231
import org.springframework.data.elasticsearch.core.query.BaseQuery;
33-
import org.springframework.data.elasticsearch.core.query.ScriptedField;
3432
import org.springframework.lang.Nullable;
3533
import org.springframework.util.Assert;
3634

@@ -40,6 +38,7 @@
4038
*
4139
* @author Peter-Josef Meisch
4240
* @author Sascha Woo
41+
* @author Haibo Liu
4342
* @since 4.4
4443
*/
4544
public class NativeQuery extends BaseQuery {
@@ -54,7 +53,6 @@ public class NativeQuery extends BaseQuery {
5453
private List<SortOptions> sortOptions = Collections.emptyList();
5554

5655
private Map<String, JsonData> searchExtensions = Collections.emptyMap();
57-
@Nullable private KnnQuery knnQuery;
5856
@Nullable private List<KnnSearch> knnSearches = Collections.emptyList();
5957

6058
public NativeQuery(NativeQueryBuilder builder) {
@@ -72,7 +70,6 @@ public NativeQuery(NativeQueryBuilder builder) {
7270
"Cannot add an NativeQuery in a NativeQuery");
7371
}
7472
this.springDataQuery = builder.getSpringDataQuery();
75-
this.knnQuery = builder.getKnnQuery();
7673
this.knnSearches = builder.getKnnSearches();
7774
}
7875

@@ -124,14 +121,6 @@ public void setSpringDataQuery(@Nullable org.springframework.data.elasticsearch.
124121
this.springDataQuery = springDataQuery;
125122
}
126123

127-
/**
128-
* @since 5.1
129-
*/
130-
@Nullable
131-
public KnnQuery getKnnQuery() {
132-
return knnQuery;
133-
}
134-
135124
/**
136125
* @since 5.3.1
137126
*/

src/main/java/org/springframework/data/elasticsearch/client/elc/NativeQueryBuilder.java

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
/**
4141
* @author Peter-Josef Meisch
4242
* @author Sascha Woo
43+
* @author Haibo Liu
4344
* @since 4.4
4445
*/
4546
public class NativeQueryBuilder extends BaseQueryBuilder<NativeQuery, NativeQueryBuilder> {
@@ -213,13 +214,30 @@ public NativeQueryBuilder withQuery(org.springframework.data.elasticsearch.core.
213214
}
214215

215216
/**
216-
* @since 5.1
217+
* @since 5.4
217218
*/
218-
public NativeQueryBuilder withKnnQuery(KnnQuery knnQuery) {
219-
this.knnQuery = knnQuery;
219+
public NativeQueryBuilder withKnnSearches(List<KnnSearch> knnSearches) {
220+
this.knnSearches = knnSearches;
220221
return this;
221222
}
222223

224+
/**
225+
* @since 5.4
226+
*/
227+
public NativeQueryBuilder withKnnSearches(Function<KnnSearch.Builder, ObjectBuilder<KnnSearch>> fn) {
228+
229+
Assert.notNull(fn, "fn must not be null");
230+
231+
return withKnnSearches(fn.apply(new KnnSearch.Builder()).build());
232+
}
233+
234+
/**
235+
* @since 5.4
236+
*/
237+
public NativeQueryBuilder withKnnSearches(KnnSearch knnSearch) {
238+
return withKnnSearches(List.of(knnSearch));
239+
}
240+
223241
public NativeQuery build() {
224242
Assert.isTrue(query == null || springDataQuery == null, "Cannot have both a native query and a Spring Data query");
225243
return new NativeQuery(this);

src/main/java/org/springframework/data/elasticsearch/client/elc/RequestConverter.java

Lines changed: 2 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1377,7 +1377,7 @@ public MsearchRequest searchMsearchRequest(
13771377
private Function<MultisearchHeader.Builder, ObjectBuilder<MultisearchHeader>> msearchHeaderBuilder(Query query,
13781378
IndexCoordinates index, @Nullable String routing) {
13791379
return h -> {
1380-
var searchType = (query instanceof NativeQuery nativeQuery && nativeQuery.getKnnQuery() != null) ? null
1380+
var searchType = (query instanceof NativeQuery nativeQuery && !isEmpty(nativeQuery.getKnnSearches())) ? null
13811381
: searchType(query.getSearchType());
13821382

13831383
h //
@@ -1409,7 +1409,7 @@ private <T> void prepareSearchRequest(Query query, @Nullable String routing, @Nu
14091409

14101410
ElasticsearchPersistentEntity<?> persistentEntity = getPersistentEntity(clazz);
14111411

1412-
var searchType = (query instanceof NativeQuery nativeQuery && nativeQuery.getKnnQuery() != null) ? null
1412+
var searchType = (query instanceof NativeQuery nativeQuery && !isEmpty(nativeQuery.getKnnSearches())) ? null
14131413
: searchType(query.getSearchType());
14141414

14151415
builder //
@@ -1728,17 +1728,6 @@ private void prepareNativeSearch(NativeQuery query, SearchRequest.Builder builde
17281728
.sort(query.getSortOptions()) //
17291729
;
17301730

1731-
if (query.getKnnQuery() != null) {
1732-
var kq = query.getKnnQuery();
1733-
builder.knn(ksb -> ksb
1734-
.field(kq.field())
1735-
.queryVector(kq.queryVector())
1736-
.numCandidates(kq.numCandidates())
1737-
.filter(kq.filter())
1738-
.similarity(kq.similarity()));
1739-
1740-
}
1741-
17421731
if (!isEmpty(query.getKnnSearches())) {
17431732
builder.knn(query.getKnnSearches());
17441733
}
@@ -1760,17 +1749,6 @@ private void prepareNativeSearch(NativeQuery query, MultisearchBody.Builder buil
17601749
.collapse(query.getFieldCollapse()) //
17611750
.sort(query.getSortOptions());
17621751

1763-
if (query.getKnnQuery() != null) {
1764-
var kq = query.getKnnQuery();
1765-
builder.knn(ksb -> ksb
1766-
.field(kq.field())
1767-
.queryVector(kq.queryVector())
1768-
.numCandidates(kq.numCandidates())
1769-
.filter(kq.filter())
1770-
.similarity(kq.similarity()));
1771-
1772-
}
1773-
17741752
if (!isEmpty(query.getKnnSearches())) {
17751753
builder.knn(query.getKnnSearches());
17761754
}

0 commit comments

Comments
 (0)