Skip to content

Commit 4382b0e

Browse files
committed
HSEARCH-5064 Remove knn integration for Elasticsearch < 8.12
1 parent db210b8 commit 4382b0e

File tree

22 files changed

+162
-575
lines changed

22 files changed

+162
-575
lines changed

backend/elasticsearch/src/main/java/org/hibernate/search/backend/elasticsearch/dialect/model/impl/Elasticsearch812ModelDialect.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
import org.hibernate.search.backend.elasticsearch.types.dsl.provider.impl.Elasticsearch812IndexFieldTypeFactoryProvider;
1010
import org.hibernate.search.backend.elasticsearch.types.dsl.provider.impl.ElasticsearchIndexFieldTypeFactoryProvider;
11-
import org.hibernate.search.backend.elasticsearch.validation.impl.Elasticsearch8PropertyMappingValidatorProvider;
11+
import org.hibernate.search.backend.elasticsearch.validation.impl.Elasticsearch812PropertyMappingValidatorProvider;
1212
import org.hibernate.search.backend.elasticsearch.validation.impl.ElasticsearchPropertyMappingValidatorProvider;
1313

1414
import com.google.gson.Gson;
@@ -25,6 +25,6 @@ public ElasticsearchIndexFieldTypeFactoryProvider createIndexTypeFieldFactoryPro
2525

2626
@Override
2727
public ElasticsearchPropertyMappingValidatorProvider createElasticsearchPropertyMappingValidatorProvider() {
28-
return new Elasticsearch8PropertyMappingValidatorProvider();
28+
return new Elasticsearch812PropertyMappingValidatorProvider();
2929
}
3030
}

backend/elasticsearch/src/main/java/org/hibernate/search/backend/elasticsearch/dialect/model/impl/Elasticsearch8ModelDialect.java

+4-4
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@
66
*/
77
package org.hibernate.search.backend.elasticsearch.dialect.model.impl;
88

9-
import org.hibernate.search.backend.elasticsearch.types.dsl.provider.impl.Elasticsearch8IndexFieldTypeFactoryProvider;
9+
import org.hibernate.search.backend.elasticsearch.types.dsl.provider.impl.Elasticsearch7IndexFieldTypeFactoryProvider;
1010
import org.hibernate.search.backend.elasticsearch.types.dsl.provider.impl.ElasticsearchIndexFieldTypeFactoryProvider;
11-
import org.hibernate.search.backend.elasticsearch.validation.impl.Elasticsearch8PropertyMappingValidatorProvider;
11+
import org.hibernate.search.backend.elasticsearch.validation.impl.Elasticsearch7PropertyMappingValidatorProvider;
1212
import org.hibernate.search.backend.elasticsearch.validation.impl.ElasticsearchPropertyMappingValidatorProvider;
1313

1414
import com.google.gson.Gson;
@@ -20,11 +20,11 @@ public class Elasticsearch8ModelDialect implements ElasticsearchModelDialect {
2020

2121
@Override
2222
public ElasticsearchIndexFieldTypeFactoryProvider createIndexTypeFieldFactoryProvider(Gson userFacingGson) {
23-
return new Elasticsearch8IndexFieldTypeFactoryProvider( userFacingGson );
23+
return new Elasticsearch7IndexFieldTypeFactoryProvider( userFacingGson );
2424
}
2525

2626
@Override
2727
public ElasticsearchPropertyMappingValidatorProvider createElasticsearchPropertyMappingValidatorProvider() {
28-
return new Elasticsearch8PropertyMappingValidatorProvider();
28+
return new Elasticsearch7PropertyMappingValidatorProvider();
2929
}
3030
}

backend/elasticsearch/src/main/java/org/hibernate/search/backend/elasticsearch/logging/impl/Log.java

-15
Original file line numberDiff line numberDiff line change
@@ -865,26 +865,11 @@ SearchException vectorKnnMatchVectorTypeDiffersFromField(String absoluteFieldPat
865865
+ " Use the array of the same size as the vector field.")
866866
SearchException vectorKnnMatchVectorDimensionDiffersFromField(String absoluteFieldPath, int expected, int actual);
867867

