Previously we'd get a `ClassCastException` when you tried to use `numeric_type` on `scaled_float`. Oops! This cleans up the CCE and moves some code around so the casting actually works.
This commit is contained in:
parent
07c76f2894
commit
f52e779806
|
@ -29,14 +29,11 @@ import org.apache.lucene.index.Term;
|
||||||
import org.apache.lucene.search.BoostQuery;
|
import org.apache.lucene.search.BoostQuery;
|
||||||
import org.apache.lucene.search.DocValuesFieldExistsQuery;
|
import org.apache.lucene.search.DocValuesFieldExistsQuery;
|
||||||
import org.apache.lucene.search.Query;
|
import org.apache.lucene.search.Query;
|
||||||
import org.apache.lucene.search.SortField;
|
|
||||||
import org.apache.lucene.search.TermQuery;
|
import org.apache.lucene.search.TermQuery;
|
||||||
import org.apache.lucene.util.BytesRef;
|
import org.apache.lucene.util.BytesRef;
|
||||||
import org.elasticsearch.common.Explicit;
|
import org.elasticsearch.common.Explicit;
|
||||||
import org.elasticsearch.common.Nullable;
|
|
||||||
import org.elasticsearch.common.settings.Setting;
|
import org.elasticsearch.common.settings.Setting;
|
||||||
import org.elasticsearch.common.settings.Settings;
|
import org.elasticsearch.common.settings.Settings;
|
||||||
import org.elasticsearch.common.util.BigArrays;
|
|
||||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||||
import org.elasticsearch.common.xcontent.XContentParser;
|
import org.elasticsearch.common.xcontent.XContentParser;
|
||||||
import org.elasticsearch.common.xcontent.XContentParser.Token;
|
import org.elasticsearch.common.xcontent.XContentParser.Token;
|
||||||
|
@ -45,7 +42,6 @@ import org.elasticsearch.index.Index;
|
||||||
import org.elasticsearch.index.IndexSettings;
|
import org.elasticsearch.index.IndexSettings;
|
||||||
import org.elasticsearch.index.fielddata.FieldData;
|
import org.elasticsearch.index.fielddata.FieldData;
|
||||||
import org.elasticsearch.index.fielddata.IndexFieldData;
|
import org.elasticsearch.index.fielddata.IndexFieldData;
|
||||||
import org.elasticsearch.index.fielddata.IndexFieldData.XFieldComparatorSource.Nested;
|
|
||||||
import org.elasticsearch.index.fielddata.IndexFieldDataCache;
|
import org.elasticsearch.index.fielddata.IndexFieldDataCache;
|
||||||
import org.elasticsearch.index.fielddata.IndexNumericFieldData;
|
import org.elasticsearch.index.fielddata.IndexNumericFieldData;
|
||||||
import org.elasticsearch.index.fielddata.LeafNumericFieldData;
|
import org.elasticsearch.index.fielddata.LeafNumericFieldData;
|
||||||
|
@ -53,17 +49,13 @@ import org.elasticsearch.index.fielddata.NumericDoubleValues;
|
||||||
import org.elasticsearch.index.fielddata.ScriptDocValues;
|
import org.elasticsearch.index.fielddata.ScriptDocValues;
|
||||||
import org.elasticsearch.index.fielddata.SortedBinaryDocValues;
|
import org.elasticsearch.index.fielddata.SortedBinaryDocValues;
|
||||||
import org.elasticsearch.index.fielddata.SortedNumericDoubleValues;
|
import org.elasticsearch.index.fielddata.SortedNumericDoubleValues;
|
||||||
import org.elasticsearch.index.fielddata.fieldcomparator.DoubleValuesComparatorSource;
|
|
||||||
import org.elasticsearch.index.fielddata.plain.SortedNumericIndexFieldData;
|
import org.elasticsearch.index.fielddata.plain.SortedNumericIndexFieldData;
|
||||||
import org.elasticsearch.index.mapper.NumberFieldMapper.Defaults;
|
import org.elasticsearch.index.mapper.NumberFieldMapper.Defaults;
|
||||||
import org.elasticsearch.index.query.QueryShardContext;
|
import org.elasticsearch.index.query.QueryShardContext;
|
||||||
import org.elasticsearch.indices.breaker.CircuitBreakerService;
|
import org.elasticsearch.indices.breaker.CircuitBreakerService;
|
||||||
import org.elasticsearch.search.DocValueFormat;
|
import org.elasticsearch.search.DocValueFormat;
|
||||||
import org.elasticsearch.search.MultiValueMode;
|
|
||||||
import org.elasticsearch.search.aggregations.support.CoreValuesSourceType;
|
import org.elasticsearch.search.aggregations.support.CoreValuesSourceType;
|
||||||
import org.elasticsearch.search.aggregations.support.ValuesSourceType;
|
import org.elasticsearch.search.aggregations.support.ValuesSourceType;
|
||||||
import org.elasticsearch.search.sort.BucketedSort;
|
|
||||||
import org.elasticsearch.search.sort.SortOrder;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
|
@ -499,7 +491,7 @@ public class ScaledFloatFieldMapper extends FieldMapper {
|
||||||
return doubleValue;
|
return doubleValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class ScaledFloatIndexFieldData implements IndexNumericFieldData {
|
private static class ScaledFloatIndexFieldData extends IndexNumericFieldData {
|
||||||
|
|
||||||
private final IndexNumericFieldData scaledFieldData;
|
private final IndexNumericFieldData scaledFieldData;
|
||||||
private final double scalingFactor;
|
private final double scalingFactor;
|
||||||
|
@ -525,16 +517,15 @@ public class ScaledFloatFieldMapper extends FieldMapper {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SortField sortField(@Nullable Object missingValue, MultiValueMode sortMode, Nested nested, boolean reverse) {
|
protected boolean sortRequiresCustomComparator() {
|
||||||
final XFieldComparatorSource source = new DoubleValuesComparatorSource(this, missingValue, sortMode, nested);
|
/*
|
||||||
return new SortField(getFieldName(), source, reverse);
|
* We need to use a custom comparator because the non-custom
|
||||||
}
|
* comparator wouldn't properly decode the long bits into the
|
||||||
|
* double. Sorting on the long representation *would* put the
|
||||||
@Override
|
* docs in order. We just don't have a way to convert the long
|
||||||
public BucketedSort newBucketedSort(BigArrays bigArrays, Object missingValue, MultiValueMode sortMode, Nested nested,
|
* into a double the right way afterwords.
|
||||||
SortOrder sortOrder, DocValueFormat format, int bucketSize, BucketedSort.ExtraData extra) {
|
*/
|
||||||
return new DoubleValuesComparatorSource(this, missingValue, sortMode, nested)
|
return true;
|
||||||
.newBucketedSort(bigArrays, sortOrder, format, bucketSize, extra);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -549,7 +540,7 @@ public class ScaledFloatFieldMapper extends FieldMapper {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public NumericType getNumericType() {
|
public NumericType getNumericType() {
|
||||||
/**
|
/*
|
||||||
* {@link ScaledFloatLeafFieldData#getDoubleValues()} transforms the raw long values in `scaled` floats.
|
* {@link ScaledFloatLeafFieldData#getDoubleValues()} transforms the raw long values in `scaled` floats.
|
||||||
*/
|
*/
|
||||||
return NumericType.DOUBLE;
|
return NumericType.DOUBLE;
|
||||||
|
|
|
@ -97,8 +97,28 @@ setup:
|
||||||
|
|
||||||
- do:
|
- do:
|
||||||
search:
|
search:
|
||||||
rest_total_hits_as_int: true
|
body:
|
||||||
body: { "size" : 1, "sort" : { "number" : { "order" : "asc" } } }
|
size: 1
|
||||||
|
sort:
|
||||||
|
number:
|
||||||
|
order: asc
|
||||||
|
|
||||||
- match: { hits.total: 4 }
|
- match: { hits.total.value: 4 }
|
||||||
- match: { hits.hits.0._id: "3" }
|
- match: { hits.hits.0._id: "3" }
|
||||||
|
- match: { hits.hits.0.sort.0: -2.1 }
|
||||||
|
|
||||||
|
---
|
||||||
|
"Sort with numeric_type":
|
||||||
|
|
||||||
|
- do:
|
||||||
|
search:
|
||||||
|
body:
|
||||||
|
size: 1
|
||||||
|
sort:
|
||||||
|
number:
|
||||||
|
order: asc
|
||||||
|
numeric_type: long
|
||||||
|
|
||||||
|
- match: { hits.total.value: 4 }
|
||||||
|
- match: { hits.hits.0._id: "3" }
|
||||||
|
- match: { hits.hits.0.sort.0: -2 }
|
||||||
|
|
|
@ -19,31 +19,184 @@
|
||||||
|
|
||||||
package org.elasticsearch.index.fielddata;
|
package org.elasticsearch.index.fielddata;
|
||||||
|
|
||||||
public interface IndexNumericFieldData extends IndexFieldData<LeafNumericFieldData> {
|
import org.apache.lucene.index.SortedNumericDocValues;
|
||||||
|
import org.apache.lucene.search.SortField;
|
||||||
|
import org.apache.lucene.search.SortedNumericSelector;
|
||||||
|
import org.apache.lucene.search.SortedNumericSortField;
|
||||||
|
import org.elasticsearch.common.Nullable;
|
||||||
|
import org.elasticsearch.common.time.DateUtils;
|
||||||
|
import org.elasticsearch.common.util.BigArrays;
|
||||||
|
import org.elasticsearch.index.fielddata.IndexFieldData.XFieldComparatorSource.Nested;
|
||||||
|
import org.elasticsearch.index.fielddata.fieldcomparator.DoubleValuesComparatorSource;
|
||||||
|
import org.elasticsearch.index.fielddata.fieldcomparator.FloatValuesComparatorSource;
|
||||||
|
import org.elasticsearch.index.fielddata.fieldcomparator.LongValuesComparatorSource;
|
||||||
|
import org.elasticsearch.search.DocValueFormat;
|
||||||
|
import org.elasticsearch.search.MultiValueMode;
|
||||||
|
import org.elasticsearch.search.sort.BucketedSort;
|
||||||
|
import org.elasticsearch.search.sort.SortOrder;
|
||||||
|
|
||||||
enum NumericType {
|
import java.io.IOException;
|
||||||
BOOLEAN(false),
|
import java.util.function.LongUnaryOperator;
|
||||||
BYTE(false),
|
|
||||||
SHORT(false),
|
/**
|
||||||
INT(false),
|
* Base class for numeric field data.
|
||||||
LONG(false),
|
*/
|
||||||
DATE(false),
|
public abstract class IndexNumericFieldData implements IndexFieldData<LeafNumericFieldData> {
|
||||||
DATE_NANOSECONDS(false),
|
/**
|
||||||
HALF_FLOAT(true),
|
* The type of number.
|
||||||
FLOAT(true),
|
*/
|
||||||
DOUBLE(true);
|
public enum NumericType {
|
||||||
|
BOOLEAN(false, SortField.Type.LONG),
|
||||||
|
BYTE(false, SortField.Type.LONG),
|
||||||
|
SHORT(false, SortField.Type.LONG),
|
||||||
|
INT(false, SortField.Type.LONG),
|
||||||
|
LONG(false, SortField.Type.LONG),
|
||||||
|
DATE(false, SortField.Type.LONG),
|
||||||
|
DATE_NANOSECONDS(false, SortField.Type.LONG),
|
||||||
|
HALF_FLOAT(true, SortField.Type.LONG),
|
||||||
|
FLOAT(true, SortField.Type.FLOAT),
|
||||||
|
DOUBLE(true, SortField.Type.DOUBLE);
|
||||||
|
|
||||||
private final boolean floatingPoint;
|
private final boolean floatingPoint;
|
||||||
|
private final SortField.Type sortFieldType;
|
||||||
|
|
||||||
NumericType(boolean floatingPoint) {
|
NumericType(boolean floatingPoint, SortField.Type sortFieldType) {
|
||||||
this.floatingPoint = floatingPoint;
|
this.floatingPoint = floatingPoint;
|
||||||
|
this.sortFieldType = sortFieldType;
|
||||||
}
|
}
|
||||||
|
|
||||||
public final boolean isFloatingPoint() {
|
public final boolean isFloatingPoint() {
|
||||||
return floatingPoint;
|
return floatingPoint;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
NumericType getNumericType();
|
/**
|
||||||
|
* The numeric type of this number.
|
||||||
|
*/
|
||||||
|
public abstract NumericType getNumericType();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the {@link SortField} to used for sorting.
|
||||||
|
* Values are casted to the provided <code>targetNumericType</code> type if it doesn't
|
||||||
|
* match the field's <code>numericType</code>.
|
||||||
|
*/
|
||||||
|
public final SortField sortField(
|
||||||
|
NumericType targetNumericType,
|
||||||
|
Object missingValue,
|
||||||
|
MultiValueMode sortMode,
|
||||||
|
Nested nested,
|
||||||
|
boolean reverse
|
||||||
|
) {
|
||||||
|
XFieldComparatorSource source = comparatorSource(targetNumericType, missingValue, sortMode, nested);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Use a SortField with the custom comparator logic if required because
|
||||||
|
* 1. The underlying data source needs it.
|
||||||
|
* 2. We need to read the value from a nested field.
|
||||||
|
* 3. We Aren't using max or min to resolve the duplicates.
|
||||||
|
* 4. We have to cast the results to another type.
|
||||||
|
*/
|
||||||
|
if (sortRequiresCustomComparator()
|
||||||
|
|| nested != null
|
||||||
|
|| (sortMode != MultiValueMode.MAX && sortMode != MultiValueMode.MIN)
|
||||||
|
|| targetNumericType != getNumericType()) {
|
||||||
|
return new SortField(getFieldName(), source, reverse);
|
||||||
|
}
|
||||||
|
|
||||||
|
SortedNumericSelector.Type selectorType = sortMode == MultiValueMode.MAX ?
|
||||||
|
SortedNumericSelector.Type.MAX : SortedNumericSelector.Type.MIN;
|
||||||
|
SortField sortField = new SortedNumericSortField(getFieldName(), getNumericType().sortFieldType, reverse, selectorType);
|
||||||
|
sortField.setMissingValue(source.missingObject(missingValue, reverse));
|
||||||
|
return sortField;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Does {@link #sortField} require a custom comparator because of the way
|
||||||
|
* the data is stored in doc values ({@code true}) or are the docs values
|
||||||
|
* stored such that they can be sorted without decoding ({@code false}).
|
||||||
|
*/
|
||||||
|
protected abstract boolean sortRequiresCustomComparator();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final SortField sortField(Object missingValue, MultiValueMode sortMode, Nested nested, boolean reverse) {
|
||||||
|
return sortField(getNumericType(), missingValue, sortMode, nested, reverse);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builds a {@linkplain BucketedSort} for the {@code targetNumericType},
|
||||||
|
* casting the values if their native type doesn't match.
|
||||||
|
*/
|
||||||
|
public final BucketedSort newBucketedSort(NumericType targetNumericType, BigArrays bigArrays, @Nullable Object missingValue,
|
||||||
|
MultiValueMode sortMode, Nested nested, SortOrder sortOrder, DocValueFormat format,
|
||||||
|
int bucketSize, BucketedSort.ExtraData extra) {
|
||||||
|
return comparatorSource(targetNumericType, missingValue, sortMode, nested)
|
||||||
|
.newBucketedSort(bigArrays, sortOrder, format, bucketSize, extra);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final BucketedSort newBucketedSort(BigArrays bigArrays, @Nullable Object missingValue, MultiValueMode sortMode, Nested nested,
|
||||||
|
SortOrder sortOrder, DocValueFormat format, int bucketSize, BucketedSort.ExtraData extra) {
|
||||||
|
return newBucketedSort(getNumericType(), bigArrays, missingValue, sortMode, nested, sortOrder, format, bucketSize, extra);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Build a {@link XFieldComparatorSource} matching the parameters.
|
||||||
|
*/
|
||||||
|
private XFieldComparatorSource comparatorSource(
|
||||||
|
NumericType targetNumericType,
|
||||||
|
@Nullable Object missingValue,
|
||||||
|
MultiValueMode sortMode,
|
||||||
|
Nested nested
|
||||||
|
) {
|
||||||
|
switch (targetNumericType) {
|
||||||
|
case HALF_FLOAT:
|
||||||
|
case FLOAT:
|
||||||
|
return new FloatValuesComparatorSource(this, missingValue, sortMode, nested);
|
||||||
|
case DOUBLE:
|
||||||
|
return new DoubleValuesComparatorSource(this, missingValue, sortMode, nested);
|
||||||
|
case DATE:
|
||||||
|
return dateComparatorSource(missingValue, sortMode, nested);
|
||||||
|
case DATE_NANOSECONDS:
|
||||||
|
return dateNanosComparatorSource(missingValue, sortMode, nested);
|
||||||
|
default:
|
||||||
|
assert !targetNumericType.isFloatingPoint();
|
||||||
|
return new LongValuesComparatorSource(this, missingValue, sortMode, nested);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected XFieldComparatorSource dateComparatorSource(@Nullable Object missingValue, MultiValueMode sortMode, Nested nested) {
|
||||||
|
return new LongValuesComparatorSource(this, missingValue, sortMode, nested);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected XFieldComparatorSource dateNanosComparatorSource(@Nullable Object missingValue, MultiValueMode sortMode, Nested nested) {
|
||||||
|
return new LongValuesComparatorSource(this, missingValue, sortMode, nested, dvs -> convertNumeric(dvs, DateUtils::toNanoSeconds));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert the values in <code>dvs</code> using the provided <code>converter</code>.
|
||||||
|
*/
|
||||||
|
protected static SortedNumericDocValues convertNumeric(SortedNumericDocValues values, LongUnaryOperator converter) {
|
||||||
|
return new AbstractSortedNumericDocValues() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean advanceExact(int target) throws IOException {
|
||||||
|
return values.advanceExact(target);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long nextValue() throws IOException {
|
||||||
|
return converter.applyAsLong(values.nextValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int docValueCount() {
|
||||||
|
return values.docValueCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int nextDoc() throws IOException {
|
||||||
|
return values.nextDoc();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,17 +26,11 @@ import org.apache.lucene.index.LeafReader;
|
||||||
import org.apache.lucene.index.LeafReaderContext;
|
import org.apache.lucene.index.LeafReaderContext;
|
||||||
import org.apache.lucene.index.NumericDocValues;
|
import org.apache.lucene.index.NumericDocValues;
|
||||||
import org.apache.lucene.index.SortedNumericDocValues;
|
import org.apache.lucene.index.SortedNumericDocValues;
|
||||||
import org.apache.lucene.search.SortField;
|
|
||||||
import org.apache.lucene.search.SortedNumericSelector;
|
|
||||||
import org.apache.lucene.search.SortedNumericSortField;
|
|
||||||
import org.apache.lucene.util.Accountable;
|
import org.apache.lucene.util.Accountable;
|
||||||
import org.apache.lucene.util.NumericUtils;
|
import org.apache.lucene.util.NumericUtils;
|
||||||
import org.elasticsearch.common.Nullable;
|
|
||||||
import org.elasticsearch.common.time.DateUtils;
|
import org.elasticsearch.common.time.DateUtils;
|
||||||
import org.elasticsearch.common.util.BigArrays;
|
|
||||||
import org.elasticsearch.index.Index;
|
import org.elasticsearch.index.Index;
|
||||||
import org.elasticsearch.index.IndexSettings;
|
import org.elasticsearch.index.IndexSettings;
|
||||||
import org.elasticsearch.index.fielddata.AbstractSortedNumericDocValues;
|
|
||||||
import org.elasticsearch.index.fielddata.FieldData;
|
import org.elasticsearch.index.fielddata.FieldData;
|
||||||
import org.elasticsearch.index.fielddata.IndexFieldData;
|
import org.elasticsearch.index.fielddata.IndexFieldData;
|
||||||
import org.elasticsearch.index.fielddata.IndexFieldData.XFieldComparatorSource.Nested;
|
import org.elasticsearch.index.fielddata.IndexFieldData.XFieldComparatorSource.Nested;
|
||||||
|
@ -45,28 +39,22 @@ import org.elasticsearch.index.fielddata.IndexNumericFieldData;
|
||||||
import org.elasticsearch.index.fielddata.LeafNumericFieldData;
|
import org.elasticsearch.index.fielddata.LeafNumericFieldData;
|
||||||
import org.elasticsearch.index.fielddata.NumericDoubleValues;
|
import org.elasticsearch.index.fielddata.NumericDoubleValues;
|
||||||
import org.elasticsearch.index.fielddata.SortedNumericDoubleValues;
|
import org.elasticsearch.index.fielddata.SortedNumericDoubleValues;
|
||||||
import org.elasticsearch.index.fielddata.fieldcomparator.DoubleValuesComparatorSource;
|
|
||||||
import org.elasticsearch.index.fielddata.fieldcomparator.FloatValuesComparatorSource;
|
|
||||||
import org.elasticsearch.index.fielddata.fieldcomparator.LongValuesComparatorSource;
|
import org.elasticsearch.index.fielddata.fieldcomparator.LongValuesComparatorSource;
|
||||||
import org.elasticsearch.index.mapper.MappedFieldType;
|
import org.elasticsearch.index.mapper.MappedFieldType;
|
||||||
import org.elasticsearch.index.mapper.MapperService;
|
import org.elasticsearch.index.mapper.MapperService;
|
||||||
import org.elasticsearch.indices.breaker.CircuitBreakerService;
|
import org.elasticsearch.indices.breaker.CircuitBreakerService;
|
||||||
import org.elasticsearch.search.DocValueFormat;
|
|
||||||
import org.elasticsearch.search.MultiValueMode;
|
import org.elasticsearch.search.MultiValueMode;
|
||||||
import org.elasticsearch.search.sort.BucketedSort;
|
|
||||||
import org.elasticsearch.search.sort.SortOrder;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.function.LongUnaryOperator;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* FieldData backed by {@link LeafReader#getSortedNumericDocValues(String)}
|
* FieldData backed by {@link LeafReader#getSortedNumericDocValues(String)}
|
||||||
* @see DocValuesType#SORTED_NUMERIC
|
* @see DocValuesType#SORTED_NUMERIC
|
||||||
*/
|
*/
|
||||||
public class SortedNumericIndexFieldData implements IndexNumericFieldData {
|
public class SortedNumericIndexFieldData extends IndexNumericFieldData {
|
||||||
public static class Builder implements IndexFieldData.Builder {
|
public static class Builder implements IndexFieldData.Builder {
|
||||||
|
|
||||||
private final NumericType numericType;
|
private final NumericType numericType;
|
||||||
|
@ -113,95 +101,29 @@ public class SortedNumericIndexFieldData implements IndexNumericFieldData {
|
||||||
return index;
|
return index;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* Returns the {@link SortField} to used for sorting.
|
protected boolean sortRequiresCustomComparator() {
|
||||||
* Values are casted to the provided <code>targetNumericType</code> type if it doesn't
|
return numericType == NumericType.HALF_FLOAT;
|
||||||
* match the field's <code>numericType</code>.
|
|
||||||
*/
|
|
||||||
public SortField sortField(NumericType targetNumericType, Object missingValue, MultiValueMode sortMode,
|
|
||||||
Nested nested, boolean reverse) {
|
|
||||||
final XFieldComparatorSource source = comparatorSource(targetNumericType, missingValue, sortMode, nested);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if we can use a simple {@link SortedNumericSortField} compatible with index sorting and
|
|
||||||
* returns a custom sort field otherwise.
|
|
||||||
*/
|
|
||||||
if (nested != null
|
|
||||||
|| (sortMode != MultiValueMode.MAX && sortMode != MultiValueMode.MIN)
|
|
||||||
|| numericType == NumericType.HALF_FLOAT
|
|
||||||
|| targetNumericType != numericType) {
|
|
||||||
return new SortField(fieldName, source, reverse);
|
|
||||||
}
|
|
||||||
|
|
||||||
final SortField sortField;
|
|
||||||
final SortedNumericSelector.Type selectorType = sortMode == MultiValueMode.MAX ?
|
|
||||||
SortedNumericSelector.Type.MAX : SortedNumericSelector.Type.MIN;
|
|
||||||
switch (numericType) {
|
|
||||||
case FLOAT:
|
|
||||||
sortField = new SortedNumericSortField(fieldName, SortField.Type.FLOAT, reverse, selectorType);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case DOUBLE:
|
|
||||||
sortField = new SortedNumericSortField(fieldName, SortField.Type.DOUBLE, reverse, selectorType);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
assert !numericType.isFloatingPoint();
|
|
||||||
sortField = new SortedNumericSortField(fieldName, SortField.Type.LONG, reverse, selectorType);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
sortField.setMissingValue(source.missingObject(missingValue, reverse));
|
|
||||||
return sortField;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SortField sortField(Object missingValue, MultiValueMode sortMode, Nested nested, boolean reverse) {
|
protected XFieldComparatorSource dateComparatorSource(Object missingValue, MultiValueMode sortMode, Nested nested) {
|
||||||
return sortField(numericType, missingValue, sortMode, nested, reverse);
|
if (numericType == NumericType.DATE_NANOSECONDS) {
|
||||||
}
|
// converts date values to nanosecond resolution
|
||||||
|
return new LongValuesComparatorSource(this, missingValue,
|
||||||
/**
|
sortMode, nested, dvs -> convertNumeric(dvs, DateUtils::toMilliSeconds));
|
||||||
* Builds a {@linkplain BucketedSort} for the {@code targetNumericType},
|
|
||||||
* casting the values if their native type doesn't match.
|
|
||||||
*/
|
|
||||||
public BucketedSort newBucketedSort(NumericType targetNumericType, BigArrays bigArrays, @Nullable Object missingValue,
|
|
||||||
MultiValueMode sortMode, Nested nested, SortOrder sortOrder, DocValueFormat format,
|
|
||||||
int bucketSize, BucketedSort.ExtraData extra) {
|
|
||||||
return comparatorSource(targetNumericType, missingValue, sortMode, nested)
|
|
||||||
.newBucketedSort(bigArrays, sortOrder, format, bucketSize, extra);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public BucketedSort newBucketedSort(BigArrays bigArrays, @Nullable Object missingValue, MultiValueMode sortMode, Nested nested,
|
|
||||||
SortOrder sortOrder, DocValueFormat format, int bucketSize, BucketedSort.ExtraData extra) {
|
|
||||||
return newBucketedSort(numericType, bigArrays, missingValue, sortMode, nested, sortOrder, format, bucketSize, extra);
|
|
||||||
}
|
|
||||||
|
|
||||||
private XFieldComparatorSource comparatorSource(NumericType targetNumericType, @Nullable Object missingValue, MultiValueMode sortMode,
|
|
||||||
Nested nested) {
|
|
||||||
switch (targetNumericType) {
|
|
||||||
case HALF_FLOAT:
|
|
||||||
case FLOAT:
|
|
||||||
return new FloatValuesComparatorSource(this, missingValue, sortMode, nested);
|
|
||||||
case DOUBLE:
|
|
||||||
return new DoubleValuesComparatorSource(this, missingValue, sortMode, nested);
|
|
||||||
case DATE:
|
|
||||||
if (numericType == NumericType.DATE_NANOSECONDS) {
|
|
||||||
// converts date values to nanosecond resolution
|
|
||||||
return new LongValuesComparatorSource(this, missingValue,
|
|
||||||
sortMode, nested, dvs -> convertNanosToMillis(dvs));
|
|
||||||
}
|
|
||||||
return new LongValuesComparatorSource(this, missingValue, sortMode, nested);
|
|
||||||
case DATE_NANOSECONDS:
|
|
||||||
if (numericType == NumericType.DATE) {
|
|
||||||
// converts date_nanos values to millisecond resolution
|
|
||||||
return new LongValuesComparatorSource(this, missingValue,
|
|
||||||
sortMode, nested, dvs -> convertMillisToNanos(dvs));
|
|
||||||
}
|
|
||||||
return new LongValuesComparatorSource(this, missingValue, sortMode, nested);
|
|
||||||
default:
|
|
||||||
assert !targetNumericType.isFloatingPoint();
|
|
||||||
return new LongValuesComparatorSource(this, missingValue, sortMode, nested);
|
|
||||||
}
|
}
|
||||||
|
return new LongValuesComparatorSource(this, missingValue, sortMode, nested);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected XFieldComparatorSource dateNanosComparatorSource(Object missingValue, MultiValueMode sortMode, Nested nested) {
|
||||||
|
if (numericType == NumericType.DATE) {
|
||||||
|
// converts date_nanos values to millisecond resolution
|
||||||
|
return new LongValuesComparatorSource(this, missingValue,
|
||||||
|
sortMode, nested, dvs -> convertNumeric(dvs, DateUtils::toNanoSeconds));
|
||||||
|
}
|
||||||
|
return new LongValuesComparatorSource(this, missingValue, sortMode, nested);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -250,7 +172,7 @@ public class SortedNumericIndexFieldData implements IndexNumericFieldData {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SortedNumericDocValues getLongValues() {
|
public SortedNumericDocValues getLongValues() {
|
||||||
return convertNanosToMillis(getLongValuesAsNanos());
|
return convertNumeric(getLongValuesAsNanos(), DateUtils::toMilliSeconds);
|
||||||
}
|
}
|
||||||
|
|
||||||
public SortedNumericDocValues getLongValuesAsNanos() {
|
public SortedNumericDocValues getLongValuesAsNanos() {
|
||||||
|
@ -520,47 +442,4 @@ public class SortedNumericIndexFieldData implements IndexNumericFieldData {
|
||||||
return Collections.emptyList();
|
return Collections.emptyList();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Convert the values in <code>dvs</code> from nanosecond to millisecond resolution.
|
|
||||||
*/
|
|
||||||
static SortedNumericDocValues convertNanosToMillis(SortedNumericDocValues dvs) {
|
|
||||||
return convertNumeric(dvs, DateUtils::toMilliSeconds);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Convert the values in <code>dvs</code> from millisecond to nanosecond resolution.
|
|
||||||
*/
|
|
||||||
static SortedNumericDocValues convertMillisToNanos(SortedNumericDocValues values) {
|
|
||||||
return convertNumeric(values, DateUtils::toNanoSeconds);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Convert the values in <code>dvs</code> using the provided <code>converter</code>.
|
|
||||||
*/
|
|
||||||
private static SortedNumericDocValues convertNumeric(SortedNumericDocValues values, LongUnaryOperator converter) {
|
|
||||||
return new AbstractSortedNumericDocValues() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean advanceExact(int target) throws IOException {
|
|
||||||
return values.advanceExact(target);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public long nextValue() throws IOException {
|
|
||||||
return converter.applyAsLong(values.nextValue());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int docValueCount() {
|
|
||||||
return values.docValueCount();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int nextDoc() throws IOException {
|
|
||||||
return values.nextDoc();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,7 +44,6 @@ import org.elasticsearch.index.fielddata.IndexFieldData;
|
||||||
import org.elasticsearch.index.fielddata.IndexFieldData.XFieldComparatorSource.Nested;
|
import org.elasticsearch.index.fielddata.IndexFieldData.XFieldComparatorSource.Nested;
|
||||||
import org.elasticsearch.index.fielddata.IndexNumericFieldData;
|
import org.elasticsearch.index.fielddata.IndexNumericFieldData;
|
||||||
import org.elasticsearch.index.fielddata.IndexNumericFieldData.NumericType;
|
import org.elasticsearch.index.fielddata.IndexNumericFieldData.NumericType;
|
||||||
import org.elasticsearch.index.fielddata.plain.SortedNumericIndexFieldData;
|
|
||||||
import org.elasticsearch.index.mapper.DateFieldMapper.DateFieldType;
|
import org.elasticsearch.index.mapper.DateFieldMapper.DateFieldType;
|
||||||
import org.elasticsearch.index.mapper.KeywordFieldMapper;
|
import org.elasticsearch.index.mapper.KeywordFieldMapper;
|
||||||
import org.elasticsearch.index.mapper.MappedFieldType;
|
import org.elasticsearch.index.mapper.MappedFieldType;
|
||||||
|
@ -53,9 +52,9 @@ import org.elasticsearch.index.query.QueryBuilder;
|
||||||
import org.elasticsearch.index.query.QueryRewriteContext;
|
import org.elasticsearch.index.query.QueryRewriteContext;
|
||||||
import org.elasticsearch.index.query.QueryShardContext;
|
import org.elasticsearch.index.query.QueryShardContext;
|
||||||
import org.elasticsearch.index.query.QueryShardException;
|
import org.elasticsearch.index.query.QueryShardException;
|
||||||
import org.elasticsearch.search.SearchSortValuesAndFormats;
|
|
||||||
import org.elasticsearch.search.DocValueFormat;
|
import org.elasticsearch.search.DocValueFormat;
|
||||||
import org.elasticsearch.search.MultiValueMode;
|
import org.elasticsearch.search.MultiValueMode;
|
||||||
|
import org.elasticsearch.search.SearchSortValuesAndFormats;
|
||||||
import org.elasticsearch.search.builder.SearchSourceBuilder;
|
import org.elasticsearch.search.builder.SearchSourceBuilder;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
@ -411,7 +410,7 @@ public class FieldSortBuilder extends SortBuilder<FieldSortBuilder> {
|
||||||
throw new QueryShardException(context,
|
throw new QueryShardException(context,
|
||||||
"[numeric_type] option cannot be set on a non-numeric field, got " + fieldType.typeName());
|
"[numeric_type] option cannot be set on a non-numeric field, got " + fieldType.typeName());
|
||||||
}
|
}
|
||||||
SortedNumericIndexFieldData numericFieldData = (SortedNumericIndexFieldData) fieldData;
|
IndexNumericFieldData numericFieldData = (IndexNumericFieldData) fieldData;
|
||||||
NumericType resolvedType = resolveNumericType(numericType);
|
NumericType resolvedType = resolveNumericType(numericType);
|
||||||
field = numericFieldData.sortField(resolvedType, missing, localSortMode(), nested, reverse);
|
field = numericFieldData.sortField(resolvedType, missing, localSortMode(), nested, reverse);
|
||||||
} else {
|
} else {
|
||||||
|
@ -487,7 +486,11 @@ public class FieldSortBuilder extends SortBuilder<FieldSortBuilder> {
|
||||||
throw new QueryShardException(context, "we only support AVG, MEDIAN and SUM on number based fields");
|
throw new QueryShardException(context, "we only support AVG, MEDIAN and SUM on number based fields");
|
||||||
}
|
}
|
||||||
if (numericType != null) {
|
if (numericType != null) {
|
||||||
SortedNumericIndexFieldData numericFieldData = (SortedNumericIndexFieldData) fieldData;
|
if (fieldData instanceof IndexNumericFieldData == false) {
|
||||||
|
throw new QueryShardException(context,
|
||||||
|
"[numeric_type] option cannot be set on a non-numeric field, got " + fieldType.typeName());
|
||||||
|
}
|
||||||
|
IndexNumericFieldData numericFieldData = (IndexNumericFieldData) fieldData;
|
||||||
NumericType resolvedType = resolveNumericType(numericType);
|
NumericType resolvedType = resolveNumericType(numericType);
|
||||||
return numericFieldData.newBucketedSort(resolvedType, context.bigArrays(), missing, localSortMode(), nested, order,
|
return numericFieldData.newBucketedSort(resolvedType, context.bigArrays(), missing, localSortMode(), nested, order,
|
||||||
fieldType.docValueFormat(null, null), bucketSize, extra);
|
fieldType.docValueFormat(null, null), bucketSize, extra);
|
||||||
|
|
|
@ -54,11 +54,11 @@ import org.elasticsearch.common.lucene.search.function.ScoreFunction;
|
||||||
import org.elasticsearch.common.lucene.search.function.WeightFactorFunction;
|
import org.elasticsearch.common.lucene.search.function.WeightFactorFunction;
|
||||||
import org.elasticsearch.common.util.BigArrays;
|
import org.elasticsearch.common.util.BigArrays;
|
||||||
import org.elasticsearch.index.Index;
|
import org.elasticsearch.index.Index;
|
||||||
import org.elasticsearch.index.fielddata.LeafFieldData;
|
|
||||||
import org.elasticsearch.index.fielddata.LeafNumericFieldData;
|
|
||||||
import org.elasticsearch.index.fielddata.IndexFieldData;
|
import org.elasticsearch.index.fielddata.IndexFieldData;
|
||||||
import org.elasticsearch.index.fielddata.IndexFieldData.XFieldComparatorSource.Nested;
|
import org.elasticsearch.index.fielddata.IndexFieldData.XFieldComparatorSource.Nested;
|
||||||
import org.elasticsearch.index.fielddata.IndexNumericFieldData;
|
import org.elasticsearch.index.fielddata.IndexNumericFieldData;
|
||||||
|
import org.elasticsearch.index.fielddata.LeafFieldData;
|
||||||
|
import org.elasticsearch.index.fielddata.LeafNumericFieldData;
|
||||||
import org.elasticsearch.index.fielddata.ScriptDocValues;
|
import org.elasticsearch.index.fielddata.ScriptDocValues;
|
||||||
import org.elasticsearch.index.fielddata.SortedBinaryDocValues;
|
import org.elasticsearch.index.fielddata.SortedBinaryDocValues;
|
||||||
import org.elasticsearch.index.fielddata.SortedNumericDoubleValues;
|
import org.elasticsearch.index.fielddata.SortedNumericDoubleValues;
|
||||||
|
@ -169,7 +169,7 @@ public class FunctionScoreTests extends ESTestCase {
|
||||||
/**
|
/**
|
||||||
* Stub for IndexNumericFieldData needed by some score functions. Returns 1 as value always.
|
* Stub for IndexNumericFieldData needed by some score functions. Returns 1 as value always.
|
||||||
*/
|
*/
|
||||||
private static class IndexNumericFieldDataStub implements IndexNumericFieldData {
|
private static class IndexNumericFieldDataStub extends IndexNumericFieldData {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public NumericType getNumericType() {
|
public NumericType getNumericType() {
|
||||||
|
@ -241,15 +241,8 @@ public class FunctionScoreTests extends ESTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SortField sortField(@Nullable Object missingValue, MultiValueMode sortMode,
|
protected boolean sortRequiresCustomComparator() {
|
||||||
XFieldComparatorSource.Nested nested, boolean reverse) {
|
return false;
|
||||||
throw new UnsupportedOperationException(UNSUPPORTED);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public BucketedSort newBucketedSort(BigArrays bigArrays, Object missingValue, MultiValueMode sortMode, Nested nested,
|
|
||||||
SortOrder sortOrder, DocValueFormat format, int bucketSize, BucketedSort.ExtraData extra) {
|
|
||||||
throw new UnsupportedOperationException(UNSUPPORTED);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
Loading…
Reference in New Issue