Skip to content

Commit 61fa647

Browse files
authored
Split index-time and search-time sort definitions (#137880)
At search time, we can now always use our custom comparators that allow pruning on secondary sorts. At index time, we need to always use Lucene SortFields, which is fine as pruning isn't used at this point in any case.
1 parent e447873 commit 61fa647

File tree

14 files changed

+149
-91
lines changed

14 files changed

+149
-91
lines changed

server/src/main/java/org/elasticsearch/index/IndexSortConfig.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -375,7 +375,7 @@ public Sort buildIndexSort(
375375
if (fieldData == null) {
376376
throw new IllegalArgumentException("docvalues not found for index sort field:[" + sortSpec.field + "]");
377377
}
378-
sortFields[i] = fieldData.sortField(this.indexCreatedVersion, sortSpec.missingValue, mode, null, reverse);
378+
sortFields[i] = fieldData.indexSort(this.indexCreatedVersion, sortSpec.missingValue, mode, reverse);
379379
validateIndexSortField(sortFields[i]);
380380
}
381381
return new Sort(sortFields);
@@ -430,6 +430,8 @@ public static SortField.Type getSortFieldType(SortField sortField) {
430430
return SortField.Type.STRING;
431431
} else if (sortField instanceof SortedNumericSortField) {
432432
return ((SortedNumericSortField) sortField).getNumericType();
433+
} else if (sortField.getComparatorSource() instanceof IndexFieldData.XFieldComparatorSource fcs) {
434+
return fcs.sortType();
433435
} else {
434436
return sortField.getType();
435437
}

server/src/main/java/org/elasticsearch/index/fielddata/IndexFieldData.java

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,13 +69,20 @@ public interface IndexFieldData<FD extends LeafFieldData> {
6969
* Returns the {@link SortField} to use for sorting depending on the version of the index.
7070
*/
7171
default SortField sortField(
72+
boolean indexSort,
7273
IndexVersion indexCreatedVersion,
7374
@Nullable Object missingValue,
7475
MultiValueMode sortMode,
7576
Nested nested,
7677
boolean reverse
7778
) {
78-
return sortField(missingValue, sortMode, nested, reverse);
79+
return indexSort
80+
? indexSort(indexCreatedVersion, missingValue, sortMode, reverse)
81+
: sortField(missingValue, sortMode, nested, reverse);
82+
}
83+
84+
default SortField indexSort(IndexVersion indexCreatedVersion, @Nullable Object missingValue, MultiValueMode sortMode, boolean reverse) {
85+
return sortField(missingValue, sortMode, null, reverse);
7986
}
8087

8188
/**
@@ -231,6 +238,10 @@ public Object missingObject(Object missingValue, boolean reversed) {
231238

232239
public abstract SortField.Type reducedType();
233240

241+
public SortField.Type sortType() {
242+
return reducedType();
243+
}
244+
234245
/**
235246
* Return a missing value that is understandable by {@link SortField#setMissingValue(Object)}.
236247
* Most implementations return null because they already replace the value at the fielddata level.

server/src/main/java/org/elasticsearch/index/fielddata/IndexNumericFieldData.java

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ public final ValuesSourceType getValuesSourceType() {
8686
* match the field's <code>numericType</code>.
8787
*/
8888
public final SortField sortField(
89+
boolean indexSort,
8990
NumericType targetNumericType,
9091
Object missingValue,
9192
MultiValueMode sortMode,
@@ -104,7 +105,7 @@ public final SortField sortField(
104105
boolean requiresCustomComparator = nested != null
105106
|| (sortMode != MultiValueMode.MAX && sortMode != MultiValueMode.MIN)
106107
|| targetNumericType != getNumericType();
107-
if (sortRequiresCustomComparator() || requiresCustomComparator) {
108+
if (indexSort == false || sortRequiresCustomComparator()) {
108109
SortField sortField = new SortField(getFieldName(), source, reverse);
109110
sortField.setOptimizeSortWithPoints(requiresCustomComparator == false && canUseOptimizedSort(indexType()));
110111
return sortField;
@@ -138,18 +139,24 @@ private static boolean canUseOptimizedSort(IndexType indexType) {
138139

139140
@Override
140141
public final SortField sortField(Object missingValue, MultiValueMode sortMode, Nested nested, boolean reverse) {
141-
return sortField(getNumericType(), missingValue, sortMode, nested, reverse);
142+
return sortField(false, getNumericType(), missingValue, sortMode, nested, reverse);
143+
}
144+
145+
@Override
146+
public SortField indexSort(IndexVersion indexCreatedVersion, Object missingValue, MultiValueMode sortMode, boolean reverse) {
147+
return sortField(true, indexCreatedVersion, missingValue, sortMode, null, reverse);
142148
}
143149

144150
@Override
145151
public SortField sortField(
152+
boolean indexSort,
146153
IndexVersion indexCreatedVersion,
147154
Object missingValue,
148155
MultiValueMode sortMode,
149156
Nested nested,
150157
boolean reverse
151158
) {
152-
SortField sortField = sortField(missingValue, sortMode, nested, reverse);
159+
SortField sortField = sortField(indexSort, getNumericType(), missingValue, sortMode, nested, reverse);
153160
if (getNumericType() == NumericType.DATE_NANOSECONDS
154161
&& indexCreatedVersion.before(IndexVersions.V_7_14_0)
155162
&& missingValue.equals("_last")

server/src/main/java/org/elasticsearch/index/fielddata/fieldcomparator/DoubleValuesComparatorSource.java

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -78,9 +78,7 @@ public FieldComparator<?> newComparator(String fieldname, int numHits, Pruning e
7878
assert indexFieldData == null || fieldname.equals(indexFieldData.getFieldName());
7979

8080
final double dMissingValue = (Double) missingObject(missingValue, reversed);
81-
// NOTE: it's important to pass null as a missing value in the constructor so that
82-
// the comparator doesn't check docsWithField since we replace missing values in select()
83-
return new DoubleComparator(numHits, fieldname, null, reversed, enableSkipping) {
81+
return new DoubleComparator(numHits, fieldname, dMissingValue, reversed, enableSkipping) {
8482
@Override
8583
public LeafFieldComparator getLeafComparator(LeafReaderContext context) throws IOException {
8684
return new DoubleLeafComparator(context) {

server/src/main/java/org/elasticsearch/index/fielddata/fieldcomparator/FloatValuesComparatorSource.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ public FieldComparator<?> newComparator(String fieldname, int numHits, Pruning e
7373
final float fMissingValue = (Float) missingObject(missingValue, reversed);
7474
// NOTE: it's important to pass null as a missing value in the constructor so that
7575
// the comparator doesn't check docsWithField since we replace missing values in select()
76-
return new FloatComparator(numHits, fieldname, null, reversed, enableSkipping) {
76+
return new FloatComparator(numHits, fieldname, fMissingValue, reversed, enableSkipping) {
7777
@Override
7878
public LeafFieldComparator getLeafComparator(LeafReaderContext context) throws IOException {
7979
return new FloatLeafComparator(context) {

server/src/main/java/org/elasticsearch/index/fielddata/fieldcomparator/HalfFloatValuesComparatorSource.java

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
import org.apache.lucene.search.FieldComparator;
1414
import org.apache.lucene.search.LeafFieldComparator;
1515
import org.apache.lucene.search.Pruning;
16+
import org.apache.lucene.search.SortField;
1617
import org.elasticsearch.core.Nullable;
1718
import org.elasticsearch.index.fielddata.DenseDoubleValues;
1819
import org.elasticsearch.index.fielddata.IndexNumericFieldData;
@@ -33,14 +34,17 @@ public HalfFloatValuesComparatorSource(
3334
super(indexFieldData, missingValue, sortMode, nested);
3435
}
3536

37+
@Override
38+
public SortField.Type sortType() {
39+
return SortField.Type.CUSTOM;
40+
}
41+
3642
@Override
3743
public FieldComparator<?> newComparator(String fieldname, int numHits, Pruning enableSkipping, boolean reversed) {
3844
assert indexFieldData == null || fieldname.equals(indexFieldData.getFieldName());
3945

4046
final float fMissingValue = (Float) missingObject(missingValue, reversed);
41-
// NOTE: it's important to pass null as a missing value in the constructor so that
42-
// the comparator doesn't check docsWithField since we replace missing values in select()
43-
return new HalfFloatComparator(numHits, fieldname, null, reversed, enableSkipping) {
47+
return new HalfFloatComparator(numHits, fieldname, fMissingValue, reversed, enableSkipping) {
4448
@Override
4549
public LeafFieldComparator getLeafComparator(LeafReaderContext context) throws IOException {
4650
return new HalfFloatLeafComparator(context) {

server/src/main/java/org/elasticsearch/index/fielddata/fieldcomparator/IntValuesComparatorSource.java

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,9 +52,7 @@ public FieldComparator<?> newComparator(String fieldname, int numHits, Pruning e
5252
assert indexFieldData == null || fieldname.equals(indexFieldData.getFieldName());
5353

5454
final int iMissingValue = (Integer) missingObject(missingValue, reversed);
55-
// NOTE: it's important to pass null as a missing value in the constructor so that
56-
// the comparator doesn't check docsWithField since we replace missing values in select()
57-
return new IntComparator(numHits, fieldname, null, reversed, enableSkipping) {
55+
return new IntComparator(numHits, fieldname, iMissingValue, reversed, enableSkipping) {
5856
@Override
5957
public LeafFieldComparator getLeafComparator(LeafReaderContext context) throws IOException {
6058
return new IntLeafComparator(context) {

server/src/main/java/org/elasticsearch/index/fielddata/fieldcomparator/LongValuesComparatorSource.java

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -105,9 +105,7 @@ public FieldComparator<?> newComparator(String fieldname, int numHits, Pruning e
105105
assert indexFieldData == null || fieldname.equals(indexFieldData.getFieldName());
106106

107107
final long lMissingValue = (Long) missingObject(missingValue, reversed);
108-
// NOTE: it's important to pass null as a missing value in the constructor so that
109-
// the comparator doesn't check docsWithField since we replace missing values in select()
110-
return new XLongComparator(numHits, fieldname, null, reversed, enableSkipping) {
108+
return new XLongComparator(numHits, fieldname, lMissingValue, reversed, enableSkipping) {
111109
@Override
112110
public LeafFieldComparator getLeafComparator(LeafReaderContext context) throws IOException {
113111
final int maxDoc = context.reader().maxDoc();

server/src/main/java/org/elasticsearch/lucene/comparators/XUpdateableDocIdSetIterator.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,4 +69,8 @@ public int docIDRunEnd() throws IOException {
6969
return super.docIDRunEnd();
7070
}
7171
}
72+
73+
public DocIdSetIterator getDelegate() {
74+
return in;
75+
}
7276
}

server/src/main/java/org/elasticsearch/search/sort/FieldSortBuilder.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -355,10 +355,10 @@ public SortFieldAndFormat build(SearchExecutionContext context) throws IOExcepti
355355
}
356356
IndexNumericFieldData numericFieldData = (IndexNumericFieldData) fieldData;
357357
NumericType resolvedType = resolveNumericType(numericType);
358-
field = numericFieldData.sortField(resolvedType, missing, localSortMode(), nested, reverse);
358+
field = numericFieldData.sortField(false, resolvedType, missing, localSortMode(), nested, reverse);
359359
isNanosecond = resolvedType == NumericType.DATE_NANOSECONDS;
360360
} else {
361-
field = fieldData.sortField(context.indexVersionCreated(), missing, localSortMode(), nested, reverse);
361+
field = fieldData.sortField(false, context.indexVersionCreated(), missing, localSortMode(), nested, reverse);
362362
if (fieldData instanceof IndexNumericFieldData) {
363363
isNanosecond = ((IndexNumericFieldData) fieldData).getNumericType() == NumericType.DATE_NANOSECONDS;
364364
}

0 commit comments

Comments
 (0)