From f3973f5055b5d94a2007d642fc33c039eb9910f2 Mon Sep 17 00:00:00 2001 From: Jim Ferenczi Date: Wed, 19 Jun 2024 12:03:27 +0100 Subject: [PATCH] Fix detection of invalid mixed sort fields Sort fields are usually rewritten into their merge form during transport serialization. For searches where all shards are local to the coordinating node, this serialization is not applied, and sort fields remain in their original form. This is typically not an issue except when checking sort compatibility, as we rely on the primary type of the sort field. This change ensures we extract the correct type even if the sort field is in its primary form (with a CUSTOM type) using the original comparator source. The only field type that benefits from this change afaik is the constant_keyword field type. When a sort field is a mix of numeric and constant_keyword, this change ensures the discrepancy is correctly reported to the user. --- .../action/search/SearchPhaseController.java | 11 ++-- .../resources/rest-api-spec/test/30_sort.yml | 65 +++++++++++++++++++ 2 files changed, 72 insertions(+), 4 deletions(-) create mode 100644 x-pack/plugin/mapper-constant-keyword/src/yamlRestTest/resources/rest-api-spec/test/30_sort.yml diff --git a/server/src/main/java/org/elasticsearch/action/search/SearchPhaseController.java b/server/src/main/java/org/elasticsearch/action/search/SearchPhaseController.java index 55c754545cbbe..82c498c64e1c9 100644 --- a/server/src/main/java/org/elasticsearch/action/search/SearchPhaseController.java +++ b/server/src/main/java/org/elasticsearch/action/search/SearchPhaseController.java @@ -28,6 +28,7 @@ import org.elasticsearch.common.lucene.search.TopDocsAndMaxScore; import org.elasticsearch.common.util.Maps; import org.elasticsearch.common.util.concurrent.AtomicArray; +import org.elasticsearch.index.fielddata.IndexFieldData; import org.elasticsearch.lucene.grouping.TopFieldGroups; import org.elasticsearch.search.DocValueFormat; import org.elasticsearch.search.SearchHit; @@ -301,11 +302,13 @@ private static Sort checkSameSortTypes(Collection results, SortField[] } private static SortField.Type getType(SortField sortField) { - if (sortField instanceof SortedNumericSortField) { - return ((SortedNumericSortField) sortField).getNumericType(); - } - if (sortField instanceof SortedSetSortField) { + if (sortField instanceof SortedNumericSortField sf) { + return sf.getNumericType(); + } else if (sortField instanceof SortedSetSortField) { return SortField.Type.STRING; + } else if (sortField.getComparatorSource() instanceof IndexFieldData.XFieldComparatorSource cmp) { + // This can occur if the sort field wasn't rewritten by Lucene#rewriteMergeSortField because all search shards are local. + return cmp.reducedType(); } else { return sortField.getType(); } diff --git a/x-pack/plugin/mapper-constant-keyword/src/yamlRestTest/resources/rest-api-spec/test/30_sort.yml b/x-pack/plugin/mapper-constant-keyword/src/yamlRestTest/resources/rest-api-spec/test/30_sort.yml new file mode 100644 index 0000000000000..8d489b8211eb1 --- /dev/null +++ b/x-pack/plugin/mapper-constant-keyword/src/yamlRestTest/resources/rest-api-spec/test/30_sort.yml @@ -0,0 +1,65 @@ +setup: + - do: + indices.create: + index: test + body: + mappings: + properties: + keyword: + type: keyword + + - do: + indices.create: + index: test_numeric + body: + mappings: + properties: + keyword: + type: long + + - do: + indices.create: + index: test_constant + body: + mappings: + properties: + keyword: + type: constant_keyword + value: value + + - do: + bulk: + refresh: true + body: | + { "index": {"_index" : "test", "_id": 3} } + { "keyword": "abc" } + { "index": {"_index" : "test_numeric", "_id": 2} } + { "keyword": 42 } + { "index": {"_index" : "test_constant", "_id": 1} } + {} + +--- +"constant_keyword mixed sort": + - do: + search: + index: test,test_constant + body: + sort: keyword + + - match: { hits.total.value: 2 } + - match: { hits.hits.0._id: "3" } + - match: { hits.hits.1._id: "1" } + +--- +"constant_keyword invalid mixed sort": + - requires: + cluster_features: [ "gte_v8.15.0" ] + reason: Better error message in 8.15.0 + + - do: + catch: /Can't sort on field \[keyword\]\; the field has incompatible sort types/ + search: + index: test* + body: + sort: keyword +