868-
@Message(id = ID_OFFSET + 183, value = "A knn predicate cannot be added. "
869-
+ "With Elasticsearch, a knn predicate can only be a top-level predicate or a should clause of a top-level bool predicate.")
870-
SearchException cannotAddKnnClauseAtThisStep();
871-
872-
@Message(id = ID_OFFSET + 184,
873-
value = "An OpenSearch distribution does not allow specifying the `number of candidates` option. "
874-
+ "This option is only applicable to an Elastic distribution of an Elasticsearch backend.")
875-
SearchException knnNumberOfCandidatesUnsupportedOption();
876-
877868
@Message(id = ID_OFFSET + 185,
878869
value = "An %1$s distribution version in use is not compatible with the Hibernate Search integration of vector search. "
879870
+ "Update your %1$s cluster to a %2$s series to get vector search integration enabled.")
880871
SearchException searchBackendVersionIncompatibleWithVectorIntegration(String distribution, String version);
881872

882-
@LogMessage(level = Logger.Level.WARN)
883-
@Message(id = ID_OFFSET + 186,
884-
value = "The Elastic distribution of Elasticsearch does not allow to apply constant score to a knn predicate."
885-
+ " Constant score will not be applied.")
886-
void elasticsearchKnnIgnoresConstantScore();
887-
888873
@Message(id = ID_OFFSET + 187,
889874
value = "An OpenSearch distribution does not allow specifying the `required minimum similarity` option. "
890875
+ "This option is only applicable to an Elastic distribution of an Elasticsearch backend.")

backend/elasticsearch/src/main/java/org/hibernate/search/backend/elasticsearch/search/predicate/impl/ElasticsearchBooleanPredicate.java

+9-51
Original file line numberDiff line numberDiff line change
@@ -65,16 +65,10 @@ private ElasticsearchBooleanPredicate(Builder builder) {
6565

6666
@Override
6767
public void checkNestableWithin(PredicateNestingContext context) {
68-
// For Elasticsearch backend only:
69-
// If this method is called that means we are trying to pass a bool predicate as a clause/filter/etc to some other predicate
70-
// and that would mean that if our current bool predicate has a knn should clause -- it is not ok to continue,
71-
// since it will place a knn clause deeper than a should clause of a top level bool predicate, which is not acceptable.
72-
// Because of that we are making sure that the context we pass in to check the clauses is updated:
73-
PredicateNestingContext updatedContext = context.rejectKnn();
74-
checkAcceptableWithin( updatedContext, mustClauses );
75-
checkAcceptableWithin( updatedContext, shouldClauses );
76-
checkAcceptableWithin( updatedContext, filterClauses );
77-
checkAcceptableWithin( updatedContext, mustNotClauses );
68+
checkAcceptableWithin( context, mustClauses );
69+
checkAcceptableWithin( context, shouldClauses );
70+
checkAcceptableWithin( context, filterClauses );
71+
checkAcceptableWithin( context, mustNotClauses );
7872
}
7973

8074
@Override
@@ -116,15 +110,7 @@ private void contributeClauses(PredicateRequestContext context, JsonObject inner
116110
}
117111

118112
for ( ElasticsearchSearchPredicate clause : clauses ) {
119-
JsonObject jsonQuery = clause.toJsonQuery( context );
120-
if ( jsonQuery != null ) {
121-
// This is an exceptional case for a KNN search on Elasticsearch distribution.
122-
// A Knn predicate would contribute to a knn clause inside the request context itself,
123-
// and we do not want to add this json as a clause to the bool predicate.
124-
// Hence, when the predicate returns null as JSON query and we ignore it.
125-
126-
GsonUtils.setOrAppendToArray( innerObject, occurProperty, jsonQuery );
127-
}
113+
GsonUtils.setOrAppendToArray( innerObject, occurProperty, clause.toJsonQuery( context ) );
128114
}
129115
}
130116

