Skip to content

Commit 8a05b67

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 cb868d2 commit 8a05b67

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
@@ -499,46 +499,6 @@ public static FieldSortBuilder getPrimaryFieldSortOrNull(SearchSourceBuilder sou
499499
return source.sorts().get(0) instanceof FieldSortBuilder ? (FieldSortBuilder) source.sorts().get(0) : null;
500500
}
501501

502-
/**
503-
* Return a {@link Function} that converts a serialized point into a {@link Number} according to the provided
504-
* {@link SortField}. This is needed for {@link SortField} that converts values from one type to another using
505-
* {@link FieldSortBuilder#setNumericType(String)} )} (e.g.: long to double).
506-
*/
507-
private static Function<byte[], Comparable> numericPointConverter(SortField sortField, NumberFieldType numberFieldType) {
508-
switch (IndexSortConfig.getSortFieldType(sortField)) {
509-
case LONG:
510-
return v -> numberFieldType.parsePoint(v).longValue();
511-
512-
case INT:
513-
return v -> numberFieldType.parsePoint(v).intValue();
514-
515-
case DOUBLE:
516-
return v -> numberFieldType.parsePoint(v).doubleValue();
517-
518-
case FLOAT:
519-
return v -> numberFieldType.parsePoint(v).floatValue();
520-
521-
default:
522-
return v -> null;
523-
}
524-
}
525-
526-
/**
527-
* Return a {@link Function} that converts a serialized date point into a {@link Long} according to the provided
528-
* {@link NumericType}.
529-
*/
530-
private static Function<byte[], Comparable> datePointConverter(DateFieldType dateFieldType, String numericTypeStr) {
531-
if (numericTypeStr != null) {
532-
NumericType numericType = resolveNumericType(numericTypeStr);
533-
if (dateFieldType.resolution() == MILLISECONDS && numericType == NumericType.DATE_NANOSECONDS) {
534-
return v -> DateUtils.toNanoSeconds(LongPoint.decodeDimension(v, 0));
535-
} else if (dateFieldType.resolution() == NANOSECONDS && numericType == NumericType.DATE) {
536-
return v -> DateUtils.toMilliSeconds(LongPoint.decodeDimension(v, 0));
537-
}
538-
}
539-
return v -> LongPoint.decodeDimension(v, 0);
540-
}
541-
542502
/**
543503
* Return the {@link MinAndMax} indexed value from the provided {@link FieldSortBuilder} or <code>null</code> if unknown.
544504
* The value can be extracted on non-nested indexed mapped fields of type keyword, numeric or date, other fields
@@ -555,41 +515,73 @@ public static MinAndMax<?> getMinMaxOrNull(QueryShardContext context, FieldSortB
555515
if (reader == null || (fieldType == null || fieldType.indexOptions() == IndexOptions.NONE)) {
556516
return null;
557517
}
558-
String fieldName = fieldType.name();
559518
switch (IndexSortConfig.getSortFieldType(sortField)) {
560519
case LONG:
561520
case INT:
562521
case DOUBLE:
563522
case FLOAT:
564-
final Function<byte[], Comparable> converter;
565-
if (fieldType instanceof NumberFieldType) {
566-
converter = numericPointConverter(sortField, (NumberFieldType) fieldType);
567-
} else if (fieldType instanceof DateFieldType) {
568-
converter = datePointConverter((DateFieldType) fieldType, sortBuilder.getNumericType());
569-
} else {
570-
return null;
571-
}
572-
if (PointValues.size(reader, fieldName) == 0) {
573-
return null;
574-
}
575-
final Comparable min = converter.apply(PointValues.getMinPackedValue(reader, fieldName));
576-
final Comparable max = converter.apply(PointValues.getMaxPackedValue(reader, fieldName));
577-
return MinAndMax.newMinMax(min, max);
578-
523+
return extractNumericMinAndMax(reader, sortField, fieldType, sortBuilder);
579524
case STRING:
580525
case STRING_VAL:
581526
if (fieldType instanceof KeywordFieldMapper.KeywordFieldType) {
582-
Terms terms = MultiTerms.getTerms(reader, fieldName);
527+
Terms terms = MultiTerms.getTerms(reader, fieldType.name());
583528
if (terms == null) {
584529
return null;
585530
}
586-
return terms.getMin() != null ? MinAndMax.newMinMax(terms.getMin(), terms.getMax()) : null;
531+
return terms.getMin() != null ? new MinAndMax<>(terms.getMin(), terms.getMax()) : null;
587532
}
588533
break;
589534
}
590535
return null;
591536
}
592537

538+
private static MinAndMax<?> extractNumericMinAndMax(IndexReader reader,
539+
SortField sortField,
540+
MappedFieldType fieldType,
541+
FieldSortBuilder sortBuilder) throws IOException {
542+
String fieldName = fieldType.name();
543+
if (PointValues.size(reader, fieldName) == 0) {
544+
return null;
545+
}
546+
if (fieldType instanceof NumberFieldType) {
547+
NumberFieldType numberFieldType = (NumberFieldType) fieldType;
548+
Number minPoint = numberFieldType.parsePoint(PointValues.getMinPackedValue(reader, fieldName));
549+
Number maxPoint = numberFieldType.parsePoint(PointValues.getMaxPackedValue(reader, fieldName));
550+
switch (IndexSortConfig.getSortFieldType(sortField)) {
551+
case LONG:
552+
return new MinAndMax<>(minPoint.longValue(), maxPoint.longValue());
553+
case INT:
554+
return new MinAndMax<>(minPoint.intValue(), maxPoint.intValue());
555+
case DOUBLE:
556+
return new MinAndMax<>(minPoint.doubleValue(), maxPoint.doubleValue());
557+
case FLOAT:
558+
return new MinAndMax<>(minPoint.floatValue(), maxPoint.floatValue());
559+
default:
560+
return null;
561+
}
562+
} else if (fieldType instanceof DateFieldType) {
563+
DateFieldType dateFieldType = (DateFieldType) fieldType;
564+
Function<byte[], Long> dateConverter = createDateConverter(sortBuilder, dateFieldType);
565+
Long min = dateConverter.apply(PointValues.getMinPackedValue(reader, fieldName));
566+
Long max = dateConverter.apply(PointValues.getMaxPackedValue(reader, fieldName));
567+
return new MinAndMax<>(min, max);
568+
}
569+
return null;
570+
}
571+
572+
private static Function<byte[], Long> createDateConverter(FieldSortBuilder sortBuilder, DateFieldType dateFieldType) {
573+
String numericTypeStr = sortBuilder.getNumericType();
574+
if (numericTypeStr != null) {
575+
NumericType numericType = resolveNumericType(numericTypeStr);
576+
if (dateFieldType.resolution() == MILLISECONDS && numericType == NumericType.DATE_NANOSECONDS) {
577+
return v -> DateUtils.toNanoSeconds(LongPoint.decodeDimension(v, 0));
578+
} else if (dateFieldType.resolution() == NANOSECONDS && numericType == NumericType.DATE) {
579+
return v -> DateUtils.toMilliSeconds(LongPoint.decodeDimension(v, 0));
580+
}
581+
}
582+
return v -> LongPoint.decodeDimension(v, 0);
583+
}
584+
593585
/**
594586
* Throws an exception if max children is not located at top level nested sort.
595587
*/
@@ -647,7 +639,7 @@ public static FieldSortBuilder fromXContent(XContentParser parser, String fieldN
647639
private static final ObjectParser<FieldSortBuilder, Void> PARSER = new ObjectParser<>(NAME);
648640

649641
static {
650-
PARSER.declareField(FieldSortBuilder::missing, p -> p.objectText(), MISSING, ValueType.VALUE);
642+
PARSER.declareField(FieldSortBuilder::missing, XContentParser::objectText, MISSING, ValueType.VALUE);
651643
PARSER.declareString((fieldSortBuilder, nestedPath) -> {
652644
deprecationLogger.deprecated("[nested_path] has been deprecated in favor of the [nested] parameter");
653645
fieldSortBuilder.setNestedPath(nestedPath);
@@ -660,7 +652,7 @@ public static FieldSortBuilder fromXContent(XContentParser parser, String fieldN
660652
return SortBuilder.parseNestedFilter(p);
661653
}, NESTED_FILTER_FIELD);
662654
PARSER.declareObject(FieldSortBuilder::setNestedSort, (p, c) -> NestedSortBuilder.fromXContent(p), NESTED_FIELD);
663-
PARSER.declareString((b, v) -> b.setNumericType(v), NUMERIC_TYPE);
655+
PARSER.declareString(FieldSortBuilder::setNumericType, NUMERIC_TYPE);
664656
}
665657

666658
@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)