Skip to content

Commit b152d50

Browse files
authored
[8.11] Allow mismatched sort-by field types if there are no docs to sort (#102779) (#102834)
* Allow mismatched sort-by field types if there are no docs to sort (#102779) When searching multiple indices and a field only exists in ONE of the indices, we should allow sorting by that field, regardless of the "unmapped" type provided. closes: #102723 (cherry picked from commit 43dc74b) * fixing compile * fixing format
1 parent b5e7a2e commit b152d50

File tree

5 files changed

+40
-9
lines changed

5 files changed

+40
-9
lines changed

docs/changelog/102779.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
pr: 102779
2+
summary: Allow mismatched sort-by field types if there are no docs to sort
3+
area: Search
4+
type: bug
5+
issues: []

server/src/internalClusterTest/java/org/elasticsearch/search/sort/FieldSortIT.java

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ public void testIssue8226() {
149149
}
150150
}
151151

152-
public void testIssue6614() throws ExecutionException, InterruptedException {
152+
public void testIssue6614() throws InterruptedException {
153153
List<IndexRequestBuilder> builders = new ArrayList<>();
154154
boolean strictTimeBasedIndices = randomBoolean();
155155
final int numIndices = randomIntBetween(2, 25); // at most 25 days in the month
@@ -2146,4 +2146,21 @@ public void testSortMixedFieldTypes() {
21462146
}
21472147
}
21482148

2149+
public void testSortMixedFieldTypesWithNoDocsForOneType() {
2150+
assertAcked(prepareCreate("index_long").setMapping("foo", "type=long").get());
2151+
assertAcked(prepareCreate("index_other").setMapping("bar", "type=keyword").get());
2152+
assertAcked(prepareCreate("index_double").setMapping("foo", "type=double").get());
2153+
2154+
client().prepareIndex("index_long").setId("1").setSource("foo", "123").get();
2155+
client().prepareIndex("index_long").setId("2").setSource("foo", "124").get();
2156+
client().prepareIndex("index_other").setId("1").setSource("bar", "124").get();
2157+
refresh();
2158+
2159+
assertNoFailures(
2160+
client().prepareSearch("index_long", "index_double", "index_other")
2161+
.addSort(new FieldSortBuilder("foo").unmappedType("boolean"))
2162+
.setSize(10)
2163+
.get()
2164+
);
2165+
}
21492166
}

server/src/main/java/org/elasticsearch/action/search/SearchPhaseController.java

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -241,8 +241,7 @@ static TopDocs mergeTopDocs(Collection<TopDocs> results, int topN, int from) {
241241
final TopFieldGroups[] shardTopDocs = results.toArray(new TopFieldGroups[numShards]);
242242
mergedTopDocs = TopFieldGroups.merge(sort, from, topN, shardTopDocs, false);
243243
} else if (topDocs instanceof TopFieldDocs firstTopDocs) {
244-
checkSameSortTypes(results, firstTopDocs.fields);
245-
final Sort sort = new Sort(firstTopDocs.fields);
244+
final Sort sort = checkSameSortTypes(results, firstTopDocs.fields);
246245
final TopFieldDocs[] shardTopDocs = results.toArray(new TopFieldDocs[numShards]);
247246
mergedTopDocs = TopDocs.merge(sort, from, topN, shardTopDocs);
248247
} else {
@@ -252,19 +251,26 @@ static TopDocs mergeTopDocs(Collection<TopDocs> results, int topN, int from) {
252251
return mergedTopDocs;
253252
}
254253

255-
private static void checkSameSortTypes(Collection<TopDocs> results, SortField[] firstSortFields) {
256-
if (results.size() < 2) return;
254+
private static Sort checkSameSortTypes(Collection<TopDocs> results, SortField[] firstSortFields) {
255+
Sort sort = new Sort(firstSortFields);
256+
if (results.size() < 2) return sort;
257257

258-
SortField.Type[] firstTypes = new SortField.Type[firstSortFields.length];
258+
SortField.Type[] firstTypes = null;
259259
boolean isFirstResult = true;
260260
for (TopDocs topDocs : results) {
261+
// We don't actually merge in empty score docs, so ignore potentially mismatched types if there are no docs
262+
if (topDocs.scoreDocs == null || topDocs.scoreDocs.length == 0) {
263+
continue;
264+
}
261265
SortField[] curSortFields = ((TopFieldDocs) topDocs).fields;
262266
if (isFirstResult) {
267+
sort = new Sort(curSortFields);
268+
firstTypes = new SortField.Type[curSortFields.length];
263269
for (int i = 0; i < curSortFields.length; i++) {
264-
firstTypes[i] = getType(firstSortFields[i]);
270+
firstTypes[i] = getType(curSortFields[i]);
265271
if (firstTypes[i] == SortField.Type.CUSTOM) {
266272
// for custom types that we can't resolve, we can't do the check
267-
return;
273+
return sort;
268274
}
269275
}
270276
isFirstResult = false;
@@ -274,7 +280,7 @@ private static void checkSameSortTypes(Collection<TopDocs> results, SortField[]
274280
if (curType != firstTypes[i]) {
275281
if (curType == SortField.Type.CUSTOM) {
276282
// for custom types that we can't resolve, we can't do the check
277-
return;
283+
return sort;
278284
}
279285
throw new IllegalArgumentException(
280286
"Can't sort on field ["
@@ -289,6 +295,7 @@ private static void checkSameSortTypes(Collection<TopDocs> results, SortField[]
289295
}
290296
}
291297
}
298+
return sort;
292299
}
293300

294301
private static SortField.Type getType(SortField sortField) {

server/src/main/java/org/elasticsearch/action/search/SearchResponse.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -538,6 +538,7 @@ public Clusters(int total, int successful, int skipped) {
538538
this.clusterInfo = Collections.emptyMap(); // will never be used if created from this constructor
539539
}
540540

541+
@SuppressWarnings("this-escape")
541542
public Clusters(StreamInput in) throws IOException {
542543
this.total = in.readVInt();
543544
int successfulTemp = in.readVInt();

server/src/main/java/org/elasticsearch/action/support/HandledTransportAction.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ protected HandledTransportAction(
5959
this(actionName, canTripCircuitBreaker, transportService, actionFilters, requestReader, EsExecutors.DIRECT_EXECUTOR_SERVICE);
6060
}
6161

62+
@SuppressWarnings("this-escape")
6263
protected HandledTransportAction(
6364
String actionName,
6465
boolean canTripCircuitBreaker,

0 commit comments

Comments
 (0)