@@ -221,10 +207,8 @@ public void must(SearchPredicate clause) {
221207
mustClauses = new ArrayList<>();
222208
}
223209
ElasticsearchSearchPredicate elasticsearchClause = ElasticsearchSearchPredicate.from( scope, clause );
224-
elasticsearchClause.checkNestableWithin( PredicateNestingContext.doesNotAcceptKnn() );
210+
elasticsearchClause.checkNestableWithin( PredicateNestingContext.simple() );
225211
mustClauses.add( elasticsearchClause );
226-
227-
checkShouldClausesForKnnAcceptability();
228212
}
229213

230214
@Override
@@ -233,23 +217,17 @@ public void mustNot(SearchPredicate clause) {
233217
mustNotClauses = new ArrayList<>();
234218
}
235219
ElasticsearchSearchPredicate elasticsearchClause = ElasticsearchSearchPredicate.from( scope, clause );
236-
elasticsearchClause.checkNestableWithin( PredicateNestingContext.doesNotAcceptKnn() );
220+
elasticsearchClause.checkNestableWithin( PredicateNestingContext.simple() );
237221
mustNotClauses.add( elasticsearchClause );
238-
239-
checkShouldClausesForKnnAcceptability();
240222
}
241223

242224
@Override
243225
public void should(SearchPredicate clause) {
244226
if ( shouldClauses == null ) {
245227
shouldClauses = new ArrayList<>();
246228
}
247-
248229
ElasticsearchSearchPredicate elasticsearchClause = ElasticsearchSearchPredicate.from( scope, clause );
249-
elasticsearchClause.checkNestableWithin(
250-
!hasNonShouldClause()
251-
? PredicateNestingContext.acceptsKnn()
252-
: PredicateNestingContext.doesNotAcceptKnn() );
230+
elasticsearchClause.checkNestableWithin( PredicateNestingContext.simple() );
253231
shouldClauses.add( elasticsearchClause );
254232
}
255233

@@ -259,10 +237,8 @@ public void filter(SearchPredicate clause) {
259237
filterClauses = new ArrayList<>();
260238
}
261239
ElasticsearchSearchPredicate elasticsearchClause = ElasticsearchSearchPredicate.from( scope, clause );
262-
elasticsearchClause.checkNestableWithin( PredicateNestingContext.doesNotAcceptKnn() );
240+
elasticsearchClause.checkNestableWithin( PredicateNestingContext.simple() );
263241
filterClauses.add( elasticsearchClause );
264-
265-
checkShouldClausesForKnnAcceptability();
266242
}
267243

268244
@Override
@@ -351,20 +327,6 @@ private void optimizeClauseCollection(List<ElasticsearchSearchPredicate> collect
351327
}
352328
}
353329

