Skip to content

Commit 0d89d80

Browse files
committed
Decouple MultiValueMode. (#31075)
Currently this class takes care of moth selecting the relevant value, and replacing missing values if any. This is fine for sorting, which always needs to do both at the same time, but we also have a number of aggregations and script utils that need to retain information about missing values so this change proposes to decouple selection of the relevant value and replacement of missing values.
1 parent 62b4faa commit 0d89d80

File tree

16 files changed

+260
-165
lines changed

16 files changed

+260
-165
lines changed

modules/aggs-matrix-stats/src/main/java/org/elasticsearch/search/aggregations/support/MultiValuesSource.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ public NumericDoubleValues getField(final int ordinal, LeafReaderContext ctx) th
4747
if (ordinal > names.length) {
4848
throw new IndexOutOfBoundsException("ValuesSource array index " + ordinal + " out of bounds");
4949
}
50-
return multiValueMode.select(values[ordinal].doubleValues(ctx), Double.NEGATIVE_INFINITY);
50+
return multiValueMode.select(values[ordinal].doubleValues(ctx));
5151
}
5252
}
5353

modules/lang-expression/src/main/java/org/elasticsearch/script/expression/DateMethodValueSource.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ class DateMethodValueSource extends FieldDataValueSource {
5454
public FunctionValues getValues(Map context, LeafReaderContext leaf) throws IOException {
5555
AtomicNumericFieldData leafData = (AtomicNumericFieldData) fieldData.load(leaf);
5656
final Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("UTC"), Locale.ROOT);
57-
NumericDoubleValues docValues = multiValueMode.select(leafData.getDoubleValues(), 0d);
57+
NumericDoubleValues docValues = multiValueMode.select(leafData.getDoubleValues());
5858
return new DoubleDocValues(this) {
5959
@Override
6060
public double doubleVal(int docId) throws IOException {

modules/lang-expression/src/main/java/org/elasticsearch/script/expression/DateObjectValueSource.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ class DateObjectValueSource extends FieldDataValueSource {
5656
public FunctionValues getValues(Map context, LeafReaderContext leaf) throws IOException {
5757
AtomicNumericFieldData leafData = (AtomicNumericFieldData) fieldData.load(leaf);
5858
MutableDateTime joda = new MutableDateTime(0, DateTimeZone.UTC);
59-
NumericDoubleValues docValues = multiValueMode.select(leafData.getDoubleValues(), 0d);
59+
NumericDoubleValues docValues = multiValueMode.select(leafData.getDoubleValues());
6060
return new DoubleDocValues(this) {
6161
@Override
6262
public double doubleVal(int docId) throws IOException {

modules/lang-expression/src/main/java/org/elasticsearch/script/expression/FieldDataValueSource.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ public int hashCode() {
6868
@SuppressWarnings("rawtypes") // ValueSource uses a rawtype
6969
public FunctionValues getValues(Map context, LeafReaderContext leaf) throws IOException {
7070
AtomicNumericFieldData leafData = (AtomicNumericFieldData) fieldData.load(leaf);
71-
NumericDoubleValues docValues = multiValueMode.select(leafData.getDoubleValues(), 0d);
71+
NumericDoubleValues docValues = multiValueMode.select(leafData.getDoubleValues());
7272
return new DoubleDocValues(this) {
7373
@Override
7474
public double doubleVal(int doc) throws IOException {

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

Lines changed: 59 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -291,38 +291,6 @@ public static boolean isMultiValued(SortedSetDocValues values) {
291291
return DocValues.unwrapSingleton(values) == null;
292292
}
293293

294-
/**
295-
* Returns whether the provided values *might* be multi-valued. There is no
296-
* guarantee that this method will return {@code false} in the single-valued case.
297-
*/
298-
public static boolean isMultiValued(SortedNumericDocValues values) {
299-
return DocValues.unwrapSingleton(values) == null;
300-
}
301-
302-
/**
303-
* Returns whether the provided values *might* be multi-valued. There is no
304-
* guarantee that this method will return {@code false} in the single-valued case.
305-
*/
306-
public static boolean isMultiValued(SortedNumericDoubleValues values) {
307-
return unwrapSingleton(values) == null;
308-
}
309-
310-
/**
311-
* Returns whether the provided values *might* be multi-valued. There is no
312-
* guarantee that this method will return {@code false} in the single-valued case.
313-
*/
314-
public static boolean isMultiValued(SortedBinaryDocValues values) {
315-
return unwrapSingleton(values) != null;
316-
}
317-
318-
/**
319-
* Returns whether the provided values *might* be multi-valued. There is no
320-
* guarantee that this method will return {@code false} in the single-valued case.
321-
*/
322-
public static boolean isMultiValued(MultiGeoPointValues values) {
323-
return unwrapSingleton(values) == null;
324-
}
325-
326294
/**
327295
* Return a {@link String} representation of the provided values. That is
328296
* typically used for scripts or for the `map` execution mode of terms aggs.
@@ -555,4 +523,63 @@ public long nextValue() throws IOException {
555523
}
556524

557525
}
526+
527+
/**
528+
* Return a {@link NumericDocValues} instance that has a value for every
529+
* document, returns the same value as {@code values} if there is a value
530+
* for the current document and {@code missing} otherwise.
531+
*/
532+
public static NumericDocValues replaceMissing(NumericDocValues values, long missing) {
533+
return new AbstractNumericDocValues() {
534+
535+
private long value;
536+
537+
@Override
538+
public int docID() {
539+
return values.docID();
540+
}
541+
542+
@Override
543+
public boolean advanceExact(int target) throws IOException {
544+
if (values.advanceExact(target)) {
545+
value = values.longValue();
546+
} else {
547+
value = missing;
548+
}
549+
return true;
550+
}
551+
552+
@Override
553+
public long longValue() throws IOException {
554+
return value;
555+
}
556+
};
557+
}
558+
559+
/**
560+
* Return a {@link NumericDoubleValues} instance that has a value for every
561+
* document, returns the same value as {@code values} if there is a value
562+
* for the current document and {@code missing} otherwise.
563+
*/
564+
public static NumericDoubleValues replaceMissing(NumericDoubleValues values, double missing) {
565+
return new NumericDoubleValues() {
566+
567+
private double value;
568+
569+
@Override
570+
public boolean advanceExact(int target) throws IOException {
571+
if (values.advanceExact(target)) {
572+
value = values.doubleValue();
573+
} else {
574+
value = missing;
575+
}
576+
return true;
577+
}
578+
579+
@Override
580+
public double doubleValue() throws IOException {
581+
return value;
582+
}
583+
};
584+
}
558585
}

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import org.apache.lucene.search.SortField;
2828
import org.apache.lucene.util.BitSet;
2929
import org.elasticsearch.common.Nullable;
30+
import org.elasticsearch.index.fielddata.FieldData;
3031
import org.elasticsearch.index.fielddata.IndexFieldData;
3132
import org.elasticsearch.index.fielddata.IndexNumericFieldData;
3233
import org.elasticsearch.index.fielddata.NumericDoubleValues;
@@ -71,7 +72,7 @@ protected NumericDocValues getNumericDocValues(LeafReaderContext context, String
7172
final SortedNumericDoubleValues values = getValues(context);
7273
final NumericDoubleValues selectedValues;
7374
if (nested == null) {
74-
selectedValues = sortMode.select(values, dMissingValue);
75+
selectedValues = FieldData.replaceMissing(sortMode.select(values), dMissingValue);
7576
} else {
7677
final BitSet rootDocs = nested.rootDocs(context);
7778
final DocIdSetIterator innerDocs = nested.innerDocs(context);

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import org.apache.lucene.search.SortField;
2626
import org.apache.lucene.util.BitSet;
2727
import org.elasticsearch.common.Nullable;
28+
import org.elasticsearch.index.fielddata.FieldData;
2829
import org.elasticsearch.index.fielddata.IndexFieldData;
2930
import org.elasticsearch.index.fielddata.IndexNumericFieldData;
3031
import org.elasticsearch.index.fielddata.NumericDoubleValues;
@@ -63,7 +64,7 @@ protected NumericDocValues getNumericDocValues(LeafReaderContext context, String
6364
final SortedNumericDoubleValues values = indexFieldData.load(context).getDoubleValues();
6465
final NumericDoubleValues selectedValues;
6566
if (nested == null) {
66-
selectedValues = sortMode.select(values, dMissingValue);
67+
selectedValues = FieldData.replaceMissing(sortMode.select(values), dMissingValue);
6768
} else {
6869
final BitSet rootDocs = nested.rootDocs(context);
6970
final DocIdSetIterator innerDocs = nested.innerDocs(context);

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import org.apache.lucene.search.SortField;
2727
import org.apache.lucene.util.BitSet;
2828
import org.elasticsearch.common.Nullable;
29+
import org.elasticsearch.index.fielddata.FieldData;
2930
import org.elasticsearch.index.fielddata.IndexFieldData;
3031
import org.elasticsearch.index.fielddata.IndexNumericFieldData;
3132
import org.elasticsearch.search.MultiValueMode;
@@ -62,7 +63,7 @@ protected NumericDocValues getNumericDocValues(LeafReaderContext context, String
6263
final SortedNumericDocValues values = indexFieldData.load(context).getLongValues();
6364
final NumericDocValues selectedValues;
6465
if (nested == null) {
65-
selectedValues = sortMode.select(values, dMissingValue);
66+
selectedValues = FieldData.replaceMissing(sortMode.select(values), dMissingValue);
6667
} else {
6768
final BitSet rootDocs = nested.rootDocs(context);
6869
final DocIdSetIterator innerDocs = nested.innerDocs(context);

server/src/main/java/org/elasticsearch/index/query/functionscore/DecayFunctionBuilder.java

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
import org.elasticsearch.common.xcontent.XContentFactory;
4141
import org.elasticsearch.common.xcontent.XContentHelper;
4242
import org.elasticsearch.common.xcontent.XContentParser;
43+
import org.elasticsearch.index.fielddata.FieldData;
4344
import org.elasticsearch.index.fielddata.IndexGeoPointFieldData;
4445
import org.elasticsearch.index.fielddata.IndexNumericFieldData;
4546
import org.elasticsearch.index.fielddata.MultiGeoPointValues;
@@ -354,7 +355,7 @@ public boolean needsScores() {
354355
@Override
355356
protected NumericDoubleValues distance(LeafReaderContext context) {
356357
final MultiGeoPointValues geoPointValues = fieldData.load(context).getGeoPointValues();
357-
return mode.select(new SortingNumericDoubleValues() {
358+
return FieldData.replaceMissing(mode.select(new SortingNumericDoubleValues() {
358359
@Override
359360
public boolean advanceExact(int docId) throws IOException {
360361
if (geoPointValues.advanceExact(docId)) {
@@ -372,7 +373,7 @@ public boolean advanceExact(int docId) throws IOException {
372373
return false;
373374
}
374375
}
375-
}, 0.0);
376+
}), 0);
376377
}
377378

378379
@Override
@@ -436,7 +437,7 @@ public boolean needsScores() {
436437
@Override
437438
protected NumericDoubleValues distance(LeafReaderContext context) {
438439
final SortedNumericDoubleValues doubleValues = fieldData.load(context).getDoubleValues();
439-
return mode.select(new SortingNumericDoubleValues() {
440+
return FieldData.replaceMissing(mode.select(new SortingNumericDoubleValues() {
440441
@Override
441442
public boolean advanceExact(int docId) throws IOException {
442443
if (doubleValues.advanceExact(docId)) {
@@ -451,7 +452,7 @@ public boolean advanceExact(int docId) throws IOException {
451452
return false;
452453
}
453454
}
454-
}, 0.0);
455+
}), 0);
455456
}
456457

457458
@Override

server/src/main/java/org/elasticsearch/search/MultiValueMode.java

Lines changed: 16 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -411,38 +411,22 @@ public static MultiValueMode fromString(String sortMode) {
411411
*
412412
* Allowed Modes: SUM, AVG, MEDIAN, MIN, MAX
413413
*/
414-
public NumericDocValues select(final SortedNumericDocValues values, final long missingValue) {
414+
public NumericDocValues select(final SortedNumericDocValues values) {
415415
final NumericDocValues singleton = DocValues.unwrapSingleton(values);
416416
if (singleton != null) {
417-
return new AbstractNumericDocValues() {
418-
419-
private long value;
420-
421-
@Override
422-
public boolean advanceExact(int target) throws IOException {
423-
this.value = singleton.advanceExact(target) ? singleton.longValue() : missingValue;
424-
return true;
425-
}
426-
427-
@Override
428-
public int docID() {
429-
return singleton.docID();
430-
}
431-
432-
@Override
433-
public long longValue() throws IOException {
434-
return this.value;
435-
}
436-
};
417+
return singleton;
437418
} else {
438419
return new AbstractNumericDocValues() {
439420

440421
private long value;
441422

442423
@Override
443424
public boolean advanceExact(int target) throws IOException {
444-
this.value = values.advanceExact(target) ? pick(values) : missingValue;
445-
return true;
425+
if (values.advanceExact(target)) {
426+
value = pick(values);
427+
return true;
428+
}
429+
return false;
446430
}
447431

448432
@Override
@@ -476,7 +460,7 @@ protected long pick(SortedNumericDocValues values) throws IOException {
476460
*/
477461
public NumericDocValues select(final SortedNumericDocValues values, final long missingValue, final BitSet parentDocs, final DocIdSetIterator childDocs, int maxDoc) throws IOException {
478462
if (parentDocs == null || childDocs == null) {
479-
return select(DocValues.emptySortedNumeric(maxDoc), missingValue);
463+
return FieldData.replaceMissing(DocValues.emptyNumeric(), missingValue);
480464
}
481465

482466
return new AbstractNumericDocValues() {
@@ -529,32 +513,22 @@ protected long pick(SortedNumericDocValues values, long missingValue, DocIdSetIt
529513
*
530514
* Allowed Modes: SUM, AVG, MEDIAN, MIN, MAX
531515
*/
532-
public NumericDoubleValues select(final SortedNumericDoubleValues values, final double missingValue) {
516+
public NumericDoubleValues select(final SortedNumericDoubleValues values) {
533517
final NumericDoubleValues singleton = FieldData.unwrapSingleton(values);
534518
if (singleton != null) {
535-
return new NumericDoubleValues() {
536-
private double value;
537-
538-
@Override
539-
public boolean advanceExact(int doc) throws IOException {
540-
this.value = singleton.advanceExact(doc) ? singleton.doubleValue() : missingValue;
541-
return true;
542-
}
543-
544-
@Override
545-
public double doubleValue() throws IOException {
546-
return this.value;
547-
}
548-
};
519+
return singleton;
549520
} else {
550521
return new NumericDoubleValues() {
551522

552523
private double value;
553524

554525
@Override
555526
public boolean advanceExact(int target) throws IOException {
556-
value = values.advanceExact(target) ? pick(values) : missingValue;
557-
return true;
527+
if (values.advanceExact(target)) {
528+
value = pick(values);
529+
return true;
530+
}
531+
return false;
558532
}
559533

560534
@Override
@@ -583,7 +557,7 @@ protected double pick(SortedNumericDoubleValues values) throws IOException {
583557
*/
584558
public NumericDoubleValues select(final SortedNumericDoubleValues values, final double missingValue, final BitSet parentDocs, final DocIdSetIterator childDocs, int maxDoc) throws IOException {
585559
if (parentDocs == null || childDocs == null) {
586-
return select(FieldData.emptySortedNumericDoubles(), missingValue);
560+
return FieldData.replaceMissing(FieldData.emptyNumericDouble(), missingValue);
587561
}
588562

589563
return new NumericDoubleValues() {

server/src/main/java/org/elasticsearch/search/aggregations/metrics/max/MaxAggregator.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ public LeafBucketCollector getLeafCollector(LeafReaderContext ctx,
7272
}
7373
final BigArrays bigArrays = context.bigArrays();
7474
final SortedNumericDoubleValues allValues = valuesSource.doubleValues(ctx);
75-
final NumericDoubleValues values = MultiValueMode.MAX.select(allValues, Double.NEGATIVE_INFINITY);
75+
final NumericDoubleValues values = MultiValueMode.MAX.select(allValues);
7676
return new LeafBucketCollectorBase(sub, allValues) {
7777

7878
@Override

server/src/main/java/org/elasticsearch/search/aggregations/metrics/min/MinAggregator.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ public LeafBucketCollector getLeafCollector(LeafReaderContext ctx,
7171
}
7272
final BigArrays bigArrays = context.bigArrays();
7373
final SortedNumericDoubleValues allValues = valuesSource.doubleValues(ctx);
74-
final NumericDoubleValues values = MultiValueMode.MIN.select(allValues, Double.POSITIVE_INFINITY);
74+
final NumericDoubleValues values = MultiValueMode.MIN.select(allValues);
7575
return new LeafBucketCollectorBase(sub, allValues) {
7676

7777
@Override

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
import org.elasticsearch.common.xcontent.XContentBuilder;
4242
import org.elasticsearch.common.xcontent.XContentParser;
4343
import org.elasticsearch.common.xcontent.XContentParser.Token;
44+
import org.elasticsearch.index.fielddata.FieldData;
4445
import org.elasticsearch.index.fielddata.IndexFieldData;
4546
import org.elasticsearch.index.fielddata.IndexFieldData.XFieldComparatorSource.Nested;
4647
import org.elasticsearch.index.fielddata.IndexGeoPointFieldData;
@@ -637,7 +638,7 @@ protected NumericDocValues getNumericDocValues(LeafReaderContext context, String
637638
localPoints);
638639
final NumericDoubleValues selectedValues;
639640
if (nested == null) {
640-
selectedValues = finalSortMode.select(distanceValues, Double.POSITIVE_INFINITY);
641+
selectedValues = FieldData.replaceMissing(finalSortMode.select(distanceValues), Double.POSITIVE_INFINITY);
641642
} else {
642643
final BitSet rootDocs = nested.rootDocs(context);
643644
final DocIdSetIterator innerDocs = nested.innerDocs(context);

0 commit comments

Comments
 (0)