|
18 | 18 | import org.elasticsearch.common.Strings; |
19 | 19 | import org.elasticsearch.common.io.stream.StreamInput; |
20 | 20 | import org.elasticsearch.common.io.stream.StreamOutput; |
| 21 | +import org.elasticsearch.index.query.BoolQueryBuilder; |
| 22 | +import org.elasticsearch.index.query.BoostingQueryBuilder; |
| 23 | +import org.elasticsearch.index.query.ConstantScoreQueryBuilder; |
| 24 | +import org.elasticsearch.index.query.DisMaxQueryBuilder; |
| 25 | +import org.elasticsearch.index.query.NestedQueryBuilder; |
21 | 26 | import org.elasticsearch.index.query.QueryBuilder; |
| 27 | +import org.elasticsearch.index.query.functionscore.FunctionScoreQueryBuilder; |
22 | 28 | import org.elasticsearch.tasks.CancellableTask; |
23 | 29 | import org.elasticsearch.tasks.Task; |
24 | 30 | import org.elasticsearch.tasks.TaskId; |
@@ -268,9 +274,53 @@ public ActionRequestValidationException validate() { |
268 | 274 | if (fields == null || fields.length == 0) { |
269 | 275 | validationException = ValidateActions.addValidationError("no fields specified", validationException); |
270 | 276 | } |
| 277 | + |
| 278 | + // Band-aid fix for https://github.com/elastic/elasticsearch/issues/116106. |
| 279 | + // Semantic queries are high-recall queries, making them poor filters and effectively the same as an exists query when used in that |
| 280 | + // context. |
| 281 | + if (containsSemanticQuery(indexFilter)) { |
| 282 | + validationException = ValidateActions.addValidationError( |
| 283 | + "index filter cannot contain semantic queries. Use an exists query instead.", |
| 284 | + validationException |
| 285 | + ); |
| 286 | + } |
| 287 | + |
271 | 288 | return validationException; |
272 | 289 | } |
273 | 290 |
|
| 291 | + /** |
| 292 | + * Recursively checks if a query builder contains any semantic queries |
| 293 | + */ |
| 294 | + private static boolean containsSemanticQuery(QueryBuilder queryBuilder) { |
| 295 | + boolean containsSemanticQuery = false; |
| 296 | + |
| 297 | + if (queryBuilder == null) { |
| 298 | + return containsSemanticQuery; |
| 299 | + } |
| 300 | + |
| 301 | + if ("semantic".equals(queryBuilder.getWriteableName())) { |
| 302 | + containsSemanticQuery = true; |
| 303 | + } else if (queryBuilder instanceof BoolQueryBuilder boolQuery) { |
| 304 | + return boolQuery.must().stream().anyMatch(FieldCapabilitiesRequest::containsSemanticQuery) |
| 305 | + || boolQuery.mustNot().stream().anyMatch(FieldCapabilitiesRequest::containsSemanticQuery) |
| 306 | + || boolQuery.should().stream().anyMatch(FieldCapabilitiesRequest::containsSemanticQuery) |
| 307 | + || boolQuery.filter().stream().anyMatch(FieldCapabilitiesRequest::containsSemanticQuery); |
| 308 | + } else if (queryBuilder instanceof DisMaxQueryBuilder disMaxQuery) { |
| 309 | + containsSemanticQuery = disMaxQuery.innerQueries().stream().anyMatch(FieldCapabilitiesRequest::containsSemanticQuery); |
| 310 | + } else if (queryBuilder instanceof NestedQueryBuilder nestedQuery) { |
| 311 | + containsSemanticQuery = containsSemanticQuery(nestedQuery.query()); |
| 312 | + } else if (queryBuilder instanceof BoostingQueryBuilder boostingQuery) { |
| 313 | + containsSemanticQuery = containsSemanticQuery(boostingQuery.positiveQuery()) |
| 314 | + || containsSemanticQuery(boostingQuery.negativeQuery()); |
| 315 | + } else if (queryBuilder instanceof ConstantScoreQueryBuilder constantScoreQuery) { |
| 316 | + containsSemanticQuery = containsSemanticQuery(constantScoreQuery.innerQuery()); |
| 317 | + } else if (queryBuilder instanceof FunctionScoreQueryBuilder functionScoreQuery) { |
| 318 | + containsSemanticQuery = containsSemanticQuery(functionScoreQuery.query()); |
| 319 | + } |
| 320 | + |
| 321 | + return containsSemanticQuery; |
| 322 | + } |
| 323 | + |
274 | 324 | @Override |
275 | 325 | public boolean equals(Object o) { |
276 | 326 | if (this == o) return true; |
|
0 commit comments