From 9c0108d9d16d1dafcc2ae14ef65d6fa182e928dd Mon Sep 17 00:00:00 2001 From: Alan Woodward Date: Thu, 11 Dec 2025 10:22:23 +0000 Subject: [PATCH] Add test for int-to-long sort BWC conversion --- .../elasticsearch/common/lucene/Lucene.java | 20 +++++----- .../search/sort/AbstractSortTestCase.java | 12 +++++- .../search/sort/FieldSortBuilderTests.java | 40 +++++++++++++++++++ 3 files changed, 60 insertions(+), 12 deletions(-) diff --git a/server/src/main/java/org/elasticsearch/common/lucene/Lucene.java b/server/src/main/java/org/elasticsearch/common/lucene/Lucene.java index 0ef0e3ffa28c8..b22768e4729c4 100644 --- a/server/src/main/java/org/elasticsearch/common/lucene/Lucene.java +++ b/server/src/main/java/org/elasticsearch/common/lucene/Lucene.java @@ -625,7 +625,7 @@ public static void writeSortType(StreamOutput out, SortField.Type sortType) thro * Returns the generic version of the provided {@link SortField} that * can be used to merge documents coming from different shards. */ - private static SortField rewriteMergeSortField(SortField sortField) { + public static SortField rewriteMergeSortField(SortField sortField) { if (sortField.getClass() == GEO_DISTANCE_SORT_TYPE_CLASS) { SortField newSortField = new SortField(sortField.getField(), SortField.Type.DOUBLE); newSortField.setMissingValue(sortField.getMissingValue()); @@ -642,6 +642,13 @@ private static SortField rewriteMergeSortField(SortField sortField) { ); newSortField.setMissingValue(sortField.getMissingValue()); return newSortField; + } else if (sortField.getComparatorSource() instanceof IndexFieldData.XFieldComparatorSource fcs) { + SortField newSortField = new SortField(sortField.getField(), fcs.reducedType(), sortField.getReverse()); + Object missingValue = fcs.missingValue(sortField.getReverse()); + if (missingValue != null) { + newSortField.setMissingValue(missingValue); + } + return newSortField; } else if (sortField.getClass() == ShardDocSortField.class) { return new SortField(sortField.getField(), SortField.Type.LONG, sortField.getReverse()); } else { @@ -655,15 +662,8 @@ static void writeSortField(StreamOutput out, SortField sortField) throws IOExcep throw new IllegalArgumentException("Cannot serialize SortField impl [" + sortField + "]"); } out.writeOptionalString(sortField.getField()); - if (sortField.getComparatorSource() != null) { - IndexFieldData.XFieldComparatorSource comparatorSource = (IndexFieldData.XFieldComparatorSource) sortField - .getComparatorSource(); - writeSortType(out, comparatorSource.reducedType()); - writeMissingValue(out, comparatorSource.missingValue(sortField.getReverse())); - } else { - writeSortType(out, sortField.getType()); - writeMissingValue(out, sortField.getMissingValue()); - } + writeSortType(out, sortField.getType()); + writeMissingValue(out, sortField.getMissingValue()); out.writeBoolean(sortField.getReverse()); } diff --git a/server/src/test/java/org/elasticsearch/search/sort/AbstractSortTestCase.java b/server/src/test/java/org/elasticsearch/search/sort/AbstractSortTestCase.java index 2a43046d5f23d..ddd330ab6196c 100644 --- a/server/src/test/java/org/elasticsearch/search/sort/AbstractSortTestCase.java +++ b/server/src/test/java/org/elasticsearch/search/sort/AbstractSortTestCase.java @@ -183,14 +183,22 @@ public void testEqualsAndHashcode() { } protected final SearchExecutionContext createMockSearchExecutionContext() { - return createMockSearchExecutionContext(null); + return createMockSearchExecutionContext(null, IndexVersion.current()); + } + + protected final SearchExecutionContext createMockSearchExecutionContext(IndexVersion indexVersion) { + return createMockSearchExecutionContext(null, indexVersion); } protected final SearchExecutionContext createMockSearchExecutionContext(IndexSearcher searcher) { + return createMockSearchExecutionContext(searcher, IndexVersion.current()); + } + + protected final SearchExecutionContext createMockSearchExecutionContext(IndexSearcher searcher, IndexVersion indexVersion) { Index index = new Index(randomAlphaOfLengthBetween(1, 10), "_na_"); IndexSettings idxSettings = IndexSettingsModule.newIndexSettings( index, - Settings.builder().put(IndexMetadata.SETTING_VERSION_CREATED, IndexVersion.current()).build() + Settings.builder().put(IndexMetadata.SETTING_VERSION_CREATED, indexVersion).build() ); BitsetFilterCache bitsetFilterCache = new BitsetFilterCache(idxSettings, mock(BitsetFilterCache.Listener.class)); BiFunction> indexFieldDataLookup = (fieldType, fdc) -> { diff --git a/server/src/test/java/org/elasticsearch/search/sort/FieldSortBuilderTests.java b/server/src/test/java/org/elasticsearch/search/sort/FieldSortBuilderTests.java index 521f6e9b5eb2f..68cb24521b66f 100644 --- a/server/src/test/java/org/elasticsearch/search/sort/FieldSortBuilderTests.java +++ b/server/src/test/java/org/elasticsearch/search/sort/FieldSortBuilderTests.java @@ -31,6 +31,9 @@ import org.apache.lucene.tests.index.RandomIndexWriter; import org.apache.lucene.tests.search.AssertingIndexSearcher; import org.apache.lucene.util.BytesRef; +import org.elasticsearch.common.lucene.Lucene; +import org.elasticsearch.index.IndexVersion; +import org.elasticsearch.index.IndexVersions; import org.elasticsearch.index.fielddata.IndexFieldData.XFieldComparatorSource; import org.elasticsearch.index.fielddata.IndexFieldData.XFieldComparatorSource.Nested; import org.elasticsearch.index.mapper.DateFieldMapper; @@ -48,6 +51,7 @@ import org.elasticsearch.search.MultiValueMode; import org.elasticsearch.search.SearchSortValuesAndFormats; import org.elasticsearch.search.builder.SearchSourceBuilder; +import org.elasticsearch.test.index.IndexVersionUtils; import org.elasticsearch.xcontent.XContentParseException; import org.elasticsearch.xcontent.XContentParser; import org.elasticsearch.xcontent.json.JsonXContent; @@ -657,4 +661,40 @@ public void testIsBottomSortShardDisjoint() throws Exception { protected FieldSortBuilder fromXContent(XContentParser parser, String fieldName) throws IOException { return FieldSortBuilder.fromXContent(parser, fieldName); } + + public void testIntRewritesToLong() throws Exception { + + assertIntegerSortRewrite( + IndexVersionUtils.randomPreviousCompatibleVersion(random(), IndexVersions.INDEX_INT_SORT_INT_TYPE_8_19), + SortField.Type.LONG + ); + assertIntegerSortRewrite( + IndexVersionUtils.randomVersionBetween( + random(), + IndexVersions.INDEX_INT_SORT_INT_TYPE_8_19, + IndexVersionUtils.getPreviousVersion(IndexVersions.UPGRADE_TO_LUCENE_10_0_0) + ), + SortField.Type.INT + ); + assertIntegerSortRewrite( + IndexVersionUtils.randomVersionBetween( + random(), + IndexVersions.UPGRADE_TO_LUCENE_10_0_0, + IndexVersionUtils.getPreviousVersion(IndexVersions.INDEX_INT_SORT_INT_TYPE) + ), + SortField.Type.LONG + ); + assertIntegerSortRewrite( + IndexVersionUtils.randomVersionBetween(random(), IndexVersions.INDEX_INT_SORT_INT_TYPE, IndexVersion.current()), + SortField.Type.INT + ); + assertIntegerSortRewrite(IndexVersion.current(), SortField.Type.INT); + } + + private void assertIntegerSortRewrite(IndexVersion version, SortField.Type expectedType) throws IOException { + FieldSortBuilder builder = new FieldSortBuilder("custom-integer"); + SortFieldAndFormat sff = builder.build(createMockSearchExecutionContext(version)); + SortField sf = Lucene.rewriteMergeSortField(sff.field()); + assertThat(sf.getType(), equalTo(expectedType)); + } }