354-
/*
355-
* For Elasticsearch backend only:
356-
* It may be that we've added knn should clauses and all was fine.
357-
* But now we are adding to such bool predicate a non-should clause.
358-
* We want to make sure that in such case there are no knn clauses in should or fail.
359-
* OpenSearch backend will not be affected by these checks.
360-
*/
361-
private void checkShouldClausesForKnnAcceptability() {
362-
if ( shouldClauses != null ) {
363-
shouldClauses.forEach(
364-
should -> should.checkNestableWithin( PredicateNestingContext.doesNotAcceptKnn() ) );
365-
}
366-
}
367-
368330
private void checkAndClearClauseCollections() {
369331
if ( mustClauses != null && mustClauses.isEmpty() ) {
370332
mustClauses = null;
@@ -378,10 +340,6 @@ private boolean hasAtLeastOneMustOrFilterPredicate() {
378340
return mustClauses != null || filterClauses != null;
379341
}
380342

381-
private boolean hasNonShouldClause() {
382-
return mustClauses != null || filterClauses != null || mustNotClauses != null;
383-
}
384-
385343
private boolean hasOnlyOneMustClause() {
386344
return mustClauses != null
387345
&& mustClauses.size() == 1

backend/elasticsearch/src/main/java/org/hibernate/search/backend/elasticsearch/search/predicate/impl/ElasticsearchKnnPredicate.java

+1-89
Original file line numberDiff line numberDiff line change
@@ -45,19 +45,6 @@ private ElasticsearchKnnPredicate(AbstractKnnBuilder<?> builder) {
4545
builder.vector = null;
4646
}
4747

48-
public static class ElasticsearchFactory<F>
49-
extends AbstractElasticsearchCodecAwareSearchQueryElementFactory<KnnPredicateBuilder, F> {
50-
public ElasticsearchFactory(ElasticsearchFieldCodec<F> codec) {
51-
super( codec );
52-
}
53-
54-
@Override
55-
public KnnPredicateBuilder create(ElasticsearchSearchIndexScope<?> scope,
56-
ElasticsearchSearchIndexValueFieldContext<F> field) {
57-
return new ElasticsearchImpl.Builder<>( codec, scope, field );
58-
}
59-
}
60-
6148
public static class Elasticsearch812Factory<F>
6249
extends AbstractElasticsearchCodecAwareSearchQueryElementFactory<KnnPredicateBuilder, F> {
6350
public Elasticsearch812Factory(ElasticsearchFieldCodec<F> codec) {
@@ -132,7 +119,7 @@ public void vector(Object vector) {
132119
@Override
133120
public void filter(SearchPredicate filter) {
134121
ElasticsearchSearchPredicate elasticsearchFilter = ElasticsearchSearchPredicate.from( scope, filter );
135-
elasticsearchFilter.checkNestableWithin( PredicateNestingContext.doesNotAcceptKnn() );
122+
elasticsearchFilter.checkNestableWithin( PredicateNestingContext.simple() );
136123
this.filter = elasticsearchFilter;
137124
}
138125

@@ -153,81 +140,6 @@ private static JsonArray vectorToJsonArray(Object vector, Class<?> vectorElement
153140
return array;
154141
}
155142

156-
private static class ElasticsearchImpl extends ElasticsearchKnnPredicate {
157-
158-
private static final Log log = LoggerFactory.make( Log.class, MethodHandles.lookup() );
159-
160-
private static final JsonAccessor<String> FIELD_ACCESSOR = JsonAccessor.root().property( "field" ).asString();
161-
private static final JsonArrayAccessor QUERY_VECTOR_ACCESSOR = JsonAccessor.root().property( "query_vector" ).asArray();
162-
private static final JsonAccessor<Integer> K_ACCESSOR = JsonAccessor.root().property( "k" ).asInteger();
163-
164-
private static final JsonObjectAccessor FILTER_ACCESSOR = JsonAccessor.root().property( "filter" ).asObject();
165-
private static final JsonAccessor<Integer> NUM_CANDIDATES_ACCESSOR =
166-
JsonAccessor.root().property( "num_candidates" ).asInteger();
167-
private static final JsonAccessor<Float> SIMILARITY_ACCESSOR = JsonAccessor.root().property( "similarity" ).asFloat();
168-
169-
170-
private ElasticsearchImpl(Builder<?> builder) {
171-
super( builder );
172-
}
173-
174-
@Override
175-
public JsonObject toJsonQuery(PredicateRequestContext context) {
176-
// we want the query to get created and passed to the request context
177-
context.contributeKnnClause( ( super.toJsonQuery( context ) ) );
178-
// but we don't want it to be an actual query so we return `null`:
179-
return null;
180-
}
181-
182-
@Override
183-
protected JsonObject doToJsonQuery(PredicateRequestContext context, JsonObject outerObject, JsonObject innerObject) {
184-
FIELD_ACCESSOR.set( innerObject, absoluteFieldPath );
185-
K_ACCESSOR.set( innerObject, k );
186-
if ( filter != null ) {
187-
JsonObject query = filter.toJsonQuery( context );
188-
// we shouldn't get a null query here, since that's only possible if a filter was a knn predicate,
189-
// and in that case we are failing much faster for am Elasticsearch distribution...
190-
FILTER_ACCESSOR.set( innerObject, query );
191-
}
192-
NUM_CANDIDATES_ACCESSOR.set( innerObject, k );
193-
QUERY_VECTOR_ACCESSOR.set( innerObject, vector );
194-
if ( similarity != null ) {
195-
SIMILARITY_ACCESSOR.set( innerObject, similarity );
196-
}
197-
return innerObject;
198-
}
199-
200-
@Override
201-
public void checkNestableWithin(PredicateNestingContext context) {
202-
if ( context.getNestedPath() != null || !context.acceptsKnnClause() ) {
203-
throw log.cannotAddKnnClauseAtThisStep();
204-
}
205-
}
206-
207-
private static class Builder<F> extends AbstractKnnBuilder<F> {
208-
209-
private Builder(ElasticsearchFieldCodec<F> codec, ElasticsearchSearchIndexScope<?> scope,
210-
ElasticsearchSearchIndexValueFieldContext<F> field) {
211-
super( codec, scope, field );
212-
}
213-
214-
@Override
215-
public void constantScore() {
216-
log.elasticsearchKnnIgnoresConstantScore();
217-
}
218-
219-
@Override
220-
public void requiredMinimumSimilarity(float similarity) {
221-
this.similarity = similarity;
222-
}
223-
224-
@Override
225-
public SearchPredicate build() {
226-
return new ElasticsearchImpl( this );
227-
}
228-
}
229-
}
230-
231143
private static class Elasticsearch812Impl extends ElasticsearchKnnPredicate {
232144

233145
private static final JsonObjectAccessor KNN_ACCESSOR = JsonAccessor.root().property( "knn" ).asObject();

backend/elasticsearch/src/main/java/org/hibernate/search/backend/elasticsearch/search/predicate/impl/PredicateNestingContext.java

+6-31
Original file line numberDiff line numberDiff line change
@@ -7,51 +7,26 @@
77
package org.hibernate.search.backend.elasticsearch.search.predicate.impl;
88

99
public class PredicateNestingContext {
10-
private static final PredicateNestingContext ACCEPTS_KNN = new PredicateNestingContext( true );
11-
private static final PredicateNestingContext DOES_NOT_ACCEPT_KNN = new PredicateNestingContext( false );
10+
private static final PredicateNestingContext EMPTY = new PredicateNestingContext();
1211
private final String nestedPath;
13-
private final boolean acceptsKnnClause;
1412

15-
public static PredicateNestingContext acceptsKnn() {
16-
return ACCEPTS_KNN;
17-
}
18-
19-
public static PredicateNestingContext doesNotAcceptKnn() {
20-
return DOES_NOT_ACCEPT_KNN;
13+
public static PredicateNestingContext simple() {
14+
return EMPTY;
2115
}
2216

2317
public static PredicateNestingContext nested(String nestedPath) {
2418
return new PredicateNestingContext( nestedPath );
2519
}
2620

27-
private PredicateNestingContext(String nestedPath, boolean acceptsKnnClause) {
28-
this.nestedPath = nestedPath;
29-
this.acceptsKnnClause = acceptsKnnClause;
30-
}
31-
3221
private PredicateNestingContext(String nestedPath) {
33-
this( nestedPath, false );
22+
this.nestedPath = nestedPath;
3423
}
3524

36-
private PredicateNestingContext(boolean acceptsKnnClause) {
37-
this( null, acceptsKnnClause );
25+
private PredicateNestingContext() {
26+
this( null );
3827
}
3928

4029
public String getNestedPath() {
4130
return nestedPath;
4231
}
43-
44-
public boolean acceptsKnnClause() {
45-
return acceptsKnnClause;
46-
}
47-
48-
public PredicateNestingContext rejectKnn() {
49-
if ( !acceptsKnnClause ) {
50-
return this;
51-
}
52-
if ( nestedPath == null ) {
53-
return DOES_NOT_ACCEPT_KNN;
54-
}
55-
return new PredicateNestingContext( nestedPath, false );
56-
}
5732
}

0 commit comments

Comments
 (0)