Skip to content

Commit bd2fc15

Browse files
authored
Address MinAndMax generics warnings (#52642)
`MinAndMax` encapsulates min and max values for a shard. It uses generics to make sure that the values are of the same type and are also comparable. Though there are warnings whenever this class is currently used, which are addressed with this commit. Relates to #49092
1 parent 427c9a0 commit bd2fc15

File tree

4 files changed

+63
-74
lines changed

4 files changed

+63
-74
lines changed

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ private static boolean shouldSortShards(MinAndMax<?>[] minAndMaxes) {
133133
private static Comparator<Integer> shardComparator(GroupShardsIterator<SearchShardIterator> shardsIts,
134134
MinAndMax<?>[] minAndMaxes,
135135
SortOrder order) {
136-
final Comparator<Integer> comparator = Comparator.comparing(index -> minAndMaxes[index], MinAndMax.getComparator(order));
136+
final Comparator<Integer> comparator = Comparator.comparing(index -> minAndMaxes[index], MinAndMax.getComparator(order));
137137
return comparator.thenComparing(index -> shardsIts.get(index).shardId());
138138
}
139139

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

+52-60
Original file line numberDiff line numberDiff line change
@@ -429,46 +429,6 @@ public static FieldSortBuilder getPrimaryFieldSortOrNull(SearchSourceBuilder sou
429429
return source.sorts().get(0) instanceof FieldSortBuilder ? (FieldSortBuilder) source.sorts().get(0) : null;
430430
}
431431

432-
/**
433-
* Return a {@link Function} that converts a serialized point into a {@link Number} according to the provided
434-
* {@link SortField}. This is needed for {@link SortField} that converts values from one type to another using
435-
* {@link FieldSortBuilder#setNumericType(String)} )} (e.g.: long to double).
436-
*/
437-
private static Function<byte[], Comparable> numericPointConverter(SortField sortField, NumberFieldType numberFieldType) {
438-
switch (IndexSortConfig.getSortFieldType(sortField)) {
439-
case LONG:
440-
return v -> numberFieldType.parsePoint(v).longValue();
441-
442-
case INT:
443-
return v -> numberFieldType.parsePoint(v).intValue();
444-
445-
case DOUBLE:
446-
return v -> numberFieldType.parsePoint(v).doubleValue();
447-
448-
case FLOAT:
449-
return v -> numberFieldType.parsePoint(v).floatValue();
450-
451-
default:
452-
return v -> null;
453-
}
454-
}
455-
456-
/**
457-
* Return a {@link Function} that converts a serialized date point into a {@link Long} according to the provided
458-
* {@link NumericType}.
459-
*/
460-
private static Function<byte[], Comparable> datePointConverter(DateFieldType dateFieldType, String numericTypeStr) {
461-
if (numericTypeStr != null) {
462-
NumericType numericType = resolveNumericType(numericTypeStr);
463-
if (dateFieldType.resolution() == MILLISECONDS && numericType == NumericType.DATE_NANOSECONDS) {
464-
return v -> DateUtils.toNanoSeconds(LongPoint.decodeDimension(v, 0));
465-
} else if (dateFieldType.resolution() == NANOSECONDS && numericType == NumericType.DATE) {
466-
return v -> DateUtils.toMilliSeconds(LongPoint.decodeDimension(v, 0));
467-
}
468-
}
469-
return v -> LongPoint.decodeDimension(v, 0);
470-
}
471-
472432
/**
473433
* Return the {@link MinAndMax} indexed value from the provided {@link FieldSortBuilder} or <code>null</code> if unknown.
474434
* The value can be extracted on non-nested indexed mapped fields of type keyword, numeric or date, other fields
@@ -485,41 +445,73 @@ public static MinAndMax<?> getMinMaxOrNull(QueryShardContext context, FieldSortB
485445
if (reader == null || (fieldType == null || fieldType.indexOptions() == IndexOptions.NONE)) {
486446
return null;
487447
}
488-
String fieldName = fieldType.name();
489448
switch (IndexSortConfig.getSortFieldType(sortField)) {
490449
case LONG:
491450
case INT:
492451
case DOUBLE:
493452
case FLOAT:
494-
final Function<byte[], Comparable> converter;
495-
if (fieldType instanceof NumberFieldType) {
496-
converter = numericPointConverter(sortField, (NumberFieldType) fieldType);
497-
} else if (fieldType instanceof DateFieldType) {
498-
converter = datePointConverter((DateFieldType) fieldType, sortBuilder.getNumericType());
499-
} else {
500-
return null;
501-
}
502-
if (PointValues.size(reader, fieldName) == 0) {
503-
return null;
504-
}
505-
final Comparable min = converter.apply(PointValues.getMinPackedValue(reader, fieldName));
506-
final Comparable max = converter.apply(PointValues.getMaxPackedValue(reader, fieldName));
507-
return MinAndMax.newMinMax(min, max);
508-
453+
return extractNumericMinAndMax(reader, sortField, fieldType, sortBuilder);
509454
case STRING:
510455
case STRING_VAL:
511456
if (fieldType instanceof KeywordFieldMapper.KeywordFieldType) {
512-
Terms terms = MultiTerms.getTerms(reader, fieldName);
457+
Terms terms = MultiTerms.getTerms(reader, fieldType.name());
513458
if (terms == null) {
514459
return null;
515460
}
516-
return terms.getMin() != null ? MinAndMax.newMinMax(terms.getMin(), terms.getMax()) : null;
461+
return terms.getMin() != null ? new MinAndMax<>(terms.getMin(), terms.getMax()) : null;
517462
}
518463
break;
519464
}
520465
return null;
521466
}
522467

468+
private static MinAndMax<?> extractNumericMinAndMax(IndexReader reader,
469+
SortField sortField,
470+
MappedFieldType fieldType,
471+
FieldSortBuilder sortBuilder) throws IOException {
472+
String fieldName = fieldType.name();
473+
if (PointValues.size(reader, fieldName) == 0) {
474+
return null;
475+
}
476+
if (fieldType instanceof NumberFieldType) {
477+
NumberFieldType numberFieldType = (NumberFieldType) fieldType;
478+
Number minPoint = numberFieldType.parsePoint(PointValues.getMinPackedValue(reader, fieldName));
479+
Number maxPoint = numberFieldType.parsePoint(PointValues.getMaxPackedValue(reader, fieldName));
480+
switch (IndexSortConfig.getSortFieldType(sortField)) {
481+
case LONG:
482+
return new MinAndMax<>(minPoint.longValue(), maxPoint.longValue());
483+
case INT:
484+
return new MinAndMax<>(minPoint.intValue(), maxPoint.intValue());
485+
case DOUBLE:
486+
return new MinAndMax<>(minPoint.doubleValue(), maxPoint.doubleValue());
487+
case FLOAT:
488+
return new MinAndMax<>(minPoint.floatValue(), maxPoint.floatValue());
489+
default:
490+
return null;
491+
}
492+
} else if (fieldType instanceof DateFieldType) {
493+
DateFieldType dateFieldType = (DateFieldType) fieldType;
494+
Function<byte[], Long> dateConverter = createDateConverter(sortBuilder, dateFieldType);
495+
Long min = dateConverter.apply(PointValues.getMinPackedValue(reader, fieldName));
496+
Long max = dateConverter.apply(PointValues.getMaxPackedValue(reader, fieldName));
497+
return new MinAndMax<>(min, max);
498+
}
499+
return null;
500+
}
501+
502+
private static Function<byte[], Long> createDateConverter(FieldSortBuilder sortBuilder, DateFieldType dateFieldType) {
503+
String numericTypeStr = sortBuilder.getNumericType();
504+
if (numericTypeStr != null) {
505+
NumericType numericType = resolveNumericType(numericTypeStr);
506+
if (dateFieldType.resolution() == MILLISECONDS && numericType == NumericType.DATE_NANOSECONDS) {
507+
return v -> DateUtils.toNanoSeconds(LongPoint.decodeDimension(v, 0));
508+
} else if (dateFieldType.resolution() == NANOSECONDS && numericType == NumericType.DATE) {
509+
return v -> DateUtils.toMilliSeconds(LongPoint.decodeDimension(v, 0));
510+
}
511+
}
512+
return v -> LongPoint.decodeDimension(v, 0);
513+
}
514+
523515
/**
524516
* Throws an exception if max children is not located at top level nested sort.
525517
*/
@@ -601,12 +593,12 @@ public static FieldSortBuilder fromXContent(XContentParser parser, String fieldN
601593
private static final ObjectParser<FieldSortBuilder, Void> PARSER = new ObjectParser<>(NAME);
602594

603595
static {
604-
PARSER.declareField(FieldSortBuilder::missing, p -> p.objectText(), MISSING, ValueType.VALUE);
596+
PARSER.declareField(FieldSortBuilder::missing, XContentParser::objectText, MISSING, ValueType.VALUE);
605597
PARSER.declareString(FieldSortBuilder::unmappedType , UNMAPPED_TYPE);
606598
PARSER.declareString((b, v) -> b.order(SortOrder.fromString(v)) , ORDER_FIELD);
607599
PARSER.declareString((b, v) -> b.sortMode(SortMode.fromString(v)), SORT_MODE);
608600
PARSER.declareObject(FieldSortBuilder::setNestedSort, (p, c) -> NestedSortBuilder.fromXContent(p), NESTED_FIELD);
609-
PARSER.declareString((b, v) -> b.setNumericType(v), NUMERIC_TYPE);
601+
PARSER.declareString(FieldSortBuilder::setNumericType, NUMERIC_TYPE);
610602
}
611603

612604
@Override

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

+9-12
Original file line numberDiff line numberDiff line change
@@ -29,20 +29,21 @@
2929
import java.util.Objects;
3030

3131
/**
32-
* A class that encapsulates a minimum and a maximum {@link Comparable}.
32+
* A class that encapsulates a minimum and a maximum, that are of the same type and {@link Comparable}.
3333
*/
3434
public class MinAndMax<T extends Comparable<? super T>> implements Writeable {
3535
private final T minValue;
3636
private final T maxValue;
3737

38-
private MinAndMax(T minValue, T maxValue) {
38+
public MinAndMax(T minValue, T maxValue) {
3939
this.minValue = Objects.requireNonNull(minValue);
4040
this.maxValue = Objects.requireNonNull(maxValue);
4141
}
4242

43+
@SuppressWarnings("unchecked")
4344
public MinAndMax(StreamInput in) throws IOException {
44-
this.minValue = (T) Lucene.readSortValue(in);
45-
this.maxValue = (T) Lucene.readSortValue(in);
45+
this.minValue = (T)Lucene.readSortValue(in);
46+
this.maxValue = (T)Lucene.readSortValue(in);
4647
}
4748

4849
@Override
@@ -54,27 +55,23 @@ public void writeTo(StreamOutput out) throws IOException {
5455
/**
5556
* Return the minimum value.
5657
*/
57-
public T getMin() {
58+
T getMin() {
5859
return minValue;
5960
}
6061

6162
/**
6263
* Return the maximum value.
6364
*/
64-
public T getMax() {
65+
T getMax() {
6566
return maxValue;
6667
}
6768

68-
public static <T extends Comparable<? super T>> MinAndMax<T> newMinMax(T min, T max) {
69-
return new MinAndMax<>(min, max);
70-
}
71-
7269
/**
7370
* Return a {@link Comparator} for {@link MinAndMax} values according to the provided {@link SortOrder}.
7471
*/
7572
public static Comparator<MinAndMax<?>> getComparator(SortOrder order) {
76-
Comparator<MinAndMax> cmp = order == SortOrder.ASC ?
77-
Comparator.comparing(v -> (Comparable) v.getMin()) : Comparator.comparing(v -> (Comparable) v.getMax());
73+
Comparator<MinAndMax<?>> cmp = order == SortOrder.ASC ?
74+
Comparator.comparing(MinAndMax::getMin) : Comparator.comparing(MinAndMax::getMax);
7875
if (order == SortOrder.DESC) {
7976
cmp = cmp.reversed();
8077
}

server/src/test/java/org/elasticsearch/action/search/CanMatchPreFilterSearchPhaseTests.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -298,7 +298,7 @@ public void sendCanMatch(Transport.Connection connection, ShardSearchRequest req
298298
ActionListener<SearchService.CanMatchResponse> listener) {
299299
Long min = rarely() ? null : randomLong();
300300
Long max = min == null ? null : randomLongBetween(min, Long.MAX_VALUE);
301-
MinAndMax<?> minMax = min == null ? null : MinAndMax.newMinMax(min, max);
301+
MinAndMax<?> minMax = min == null ? null : new MinAndMax<>(min, max);
302302
boolean canMatch = frequently();
303303
synchronized (shardIds) {
304304
shardIds.add(request.shardId());

0 commit comments

Comments
 (0)