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.
This commit is contained in:
parent
f5073813ef
commit
cc55235030
|
@ -47,7 +47,7 @@ public abstract class MultiValuesSource <VS extends ValuesSource> {
|
|||
if (ordinal > names.length) {
|
||||
throw new IndexOutOfBoundsException("ValuesSource array index " + ordinal + " out of bounds");
|
||||
}
|
||||
return multiValueMode.select(values[ordinal].doubleValues(ctx), Double.NEGATIVE_INFINITY);
|
||||
return multiValueMode.select(values[ordinal].doubleValues(ctx));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -54,7 +54,7 @@ class DateMethodValueSource extends FieldDataValueSource {
|
|||
public FunctionValues getValues(Map context, LeafReaderContext leaf) throws IOException {
|
||||
AtomicNumericFieldData leafData = (AtomicNumericFieldData) fieldData.load(leaf);
|
||||
final Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("UTC"), Locale.ROOT);
|
||||
NumericDoubleValues docValues = multiValueMode.select(leafData.getDoubleValues(), 0d);
|
||||
NumericDoubleValues docValues = multiValueMode.select(leafData.getDoubleValues());
|
||||
return new DoubleDocValues(this) {
|
||||
@Override
|
||||
public double doubleVal(int docId) throws IOException {
|
||||
|
|
|
@ -56,7 +56,7 @@ class DateObjectValueSource extends FieldDataValueSource {
|
|||
public FunctionValues getValues(Map context, LeafReaderContext leaf) throws IOException {
|
||||
AtomicNumericFieldData leafData = (AtomicNumericFieldData) fieldData.load(leaf);
|
||||
MutableDateTime joda = new MutableDateTime(0, DateTimeZone.UTC);
|
||||
NumericDoubleValues docValues = multiValueMode.select(leafData.getDoubleValues(), 0d);
|
||||
NumericDoubleValues docValues = multiValueMode.select(leafData.getDoubleValues());
|
||||
return new DoubleDocValues(this) {
|
||||
@Override
|
||||
public double doubleVal(int docId) throws IOException {
|
||||
|
|
|
@ -68,7 +68,7 @@ class FieldDataValueSource extends ValueSource {
|
|||
@SuppressWarnings("rawtypes") // ValueSource uses a rawtype
|
||||
public FunctionValues getValues(Map context, LeafReaderContext leaf) throws IOException {
|
||||
AtomicNumericFieldData leafData = (AtomicNumericFieldData) fieldData.load(leaf);
|
||||
NumericDoubleValues docValues = multiValueMode.select(leafData.getDoubleValues(), 0d);
|
||||
NumericDoubleValues docValues = multiValueMode.select(leafData.getDoubleValues());
|
||||
return new DoubleDocValues(this) {
|
||||
@Override
|
||||
public double doubleVal(int doc) throws IOException {
|
||||
|
|
|
@ -291,38 +291,6 @@ public enum FieldData {
|
|||
return DocValues.unwrapSingleton(values) == null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the provided values *might* be multi-valued. There is no
|
||||
* guarantee that this method will return {@code false} in the single-valued case.
|
||||
*/
|
||||
public static boolean isMultiValued(SortedNumericDocValues values) {
|
||||
return DocValues.unwrapSingleton(values) == null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the provided values *might* be multi-valued. There is no
|
||||
* guarantee that this method will return {@code false} in the single-valued case.
|
||||
*/
|
||||
public static boolean isMultiValued(SortedNumericDoubleValues values) {
|
||||
return unwrapSingleton(values) == null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the provided values *might* be multi-valued. There is no
|
||||
* guarantee that this method will return {@code false} in the single-valued case.
|
||||
*/
|
||||
public static boolean isMultiValued(SortedBinaryDocValues values) {
|
||||
return unwrapSingleton(values) != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the provided values *might* be multi-valued. There is no
|
||||
* guarantee that this method will return {@code false} in the single-valued case.
|
||||
*/
|
||||
public static boolean isMultiValued(MultiGeoPointValues values) {
|
||||
return unwrapSingleton(values) == null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a {@link String} representation of the provided values. That is
|
||||
* typically used for scripts or for the `map` execution mode of terms aggs.
|
||||
|
@ -555,4 +523,63 @@ public enum FieldData {
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a {@link NumericDocValues} instance that has a value for every
|
||||
* document, returns the same value as {@code values} if there is a value
|
||||
* for the current document and {@code missing} otherwise.
|
||||
*/
|
||||
public static NumericDocValues replaceMissing(NumericDocValues values, long missing) {
|
||||
return new AbstractNumericDocValues() {
|
||||
|
||||
private long value;
|
||||
|
||||
@Override
|
||||
public int docID() {
|
||||
return values.docID();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean advanceExact(int target) throws IOException {
|
||||
if (values.advanceExact(target)) {
|
||||
value = values.longValue();
|
||||
} else {
|
||||
value = missing;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long longValue() throws IOException {
|
||||
return value;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a {@link NumericDoubleValues} instance that has a value for every
|
||||
* document, returns the same value as {@code values} if there is a value
|
||||
* for the current document and {@code missing} otherwise.
|
||||
*/
|
||||
public static NumericDoubleValues replaceMissing(NumericDoubleValues values, double missing) {
|
||||
return new NumericDoubleValues() {
|
||||
|
||||
private double value;
|
||||
|
||||
@Override
|
||||
public boolean advanceExact(int target) throws IOException {
|
||||
if (values.advanceExact(target)) {
|
||||
value = values.doubleValue();
|
||||
} else {
|
||||
value = missing;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double doubleValue() throws IOException {
|
||||
return value;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,6 +27,7 @@ import org.apache.lucene.search.Scorer;
|
|||
import org.apache.lucene.search.SortField;
|
||||
import org.apache.lucene.util.BitSet;
|
||||
import org.elasticsearch.common.Nullable;
|
||||
import org.elasticsearch.index.fielddata.FieldData;
|
||||
import org.elasticsearch.index.fielddata.IndexFieldData;
|
||||
import org.elasticsearch.index.fielddata.IndexNumericFieldData;
|
||||
import org.elasticsearch.index.fielddata.NumericDoubleValues;
|
||||
|
@ -71,7 +72,7 @@ public class DoubleValuesComparatorSource extends IndexFieldData.XFieldComparato
|
|||
final SortedNumericDoubleValues values = getValues(context);
|
||||
final NumericDoubleValues selectedValues;
|
||||
if (nested == null) {
|
||||
selectedValues = sortMode.select(values, dMissingValue);
|
||||
selectedValues = FieldData.replaceMissing(sortMode.select(values), dMissingValue);
|
||||
} else {
|
||||
final BitSet rootDocs = nested.rootDocs(context);
|
||||
final DocIdSetIterator innerDocs = nested.innerDocs(context);
|
||||
|
|
|
@ -25,6 +25,7 @@ import org.apache.lucene.search.FieldComparator;
|
|||
import org.apache.lucene.search.SortField;
|
||||
import org.apache.lucene.util.BitSet;
|
||||
import org.elasticsearch.common.Nullable;
|
||||
import org.elasticsearch.index.fielddata.FieldData;
|
||||
import org.elasticsearch.index.fielddata.IndexFieldData;
|
||||
import org.elasticsearch.index.fielddata.IndexNumericFieldData;
|
||||
import org.elasticsearch.index.fielddata.NumericDoubleValues;
|
||||
|
@ -63,7 +64,7 @@ public class FloatValuesComparatorSource extends IndexFieldData.XFieldComparator
|
|||
final SortedNumericDoubleValues values = indexFieldData.load(context).getDoubleValues();
|
||||
final NumericDoubleValues selectedValues;
|
||||
if (nested == null) {
|
||||
selectedValues = sortMode.select(values, dMissingValue);
|
||||
selectedValues = FieldData.replaceMissing(sortMode.select(values), dMissingValue);
|
||||
} else {
|
||||
final BitSet rootDocs = nested.rootDocs(context);
|
||||
final DocIdSetIterator innerDocs = nested.innerDocs(context);
|
||||
|
|
|
@ -26,6 +26,7 @@ import org.apache.lucene.search.FieldComparator;
|
|||
import org.apache.lucene.search.SortField;
|
||||
import org.apache.lucene.util.BitSet;
|
||||
import org.elasticsearch.common.Nullable;
|
||||
import org.elasticsearch.index.fielddata.FieldData;
|
||||
import org.elasticsearch.index.fielddata.IndexFieldData;
|
||||
import org.elasticsearch.index.fielddata.IndexNumericFieldData;
|
||||
import org.elasticsearch.search.MultiValueMode;
|
||||
|
@ -62,7 +63,7 @@ public class LongValuesComparatorSource extends IndexFieldData.XFieldComparatorS
|
|||
final SortedNumericDocValues values = indexFieldData.load(context).getLongValues();
|
||||
final NumericDocValues selectedValues;
|
||||
if (nested == null) {
|
||||
selectedValues = sortMode.select(values, dMissingValue);
|
||||
selectedValues = FieldData.replaceMissing(sortMode.select(values), dMissingValue);
|
||||
} else {
|
||||
final BitSet rootDocs = nested.rootDocs(context);
|
||||
final DocIdSetIterator innerDocs = nested.innerDocs(context);
|
||||
|
|
|
@ -40,6 +40,7 @@ import org.elasticsearch.common.xcontent.XContentBuilder;
|
|||
import org.elasticsearch.common.xcontent.XContentFactory;
|
||||
import org.elasticsearch.common.xcontent.XContentHelper;
|
||||
import org.elasticsearch.common.xcontent.XContentParser;
|
||||
import org.elasticsearch.index.fielddata.FieldData;
|
||||
import org.elasticsearch.index.fielddata.IndexGeoPointFieldData;
|
||||
import org.elasticsearch.index.fielddata.IndexNumericFieldData;
|
||||
import org.elasticsearch.index.fielddata.MultiGeoPointValues;
|
||||
|
@ -354,7 +355,7 @@ public abstract class DecayFunctionBuilder<DFB extends DecayFunctionBuilder<DFB>
|
|||
@Override
|
||||
protected NumericDoubleValues distance(LeafReaderContext context) {
|
||||
final MultiGeoPointValues geoPointValues = fieldData.load(context).getGeoPointValues();
|
||||
return mode.select(new SortingNumericDoubleValues() {
|
||||
return FieldData.replaceMissing(mode.select(new SortingNumericDoubleValues() {
|
||||
@Override
|
||||
public boolean advanceExact(int docId) throws IOException {
|
||||
if (geoPointValues.advanceExact(docId)) {
|
||||
|
@ -372,7 +373,7 @@ public abstract class DecayFunctionBuilder<DFB extends DecayFunctionBuilder<DFB>
|
|||
return false;
|
||||
}
|
||||
}
|
||||
}, 0.0);
|
||||
}), 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -436,7 +437,7 @@ public abstract class DecayFunctionBuilder<DFB extends DecayFunctionBuilder<DFB>
|
|||
@Override
|
||||
protected NumericDoubleValues distance(LeafReaderContext context) {
|
||||
final SortedNumericDoubleValues doubleValues = fieldData.load(context).getDoubleValues();
|
||||
return mode.select(new SortingNumericDoubleValues() {
|
||||
return FieldData.replaceMissing(mode.select(new SortingNumericDoubleValues() {
|
||||
@Override
|
||||
public boolean advanceExact(int docId) throws IOException {
|
||||
if (doubleValues.advanceExact(docId)) {
|
||||
|
@ -451,7 +452,7 @@ public abstract class DecayFunctionBuilder<DFB extends DecayFunctionBuilder<DFB>
|
|||
return false;
|
||||
}
|
||||
}
|
||||
}, 0.0);
|
||||
}), 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -411,29 +411,10 @@ public enum MultiValueMode implements Writeable {
|
|||
*
|
||||
* Allowed Modes: SUM, AVG, MEDIAN, MIN, MAX
|
||||
*/
|
||||
public NumericDocValues select(final SortedNumericDocValues values, final long missingValue) {
|
||||
public NumericDocValues select(final SortedNumericDocValues values) {
|
||||
final NumericDocValues singleton = DocValues.unwrapSingleton(values);
|
||||
if (singleton != null) {
|
||||
return new AbstractNumericDocValues() {
|
||||
|
||||
private long value;
|
||||
|
||||
@Override
|
||||
public boolean advanceExact(int target) throws IOException {
|
||||
this.value = singleton.advanceExact(target) ? singleton.longValue() : missingValue;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int docID() {
|
||||
return singleton.docID();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long longValue() throws IOException {
|
||||
return this.value;
|
||||
}
|
||||
};
|
||||
return singleton;
|
||||
} else {
|
||||
return new AbstractNumericDocValues() {
|
||||
|
||||
|
@ -441,8 +422,11 @@ public enum MultiValueMode implements Writeable {
|
|||
|
||||
@Override
|
||||
public boolean advanceExact(int target) throws IOException {
|
||||
this.value = values.advanceExact(target) ? pick(values) : missingValue;
|
||||
return true;
|
||||
if (values.advanceExact(target)) {
|
||||
value = pick(values);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -476,7 +460,7 @@ public enum MultiValueMode implements Writeable {
|
|||
*/
|
||||
public NumericDocValues select(final SortedNumericDocValues values, final long missingValue, final BitSet parentDocs, final DocIdSetIterator childDocs, int maxDoc) throws IOException {
|
||||
if (parentDocs == null || childDocs == null) {
|
||||
return select(DocValues.emptySortedNumeric(maxDoc), missingValue);
|
||||
return FieldData.replaceMissing(DocValues.emptyNumeric(), missingValue);
|
||||
}
|
||||
|
||||
return new AbstractNumericDocValues() {
|
||||
|
@ -529,23 +513,10 @@ public enum MultiValueMode implements Writeable {
|
|||
*
|
||||
* Allowed Modes: SUM, AVG, MEDIAN, MIN, MAX
|
||||
*/
|
||||
public NumericDoubleValues select(final SortedNumericDoubleValues values, final double missingValue) {
|
||||
public NumericDoubleValues select(final SortedNumericDoubleValues values) {
|
||||
final NumericDoubleValues singleton = FieldData.unwrapSingleton(values);
|
||||
if (singleton != null) {
|
||||
return new NumericDoubleValues() {
|
||||
private double value;
|
||||
|
||||
@Override
|
||||
public boolean advanceExact(int doc) throws IOException {
|
||||
this.value = singleton.advanceExact(doc) ? singleton.doubleValue() : missingValue;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double doubleValue() throws IOException {
|
||||
return this.value;
|
||||
}
|
||||
};
|
||||
return singleton;
|
||||
} else {
|
||||
return new NumericDoubleValues() {
|
||||
|
||||
|
@ -553,8 +524,11 @@ public enum MultiValueMode implements Writeable {
|
|||
|
||||
@Override
|
||||
public boolean advanceExact(int target) throws IOException {
|
||||
value = values.advanceExact(target) ? pick(values) : missingValue;
|
||||
return true;
|
||||
if (values.advanceExact(target)) {
|
||||
value = pick(values);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -583,7 +557,7 @@ public enum MultiValueMode implements Writeable {
|
|||
*/
|
||||
public NumericDoubleValues select(final SortedNumericDoubleValues values, final double missingValue, final BitSet parentDocs, final DocIdSetIterator childDocs, int maxDoc) throws IOException {
|
||||
if (parentDocs == null || childDocs == null) {
|
||||
return select(FieldData.emptySortedNumericDoubles(), missingValue);
|
||||
return FieldData.replaceMissing(FieldData.emptyNumericDouble(), missingValue);
|
||||
}
|
||||
|
||||
return new NumericDoubleValues() {
|
||||
|
|
|
@ -72,7 +72,7 @@ public class MaxAggregator extends NumericMetricsAggregator.SingleValue {
|
|||
}
|
||||
final BigArrays bigArrays = context.bigArrays();
|
||||
final SortedNumericDoubleValues allValues = valuesSource.doubleValues(ctx);
|
||||
final NumericDoubleValues values = MultiValueMode.MAX.select(allValues, Double.NEGATIVE_INFINITY);
|
||||
final NumericDoubleValues values = MultiValueMode.MAX.select(allValues);
|
||||
return new LeafBucketCollectorBase(sub, allValues) {
|
||||
|
||||
@Override
|
||||
|
|
|
@ -71,7 +71,7 @@ public class MinAggregator extends NumericMetricsAggregator.SingleValue {
|
|||
}
|
||||
final BigArrays bigArrays = context.bigArrays();
|
||||
final SortedNumericDoubleValues allValues = valuesSource.doubleValues(ctx);
|
||||
final NumericDoubleValues values = MultiValueMode.MIN.select(allValues, Double.POSITIVE_INFINITY);
|
||||
final NumericDoubleValues values = MultiValueMode.MIN.select(allValues);
|
||||
return new LeafBucketCollectorBase(sub, allValues) {
|
||||
|
||||
@Override
|
||||
|
|
|
@ -41,6 +41,7 @@ import org.elasticsearch.common.unit.DistanceUnit;
|
|||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||
import org.elasticsearch.common.xcontent.XContentParser;
|
||||
import org.elasticsearch.common.xcontent.XContentParser.Token;
|
||||
import org.elasticsearch.index.fielddata.FieldData;
|
||||
import org.elasticsearch.index.fielddata.IndexFieldData;
|
||||
import org.elasticsearch.index.fielddata.IndexFieldData.XFieldComparatorSource.Nested;
|
||||
import org.elasticsearch.index.fielddata.IndexGeoPointFieldData;
|
||||
|
@ -637,7 +638,7 @@ public class GeoDistanceSortBuilder extends SortBuilder<GeoDistanceSortBuilder>
|
|||
localPoints);
|
||||
final NumericDoubleValues selectedValues;
|
||||
if (nested == null) {
|
||||
selectedValues = finalSortMode.select(distanceValues, Double.POSITIVE_INFINITY);
|
||||
selectedValues = FieldData.replaceMissing(finalSortMode.select(distanceValues), Double.POSITIVE_INFINITY);
|
||||
} else {
|
||||
final BitSet rootDocs = nested.rootDocs(context);
|
||||
final DocIdSetIterator innerDocs = nested.innerDocs(context);
|
||||
|
|
|
@ -137,4 +137,91 @@ public class FieldDataTests extends ESTestCase {
|
|||
assertEquals(valueBits, asMultiLongs.nextValue());
|
||||
assertSame(multiValues, FieldData.sortableLongBitsToDoubles(asMultiLongs));
|
||||
}
|
||||
|
||||
private static NumericDocValues asNumericDocValues(Long... values) {
|
||||
return new AbstractNumericDocValues() {
|
||||
|
||||
int docID = -1;
|
||||
|
||||
@Override
|
||||
public int docID() {
|
||||
return docID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean advanceExact(int target) throws IOException {
|
||||
docID = target;
|
||||
return target < values.length && values[target] != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long longValue() throws IOException {
|
||||
return values[docID];
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public void testReplaceMissingLongs() throws IOException {
|
||||
final NumericDocValues values = asNumericDocValues(null, 3L, 2L, null, 5L, null);
|
||||
final NumericDocValues replaced = FieldData.replaceMissing(values, 4);
|
||||
|
||||
assertTrue(replaced.advanceExact(0));
|
||||
assertEquals(4L, replaced.longValue());
|
||||
|
||||
assertTrue(replaced.advanceExact(1));
|
||||
assertEquals(3L, replaced.longValue());
|
||||
|
||||
assertTrue(replaced.advanceExact(2));
|
||||
assertEquals(2L, replaced.longValue());
|
||||
|
||||
assertTrue(replaced.advanceExact(3));
|
||||
assertEquals(4L, replaced.longValue());
|
||||
|
||||
assertTrue(replaced.advanceExact(4));
|
||||
assertEquals(5L, replaced.longValue());
|
||||
|
||||
assertTrue(replaced.advanceExact(5));
|
||||
assertEquals(4L, replaced.longValue());
|
||||
}
|
||||
|
||||
private static NumericDoubleValues asNumericDoubleValues(Double... values) {
|
||||
return new NumericDoubleValues() {
|
||||
|
||||
int docID = -1;
|
||||
|
||||
@Override
|
||||
public boolean advanceExact(int target) throws IOException {
|
||||
docID = target;
|
||||
return target < values.length && values[target] != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double doubleValue() throws IOException {
|
||||
return values[docID];
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public void testReplaceMissingDoubles() throws IOException {
|
||||
final NumericDoubleValues values = asNumericDoubleValues(null, 1.3, 1.2, null, 1.5, null);
|
||||
final NumericDoubleValues replaced = FieldData.replaceMissing(values, 1.4);
|
||||
|
||||
assertTrue(replaced.advanceExact(0));
|
||||
assertEquals(1.4, replaced.doubleValue(), 0d);
|
||||
|
||||
assertTrue(replaced.advanceExact(1));
|
||||
assertEquals(1.3, replaced.doubleValue(), 0d);
|
||||
|
||||
assertTrue(replaced.advanceExact(2));
|
||||
assertEquals(1.2, replaced.doubleValue(), 0d);
|
||||
|
||||
assertTrue(replaced.advanceExact(3));
|
||||
assertEquals(1.4, replaced.doubleValue(), 0d);
|
||||
|
||||
assertTrue(replaced.advanceExact(4));
|
||||
assertEquals(1.5, replaced.doubleValue(), 0d);
|
||||
|
||||
assertTrue(replaced.advanceExact(5));
|
||||
assertEquals(1.4, replaced.doubleValue(), 0d);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
*/
|
||||
package org.elasticsearch.index.fielddata.ordinals;
|
||||
|
||||
import org.apache.lucene.index.DocValues;
|
||||
import org.apache.lucene.index.SortedDocValues;
|
||||
import org.apache.lucene.index.SortedSetDocValues;
|
||||
import org.apache.lucene.util.packed.PackedInts;
|
||||
|
@ -261,7 +262,7 @@ public class MultiOrdinalsTests extends ESTestCase {
|
|||
}
|
||||
}
|
||||
assertThat(docs.getValueCount(), equalTo(maxOrd));
|
||||
assertThat(FieldData.isMultiValued(docs), equalTo(true));
|
||||
assertNull(DocValues.unwrapSingleton(docs));
|
||||
for (int doc = 0; doc < ordinalPlan.length; ++doc) {
|
||||
long[] ords = ordinalPlan[doc];
|
||||
assertEquals(ords.length > 0, docs.advanceExact(doc));
|
||||
|
|
|
@ -151,54 +151,55 @@ public class MultiValueModeTests extends ESTestCase {
|
|||
}
|
||||
|
||||
private void verifySortedNumeric(Supplier<SortedNumericDocValues> supplier, int maxDoc) throws IOException {
|
||||
for (long missingValue : new long[] { 0, randomLong() }) {
|
||||
for (MultiValueMode mode : MultiValueMode.values()) {
|
||||
SortedNumericDocValues values = supplier.get();
|
||||
final NumericDocValues selected = mode.select(values, missingValue);
|
||||
for (int i = 0; i < maxDoc; ++i) {
|
||||
assertTrue(selected.advanceExact(i));
|
||||
final long actual = selected.longValue();
|
||||
for (MultiValueMode mode : MultiValueMode.values()) {
|
||||
SortedNumericDocValues values = supplier.get();
|
||||
final NumericDocValues selected = mode.select(values);
|
||||
for (int i = 0; i < maxDoc; ++i) {
|
||||
Long actual = null;
|
||||
if (selected.advanceExact(i)) {
|
||||
actual = selected.longValue();
|
||||
verifyLongValueCanCalledMoreThanOnce(selected, actual);
|
||||
}
|
||||
|
||||
long expected = 0;
|
||||
if (values.advanceExact(i) == false) {
|
||||
expected = missingValue;
|
||||
|
||||
Long expected = null;
|
||||
if (values.advanceExact(i)) {
|
||||
int numValues = values.docValueCount();
|
||||
if (mode == MultiValueMode.MAX) {
|
||||
expected = Long.MIN_VALUE;
|
||||
} else if (mode == MultiValueMode.MIN) {
|
||||
expected = Long.MAX_VALUE;
|
||||
} else {
|
||||
int numValues = values.docValueCount();
|
||||
if (mode == MultiValueMode.MAX) {
|
||||
expected = Long.MIN_VALUE;
|
||||
expected = 0L;
|
||||
}
|
||||
for (int j = 0; j < numValues; ++j) {
|
||||
if (mode == MultiValueMode.SUM || mode == MultiValueMode.AVG) {
|
||||
expected += values.nextValue();
|
||||
} else if (mode == MultiValueMode.MIN) {
|
||||
expected = Long.MAX_VALUE;
|
||||
}
|
||||
for (int j = 0; j < numValues; ++j) {
|
||||
if (mode == MultiValueMode.SUM || mode == MultiValueMode.AVG) {
|
||||
expected += values.nextValue();
|
||||
} else if (mode == MultiValueMode.MIN) {
|
||||
expected = Math.min(expected, values.nextValue());
|
||||
} else if (mode == MultiValueMode.MAX) {
|
||||
expected = Math.max(expected, values.nextValue());
|
||||
}
|
||||
}
|
||||
if (mode == MultiValueMode.AVG) {
|
||||
expected = numValues > 1 ? Math.round((double)expected/(double)numValues) : expected;
|
||||
} else if (mode == MultiValueMode.MEDIAN) {
|
||||
int value = numValues/2;
|
||||
if (numValues % 2 == 0) {
|
||||
for (int j = 0; j < value - 1; ++j) {
|
||||
values.nextValue();
|
||||
}
|
||||
expected = Math.round(((double) values.nextValue() + values.nextValue())/2.0);
|
||||
} else {
|
||||
for (int j = 0; j < value; ++j) {
|
||||
values.nextValue();
|
||||
}
|
||||
expected = values.nextValue();
|
||||
}
|
||||
expected = Math.min(expected, values.nextValue());
|
||||
} else if (mode == MultiValueMode.MAX) {
|
||||
expected = Math.max(expected, values.nextValue());
|
||||
}
|
||||
}
|
||||
if (mode == MultiValueMode.AVG) {
|
||||
expected = numValues > 1 ? Math.round((double)expected/(double)numValues) : expected;
|
||||
} else if (mode == MultiValueMode.MEDIAN) {
|
||||
int value = numValues/2;
|
||||
if (numValues % 2 == 0) {
|
||||
for (int j = 0; j < value - 1; ++j) {
|
||||
values.nextValue();
|
||||
}
|
||||
expected = Math.round(((double) values.nextValue() + values.nextValue())/2.0);
|
||||
} else {
|
||||
for (int j = 0; j < value; ++j) {
|
||||
values.nextValue();
|
||||
}
|
||||
expected = values.nextValue();
|
||||
}
|
||||
}
|
||||
|
||||
assertEquals(mode.toString() + " docId=" + i, expected, actual);
|
||||
}
|
||||
|
||||
assertEquals(mode.toString() + " docId=" + i, expected, actual);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -326,54 +327,54 @@ public class MultiValueModeTests extends ESTestCase {
|
|||
}
|
||||
|
||||
private void verifySortedNumericDouble(Supplier<SortedNumericDoubleValues> supplier, int maxDoc) throws IOException {
|
||||
for (long missingValue : new long[] { 0, randomLong() }) {
|
||||
for (MultiValueMode mode : MultiValueMode.values()) {
|
||||
SortedNumericDoubleValues values = supplier.get();
|
||||
final NumericDoubleValues selected = mode.select(values, missingValue);
|
||||
for (int i = 0; i < maxDoc; ++i) {
|
||||
assertTrue(selected.advanceExact(i));
|
||||
final double actual = selected.doubleValue();
|
||||
for (MultiValueMode mode : MultiValueMode.values()) {
|
||||
SortedNumericDoubleValues values = supplier.get();
|
||||
final NumericDoubleValues selected = mode.select(values);
|
||||
for (int i = 0; i < maxDoc; ++i) {
|
||||
Double actual = null;
|
||||
if (selected.advanceExact(i)) {
|
||||
actual = selected.doubleValue();
|
||||
verifyDoubleValueCanCalledMoreThanOnce(selected, actual);
|
||||
}
|
||||
|
||||
double expected = 0.0;
|
||||
if (values.advanceExact(i) == false) {
|
||||
expected = missingValue;
|
||||
Double expected = null;
|
||||
if (values.advanceExact(i)) {
|
||||
int numValues = values.docValueCount();
|
||||
if (mode == MultiValueMode.MAX) {
|
||||
expected = Double.NEGATIVE_INFINITY;
|
||||
} else if (mode == MultiValueMode.MIN) {
|
||||
expected = Double.POSITIVE_INFINITY;
|
||||
} else {
|
||||
int numValues = values.docValueCount();
|
||||
if (mode == MultiValueMode.MAX) {
|
||||
expected = Long.MIN_VALUE;
|
||||
expected = 0d;
|
||||
}
|
||||
for (int j = 0; j < numValues; ++j) {
|
||||
if (mode == MultiValueMode.SUM || mode == MultiValueMode.AVG) {
|
||||
expected += values.nextValue();
|
||||
} else if (mode == MultiValueMode.MIN) {
|
||||
expected = Long.MAX_VALUE;
|
||||
}
|
||||
for (int j = 0; j < numValues; ++j) {
|
||||
if (mode == MultiValueMode.SUM || mode == MultiValueMode.AVG) {
|
||||
expected += values.nextValue();
|
||||
} else if (mode == MultiValueMode.MIN) {
|
||||
expected = Math.min(expected, values.nextValue());
|
||||
} else if (mode == MultiValueMode.MAX) {
|
||||
expected = Math.max(expected, values.nextValue());
|
||||
}
|
||||
}
|
||||
if (mode == MultiValueMode.AVG) {
|
||||
expected = expected/numValues;
|
||||
} else if (mode == MultiValueMode.MEDIAN) {
|
||||
int value = numValues/2;
|
||||
if (numValues % 2 == 0) {
|
||||
for (int j = 0; j < value - 1; ++j) {
|
||||
values.nextValue();
|
||||
}
|
||||
expected = (values.nextValue() + values.nextValue())/2.0;
|
||||
} else {
|
||||
for (int j = 0; j < value; ++j) {
|
||||
values.nextValue();
|
||||
}
|
||||
expected = values.nextValue();
|
||||
}
|
||||
expected = Math.min(expected, values.nextValue());
|
||||
} else if (mode == MultiValueMode.MAX) {
|
||||
expected = Math.max(expected, values.nextValue());
|
||||
}
|
||||
}
|
||||
if (mode == MultiValueMode.AVG) {
|
||||
expected = expected/numValues;
|
||||
} else if (mode == MultiValueMode.MEDIAN) {
|
||||
int value = numValues/2;
|
||||
if (numValues % 2 == 0) {
|
||||
for (int j = 0; j < value - 1; ++j) {
|
||||
values.nextValue();
|
||||
}
|
||||
expected = (values.nextValue() + values.nextValue())/2.0;
|
||||
} else {
|
||||
for (int j = 0; j < value; ++j) {
|
||||
values.nextValue();
|
||||
}
|
||||
expected = values.nextValue();
|
||||
}
|
||||
}
|
||||
|
||||
assertEquals(mode.toString() + " docId=" + i, expected, actual, 0.1);
|
||||
}
|
||||
|
||||
assertEquals(mode.toString() + " docId=" + i, expected, actual);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue