Added `sort_mode` option that defines what value to pick in the case the sort field is multi-valued.
The `min` and `max` sort modes are supported for all field types. Either the lowest value or the highest value is picked. In addition to that number based fields also support `sum` and `avg` as sort mode. If `sum` sort mode is used then all the values for a field and belonging to a document are added together and the result of that is used as sort value. If the `avg` sort mode is used then the average of all values for the sort field belonging to that document is used as sort value. Relates to #2634
This commit is contained in:
parent
7d13545e33
commit
fc13499ff5
|
@ -27,6 +27,7 @@ import org.elasticsearch.common.Nullable;
|
|||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.index.Index;
|
||||
import org.elasticsearch.index.IndexComponent;
|
||||
import org.elasticsearch.index.fielddata.fieldcomparator.SortMode;
|
||||
import org.elasticsearch.index.mapper.FieldMapper;
|
||||
import org.elasticsearch.index.settings.IndexSettings;
|
||||
|
||||
|
@ -57,7 +58,7 @@ public interface IndexFieldData<FD extends AtomicFieldData> extends IndexCompone
|
|||
/**
|
||||
* Comparator used for sorting.
|
||||
*/
|
||||
XFieldComparatorSource comparatorSource(@Nullable Object missingValue);
|
||||
XFieldComparatorSource comparatorSource(@Nullable Object missingValue, SortMode sortMode);
|
||||
|
||||
/**
|
||||
* Clears any resources associated with this field data.
|
||||
|
|
|
@ -19,18 +19,18 @@
|
|||
|
||||
package org.elasticsearch.index.fielddata.fieldcomparator;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.elasticsearch.index.fielddata.IndexNumericFieldData;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
*/
|
||||
public final class ByteValuesComparator extends LongValuesComparatorBase<Byte> {
|
||||
|
||||
private final byte[] values;
|
||||
|
||||
public ByteValuesComparator(IndexNumericFieldData<?> indexFieldData, byte missingValue, int numHits, boolean reversed) {
|
||||
super(indexFieldData, missingValue, reversed);
|
||||
public ByteValuesComparator(IndexNumericFieldData<?> indexFieldData, byte missingValue, int numHits, SortMode sortMode) {
|
||||
super(indexFieldData, missingValue, sortMode);
|
||||
this.values = new byte[numHits];
|
||||
assert indexFieldData.getNumericType().requiredBits() <= 8;
|
||||
}
|
||||
|
|
|
@ -33,10 +33,12 @@ public class ByteValuesComparatorSource extends IndexFieldData.XFieldComparatorS
|
|||
|
||||
private final IndexNumericFieldData<?> indexFieldData;
|
||||
private final Object missingValue;
|
||||
private final SortMode sortMode;
|
||||
|
||||
public ByteValuesComparatorSource(IndexNumericFieldData<?> indexFieldData, @Nullable Object missingValue) {
|
||||
public ByteValuesComparatorSource(IndexNumericFieldData<?> indexFieldData, @Nullable Object missingValue, SortMode sortMode) {
|
||||
this.indexFieldData = indexFieldData;
|
||||
this.missingValue = missingValue;
|
||||
this.sortMode = sortMode;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -57,6 +59,6 @@ public class ByteValuesComparatorSource extends IndexFieldData.XFieldComparatorS
|
|||
dMissingValue = missingValue instanceof Number ? ((Number) missingValue).byteValue() : Byte.parseByte(missingValue.toString());
|
||||
}
|
||||
|
||||
return new ByteValuesComparator(indexFieldData, dMissingValue, numHits, reversed);
|
||||
return new ByteValuesComparator(indexFieldData, dMissingValue, numHits, sortMode);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,9 +30,11 @@ import java.io.IOException;
|
|||
public class BytesRefFieldComparatorSource extends IndexFieldData.XFieldComparatorSource {
|
||||
|
||||
private final IndexFieldData<?> indexFieldData;
|
||||
private final SortMode sortMode;
|
||||
|
||||
public BytesRefFieldComparatorSource(IndexFieldData<?> indexFieldData) {
|
||||
public BytesRefFieldComparatorSource(IndexFieldData<?> indexFieldData, SortMode sortMode) {
|
||||
this.indexFieldData = indexFieldData;
|
||||
this.sortMode = sortMode;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -44,8 +46,8 @@ public class BytesRefFieldComparatorSource extends IndexFieldData.XFieldComparat
|
|||
public FieldComparator<?> newComparator(String fieldname, int numHits, int sortPos, boolean reversed) throws IOException {
|
||||
assert fieldname.equals(indexFieldData.getFieldNames().indexName());
|
||||
if (indexFieldData.valuesOrdered() && indexFieldData instanceof IndexFieldData.WithOrdinals) {
|
||||
return new BytesRefOrdValComparator((IndexFieldData.WithOrdinals<?>) indexFieldData, numHits, reversed);
|
||||
return new BytesRefOrdValComparator((IndexFieldData.WithOrdinals<?>) indexFieldData, numHits, sortMode);
|
||||
}
|
||||
return new BytesRefValComparator(indexFieldData, numHits, reversed);
|
||||
return new BytesRefValComparator(indexFieldData, numHits, sortMode);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -47,7 +47,7 @@ public final class BytesRefOrdValComparator extends FieldComparator<BytesRef> {
|
|||
@lucene.internal */
|
||||
final int[] ords;
|
||||
|
||||
final boolean reversed;
|
||||
final SortMode sortMode;
|
||||
|
||||
/* Values for each slot.
|
||||
@lucene.internal */
|
||||
|
@ -89,9 +89,9 @@ public final class BytesRefOrdValComparator extends FieldComparator<BytesRef> {
|
|||
|
||||
final BytesRef tempBR = new BytesRef();
|
||||
|
||||
public BytesRefOrdValComparator(IndexFieldData.WithOrdinals<?> indexFieldData, int numHits, boolean reversed) {
|
||||
public BytesRefOrdValComparator(IndexFieldData.WithOrdinals<?> indexFieldData, int numHits, SortMode sortMode) {
|
||||
this.indexFieldData = indexFieldData;
|
||||
this.reversed = reversed;
|
||||
this.sortMode = sortMode;
|
||||
ords = new int[numHits];
|
||||
values = new BytesRef[numHits];
|
||||
readerGen = new int[numHits];
|
||||
|
@ -487,7 +487,7 @@ public final class BytesRefOrdValComparator extends FieldComparator<BytesRef> {
|
|||
|
||||
@Override
|
||||
public int compareBottom(int doc) throws IOException {
|
||||
final int docOrd = getRelevantOrd(readerOrds, doc, reversed);
|
||||
final int docOrd = getRelevantOrd(readerOrds, doc, sortMode);
|
||||
if (bottomSameReader) {
|
||||
// ord is precisely comparable, even in the equal case
|
||||
return bottomOrd - docOrd;
|
||||
|
@ -503,7 +503,7 @@ public final class BytesRefOrdValComparator extends FieldComparator<BytesRef> {
|
|||
|
||||
@Override
|
||||
public void copy(int slot, int doc) throws IOException {
|
||||
final int ord = getRelevantOrd(readerOrds, doc, reversed);
|
||||
final int ord = getRelevantOrd(readerOrds, doc, sortMode);
|
||||
ords[slot] = ord;
|
||||
if (ord == 0) {
|
||||
values[slot] = null;
|
||||
|
@ -519,7 +519,7 @@ public final class BytesRefOrdValComparator extends FieldComparator<BytesRef> {
|
|||
|
||||
@Override
|
||||
public int compareDocToValue(int doc, BytesRef value) {
|
||||
BytesRef docValue = getRelevantValue(termsIndex, doc, reversed);
|
||||
BytesRef docValue = getRelevantValue(termsIndex, doc, sortMode);
|
||||
if (docValue == null) {
|
||||
if (value == null) {
|
||||
return 0;
|
||||
|
@ -533,7 +533,7 @@ public final class BytesRefOrdValComparator extends FieldComparator<BytesRef> {
|
|||
|
||||
}
|
||||
|
||||
static BytesRef getRelevantValue(BytesValues.WithOrdinals readerValues, int docId, boolean reversed) {
|
||||
static BytesRef getRelevantValue(BytesValues.WithOrdinals readerValues, int docId, SortMode sortMode) {
|
||||
BytesValues.Iter iter = readerValues.getIter(docId);
|
||||
if (!iter.hasNext()) {
|
||||
return null;
|
||||
|
@ -543,7 +543,7 @@ public final class BytesRefOrdValComparator extends FieldComparator<BytesRef> {
|
|||
BytesRef relevantVal = currentVal;
|
||||
while (true) {
|
||||
int cmp = currentVal.compareTo(relevantVal);
|
||||
if (reversed) {
|
||||
if (sortMode == SortMode.MAX) {
|
||||
if (cmp > 0) {
|
||||
relevantVal = currentVal;
|
||||
}
|
||||
|
@ -560,7 +560,7 @@ public final class BytesRefOrdValComparator extends FieldComparator<BytesRef> {
|
|||
return relevantVal;
|
||||
}
|
||||
|
||||
static int getRelevantOrd(Ordinals.Docs readerOrds, int docId, boolean reversed) {
|
||||
static int getRelevantOrd(Ordinals.Docs readerOrds, int docId, SortMode sortMode) {
|
||||
Ordinals.Docs.Iter iter = readerOrds.getIter(docId);
|
||||
int currentVal = iter.next();
|
||||
if (currentVal == 0) {
|
||||
|
@ -569,7 +569,7 @@ public final class BytesRefOrdValComparator extends FieldComparator<BytesRef> {
|
|||
|
||||
int relevantVal = currentVal;
|
||||
while (true) {
|
||||
if (reversed) {
|
||||
if (sortMode == SortMode.MAX) {
|
||||
if (currentVal > relevantVal) {
|
||||
relevantVal = currentVal;
|
||||
}
|
||||
|
|
|
@ -37,14 +37,14 @@ import java.io.IOException;
|
|||
public final class BytesRefValComparator extends FieldComparator<BytesRef> {
|
||||
|
||||
private final IndexFieldData<?> indexFieldData;
|
||||
private final boolean reversed;
|
||||
private final SortMode sortMode;
|
||||
|
||||
private final BytesRef[] values;
|
||||
private BytesRef bottom;
|
||||
private BytesValues docTerms;
|
||||
|
||||
BytesRefValComparator(IndexFieldData<?> indexFieldData, int numHits, boolean reversed) {
|
||||
this.reversed = reversed;
|
||||
BytesRefValComparator(IndexFieldData<?> indexFieldData, int numHits, SortMode sortMode) {
|
||||
this.sortMode = sortMode;
|
||||
values = new BytesRef[numHits];
|
||||
this.indexFieldData = indexFieldData;
|
||||
}
|
||||
|
@ -74,7 +74,7 @@ public final class BytesRefValComparator extends FieldComparator<BytesRef> {
|
|||
public FieldComparator<BytesRef> setNextReader(AtomicReaderContext context) throws IOException {
|
||||
docTerms = indexFieldData.load(context).getBytesValues();
|
||||
if (docTerms.isMultiValued()) {
|
||||
docTerms = new MultiValuedBytesWrapper(docTerms, reversed);
|
||||
docTerms = new MultiValuedBytesWrapper(docTerms, sortMode);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
@ -150,11 +150,11 @@ public final class BytesRefValComparator extends FieldComparator<BytesRef> {
|
|||
|
||||
private static final class MultiValuedBytesWrapper extends FilteredByteValues {
|
||||
|
||||
private final boolean reversed;
|
||||
private final SortMode sortMode;
|
||||
|
||||
public MultiValuedBytesWrapper(BytesValues delegate, boolean reversed) {
|
||||
public MultiValuedBytesWrapper(BytesValues delegate, SortMode sortMode) {
|
||||
super(delegate);
|
||||
this.reversed = reversed;
|
||||
this.sortMode = sortMode;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -168,7 +168,7 @@ public final class BytesRefValComparator extends FieldComparator<BytesRef> {
|
|||
BytesRef relevantVal = currentVal;
|
||||
while (true) {
|
||||
int cmp = currentVal.compareTo(relevantVal);
|
||||
if (reversed) {
|
||||
if (sortMode == SortMode.MAX) {
|
||||
if (cmp > 0) {
|
||||
relevantVal = currentVal;
|
||||
}
|
||||
|
|
|
@ -19,18 +19,18 @@
|
|||
|
||||
package org.elasticsearch.index.fielddata.fieldcomparator;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.elasticsearch.index.fielddata.IndexNumericFieldData;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
*/
|
||||
public final class DoubleValuesComparator extends DoubleValuesComparatorBase<Double> {
|
||||
|
||||
private final double[] values;
|
||||
|
||||
public DoubleValuesComparator(IndexNumericFieldData<?> indexFieldData, double missingValue, int numHits, boolean reversed) {
|
||||
super(indexFieldData, missingValue, reversed);
|
||||
public DoubleValuesComparator(IndexNumericFieldData<?> indexFieldData, double missingValue, int numHits, SortMode sortMode) {
|
||||
super(indexFieldData, missingValue, sortMode);
|
||||
assert indexFieldData.getNumericType().requiredBits() <= 64;
|
||||
this.values = new double[numHits];
|
||||
}
|
||||
|
|
|
@ -17,25 +17,26 @@ package org.elasticsearch.index.fielddata.fieldcomparator;
|
|||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import java.io.IOException;
|
||||
|
||||
import org.apache.lucene.index.AtomicReaderContext;
|
||||
import org.apache.lucene.search.FieldComparator;
|
||||
import org.elasticsearch.index.fielddata.DoubleValues;
|
||||
import org.elasticsearch.index.fielddata.IndexNumericFieldData;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
abstract class DoubleValuesComparatorBase<T extends Number> extends FieldComparator<T> {
|
||||
|
||||
protected final IndexNumericFieldData<?>indexFieldData;
|
||||
protected final IndexNumericFieldData<?> indexFieldData;
|
||||
protected final double missingValue;
|
||||
protected double bottom;
|
||||
protected DoubleValues readerValues;
|
||||
private final boolean reversed;
|
||||
private final SortMode sortMode;
|
||||
|
||||
public DoubleValuesComparatorBase(IndexNumericFieldData<?> indexFieldData, double missingValue, boolean reversed) {
|
||||
public DoubleValuesComparatorBase(IndexNumericFieldData<?> indexFieldData, double missingValue, SortMode sortMode) {
|
||||
this.indexFieldData = indexFieldData;
|
||||
this.missingValue = missingValue;
|
||||
this.reversed = reversed;
|
||||
this.sortMode = sortMode;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -55,7 +56,7 @@ abstract class DoubleValuesComparatorBase<T extends Number> extends FieldCompara
|
|||
public final FieldComparator<T> setNextReader(AtomicReaderContext context) throws IOException {
|
||||
readerValues = indexFieldData.load(context).getDoubleValues();
|
||||
if (readerValues.isMultiValued()) {
|
||||
readerValues = new MultiValuedBytesWrapper(readerValues, reversed);
|
||||
readerValues = new MultiValuedBytesWrapper(readerValues, sortMode);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
@ -72,11 +73,11 @@ abstract class DoubleValuesComparatorBase<T extends Number> extends FieldCompara
|
|||
|
||||
static final class MultiValuedBytesWrapper extends DoubleValues.FilteredDoubleValues {
|
||||
|
||||
private final boolean reversed;
|
||||
private final SortMode sortMode;
|
||||
|
||||
public MultiValuedBytesWrapper(DoubleValues delegate, boolean reversed) {
|
||||
public MultiValuedBytesWrapper(DoubleValues delegate, SortMode sortMode) {
|
||||
super(delegate);
|
||||
this.reversed = reversed;
|
||||
this.sortMode = sortMode;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -88,23 +89,35 @@ abstract class DoubleValuesComparatorBase<T extends Number> extends FieldCompara
|
|||
|
||||
double currentVal = iter.next();
|
||||
double relevantVal = currentVal;
|
||||
while (true) {
|
||||
int cmp = Double.compare(currentVal, relevantVal);
|
||||
if (reversed) {
|
||||
if (cmp > 0) {
|
||||
relevantVal = currentVal;
|
||||
}
|
||||
} else {
|
||||
if (cmp < 0) {
|
||||
relevantVal = currentVal;
|
||||
}
|
||||
}
|
||||
if (!iter.hasNext()) {
|
||||
break;
|
||||
}
|
||||
int counter = 1;
|
||||
while (iter.hasNext()) {
|
||||
currentVal = iter.next();
|
||||
int cmp = Double.compare(currentVal, relevantVal);
|
||||
switch (sortMode) {
|
||||
case SUM:
|
||||
relevantVal += currentVal;
|
||||
break;
|
||||
case AVG:
|
||||
relevantVal += currentVal;
|
||||
counter++;
|
||||
break;
|
||||
case MIN:
|
||||
if (cmp < 0) {
|
||||
relevantVal = currentVal;
|
||||
}
|
||||
break;
|
||||
case MAX:
|
||||
if (cmp > 0) {
|
||||
relevantVal = currentVal;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (sortMode == SortMode.AVG) {
|
||||
return relevantVal / counter;
|
||||
} else {
|
||||
return relevantVal;
|
||||
}
|
||||
return relevantVal;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -33,10 +33,12 @@ public class DoubleValuesComparatorSource extends IndexFieldData.XFieldComparato
|
|||
|
||||
private final IndexNumericFieldData<?> indexFieldData;
|
||||
private final Object missingValue;
|
||||
private final SortMode sortMode;
|
||||
|
||||
public DoubleValuesComparatorSource(IndexNumericFieldData<?> indexFieldData, @Nullable Object missingValue) {
|
||||
public DoubleValuesComparatorSource(IndexNumericFieldData<?> indexFieldData, @Nullable Object missingValue, SortMode sortMode) {
|
||||
this.indexFieldData = indexFieldData;
|
||||
this.missingValue = missingValue;
|
||||
this.sortMode = sortMode;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -57,6 +59,6 @@ public class DoubleValuesComparatorSource extends IndexFieldData.XFieldComparato
|
|||
dMissingValue = missingValue instanceof Number ? ((Number) missingValue).doubleValue() : Double.parseDouble(missingValue.toString());
|
||||
}
|
||||
|
||||
return new DoubleValuesComparator(indexFieldData, dMissingValue, numHits, reversed);
|
||||
return new DoubleValuesComparator(indexFieldData, dMissingValue, numHits, sortMode);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,18 +19,18 @@
|
|||
|
||||
package org.elasticsearch.index.fielddata.fieldcomparator;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.elasticsearch.index.fielddata.IndexNumericFieldData;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
*/
|
||||
public final class FloatValuesComparator extends DoubleValuesComparatorBase<Float> {
|
||||
|
||||
private final float[] values;
|
||||
|
||||
public FloatValuesComparator(IndexNumericFieldData<?> indexFieldData, float missingValue, int numHits, boolean reversed) {
|
||||
super(indexFieldData, missingValue, reversed);
|
||||
public FloatValuesComparator(IndexNumericFieldData<?> indexFieldData, float missingValue, int numHits, SortMode sortMode) {
|
||||
super(indexFieldData, missingValue, sortMode);
|
||||
assert indexFieldData.getNumericType().requiredBits() <= 32;
|
||||
this.values = new float[numHits];
|
||||
}
|
||||
|
|
|
@ -33,10 +33,12 @@ public class FloatValuesComparatorSource extends IndexFieldData.XFieldComparator
|
|||
|
||||
private final IndexNumericFieldData<?> indexFieldData;
|
||||
private final Object missingValue;
|
||||
private final SortMode sortMode;
|
||||
|
||||
public FloatValuesComparatorSource(IndexNumericFieldData<?> indexFieldData, @Nullable Object missingValue) {
|
||||
public FloatValuesComparatorSource(IndexNumericFieldData<?> indexFieldData, @Nullable Object missingValue, SortMode sortMode) {
|
||||
this.indexFieldData = indexFieldData;
|
||||
this.missingValue = missingValue;
|
||||
this.sortMode = sortMode;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -57,6 +59,6 @@ public class FloatValuesComparatorSource extends IndexFieldData.XFieldComparator
|
|||
dMissingValue = missingValue instanceof Number ? ((Number) missingValue).floatValue() : Float.parseFloat(missingValue.toString());
|
||||
}
|
||||
|
||||
return new FloatValuesComparator(indexFieldData, dMissingValue, numHits, reversed);
|
||||
return new FloatValuesComparator(indexFieldData, dMissingValue, numHits, sortMode);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,18 +19,18 @@
|
|||
|
||||
package org.elasticsearch.index.fielddata.fieldcomparator;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.elasticsearch.index.fielddata.IndexNumericFieldData;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
*/
|
||||
public final class IntValuesComparator extends LongValuesComparatorBase<Integer> {
|
||||
|
||||
private final int[] values;
|
||||
|
||||
public IntValuesComparator(IndexNumericFieldData<?> indexFieldData, int missingValue, int numHits, boolean reversed) {
|
||||
super(indexFieldData, missingValue, reversed);
|
||||
public IntValuesComparator(IndexNumericFieldData<?> indexFieldData, int missingValue, int numHits, SortMode sortMode) {
|
||||
super(indexFieldData, missingValue, sortMode);
|
||||
assert indexFieldData.getNumericType().requiredBits() <= 32;
|
||||
this.values = new int[numHits];
|
||||
}
|
||||
|
|
|
@ -33,10 +33,12 @@ public class IntValuesComparatorSource extends IndexFieldData.XFieldComparatorSo
|
|||
|
||||
private final IndexNumericFieldData<?> indexFieldData;
|
||||
private final Object missingValue;
|
||||
private final SortMode sortMode;
|
||||
|
||||
public IntValuesComparatorSource(IndexNumericFieldData<?> indexFieldData, @Nullable Object missingValue) {
|
||||
public IntValuesComparatorSource(IndexNumericFieldData<?> indexFieldData, @Nullable Object missingValue, SortMode sortMode) {
|
||||
this.indexFieldData = indexFieldData;
|
||||
this.missingValue = missingValue;
|
||||
this.sortMode = sortMode;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -57,6 +59,6 @@ public class IntValuesComparatorSource extends IndexFieldData.XFieldComparatorSo
|
|||
dMissingValue = missingValue instanceof Number ? ((Number) missingValue).intValue() : Integer.parseInt(missingValue.toString());
|
||||
}
|
||||
|
||||
return new IntValuesComparator(indexFieldData, dMissingValue, numHits, reversed);
|
||||
return new IntValuesComparator(indexFieldData, dMissingValue, numHits, sortMode);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,18 +19,18 @@
|
|||
|
||||
package org.elasticsearch.index.fielddata.fieldcomparator;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.elasticsearch.index.fielddata.IndexNumericFieldData;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
*/
|
||||
public final class LongValuesComparator extends LongValuesComparatorBase<Long> {
|
||||
|
||||
private final long[] values;
|
||||
|
||||
public LongValuesComparator(IndexNumericFieldData<?> indexFieldData, long missingValue, int numHits, boolean reversed) {
|
||||
super(indexFieldData, missingValue, reversed);
|
||||
public LongValuesComparator(IndexNumericFieldData<?> indexFieldData, long missingValue, int numHits, SortMode sortMode) {
|
||||
super(indexFieldData, missingValue, sortMode);
|
||||
this.values = new long[numHits];
|
||||
assert indexFieldData.getNumericType().requiredBits() <= 64;
|
||||
}
|
||||
|
|
|
@ -17,26 +17,27 @@ package org.elasticsearch.index.fielddata.fieldcomparator;
|
|||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import java.io.IOException;
|
||||
|
||||
import org.apache.lucene.index.AtomicReaderContext;
|
||||
import org.apache.lucene.search.FieldComparator;
|
||||
import org.elasticsearch.index.fielddata.IndexNumericFieldData;
|
||||
import org.elasticsearch.index.fielddata.LongValues;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
abstract class LongValuesComparatorBase<T extends Number> extends FieldComparator<T> {
|
||||
|
||||
protected final IndexNumericFieldData<?> indexFieldData;
|
||||
private final boolean reversed;
|
||||
protected final long missingValue;
|
||||
protected long bottom;
|
||||
protected LongValues readerValues;
|
||||
private final SortMode sortMode;
|
||||
|
||||
|
||||
public LongValuesComparatorBase(IndexNumericFieldData<?> indexFieldData, long missingValue, boolean reversed) {
|
||||
public LongValuesComparatorBase(IndexNumericFieldData<?> indexFieldData, long missingValue, SortMode sortMode) {
|
||||
this.indexFieldData = indexFieldData;
|
||||
this.missingValue = missingValue;
|
||||
this.reversed = reversed;
|
||||
this.sortMode = sortMode;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -66,18 +67,18 @@ abstract class LongValuesComparatorBase<T extends Number> extends FieldComparato
|
|||
public final FieldComparator<T> setNextReader(AtomicReaderContext context) throws IOException {
|
||||
readerValues = indexFieldData.load(context).getLongValues();
|
||||
if (readerValues.isMultiValued()) {
|
||||
readerValues = new MultiValuedBytesWrapper(readerValues, reversed);
|
||||
readerValues = new MultiValuedBytesWrapper(readerValues, sortMode);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
private static final class MultiValuedBytesWrapper extends LongValues.FilteredLongValues {
|
||||
|
||||
private final boolean reversed;
|
||||
private final SortMode sortMode;
|
||||
|
||||
public MultiValuedBytesWrapper(LongValues delegate, boolean reversed) {
|
||||
public MultiValuedBytesWrapper(LongValues delegate, SortMode sortMode) {
|
||||
super(delegate);
|
||||
this.reversed = reversed;
|
||||
this.sortMode = sortMode;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -89,22 +90,33 @@ abstract class LongValuesComparatorBase<T extends Number> extends FieldComparato
|
|||
|
||||
long currentVal = iter.next();
|
||||
long relevantVal = currentVal;
|
||||
while (true) {
|
||||
if (reversed) {
|
||||
if (currentVal > relevantVal) {
|
||||
relevantVal = currentVal;
|
||||
}
|
||||
} else {
|
||||
if (currentVal < relevantVal) {
|
||||
relevantVal = currentVal;
|
||||
}
|
||||
}
|
||||
if (!iter.hasNext()) {
|
||||
break;
|
||||
}
|
||||
int counter = 1;
|
||||
while (iter.hasNext()) {
|
||||
currentVal = iter.next();
|
||||
switch (sortMode) {
|
||||
case SUM:
|
||||
relevantVal += currentVal;
|
||||
break;
|
||||
case AVG:
|
||||
relevantVal += currentVal;
|
||||
counter++;
|
||||
break;
|
||||
case MAX:
|
||||
if (currentVal > relevantVal) {
|
||||
relevantVal = currentVal;
|
||||
}
|
||||
break;
|
||||
case MIN:
|
||||
if (currentVal < relevantVal) {
|
||||
relevantVal = currentVal;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (sortMode == SortMode.AVG) {
|
||||
return relevantVal / counter;
|
||||
} else {
|
||||
return relevantVal;
|
||||
}
|
||||
return relevantVal;
|
||||
// If we have a method on readerValues that tells if the values emitted by Iter or ArrayRef are sorted per
|
||||
// document that we can do this or something similar:
|
||||
// (This is already possible, if values are loaded from index, but we just need a method that tells us this
|
||||
|
|
|
@ -33,10 +33,12 @@ public class LongValuesComparatorSource extends IndexFieldData.XFieldComparatorS
|
|||
|
||||
private final IndexNumericFieldData<?> indexFieldData;
|
||||
private final Object missingValue;
|
||||
private final SortMode sortMode;
|
||||
|
||||
public LongValuesComparatorSource(IndexNumericFieldData<?> indexFieldData, @Nullable Object missingValue) {
|
||||
public LongValuesComparatorSource(IndexNumericFieldData<?> indexFieldData, @Nullable Object missingValue, SortMode sortMode) {
|
||||
this.indexFieldData = indexFieldData;
|
||||
this.missingValue = missingValue;
|
||||
this.sortMode = sortMode;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -57,6 +59,6 @@ public class LongValuesComparatorSource extends IndexFieldData.XFieldComparatorS
|
|||
dMissingValue = missingValue instanceof Number ? ((Number) missingValue).longValue() : Long.parseLong(missingValue.toString());
|
||||
}
|
||||
|
||||
return new LongValuesComparator(indexFieldData, dMissingValue, numHits, reversed);
|
||||
return new LongValuesComparator(indexFieldData, dMissingValue, numHits, sortMode);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,27 +19,29 @@
|
|||
|
||||
package org.elasticsearch.index.fielddata.fieldcomparator;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.elasticsearch.index.fielddata.IndexNumericFieldData;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
*/
|
||||
public final class ShortValuesComparator extends LongValuesComparatorBase<Short> {
|
||||
|
||||
private final short[] values;
|
||||
private final SortMode sortMode;
|
||||
|
||||
public ShortValuesComparator(IndexNumericFieldData<?> indexFieldData, short missingValue, int numHits, boolean reversed) {
|
||||
super(indexFieldData, missingValue, reversed);
|
||||
public ShortValuesComparator(IndexNumericFieldData<?> indexFieldData, short missingValue, int numHits, SortMode sortMode) {
|
||||
super(indexFieldData, missingValue, sortMode);
|
||||
assert indexFieldData.getNumericType().requiredBits() <= 16;
|
||||
this.values = new short[numHits];
|
||||
this.sortMode = sortMode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compare(int slot1, int slot2) {
|
||||
final int v1 = values[slot1];
|
||||
final int v2 = values[slot2];
|
||||
return v1-v2; // we cast to int so it can't overflow
|
||||
return v1 - v2; // we cast to int so it can't overflow
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -33,10 +33,12 @@ public class ShortValuesComparatorSource extends IndexFieldData.XFieldComparator
|
|||
|
||||
private final IndexNumericFieldData<?> indexFieldData;
|
||||
private final Object missingValue;
|
||||
private final SortMode sortMode;
|
||||
|
||||
public ShortValuesComparatorSource(IndexNumericFieldData<?> indexFieldData, @Nullable Object missingValue) {
|
||||
public ShortValuesComparatorSource(IndexNumericFieldData<?> indexFieldData, @Nullable Object missingValue, SortMode sortMode) {
|
||||
this.indexFieldData = indexFieldData;
|
||||
this.missingValue = missingValue;
|
||||
this.sortMode = sortMode;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -57,6 +59,6 @@ public class ShortValuesComparatorSource extends IndexFieldData.XFieldComparator
|
|||
dMissingValue = missingValue instanceof Number ? ((Number) missingValue).shortValue() : Short.parseShort(missingValue.toString());
|
||||
}
|
||||
|
||||
return new ShortValuesComparator(indexFieldData, dMissingValue, numHits, reversed);
|
||||
return new ShortValuesComparator(indexFieldData, dMissingValue, numHits, sortMode);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
* Licensed to ElasticSearch and Shay Banon under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. ElasticSearch licenses this
|
||||
* file to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
|
||||
package org.elasticsearch.index.fielddata.fieldcomparator;
|
||||
|
||||
import org.elasticsearch.ElasticSearchIllegalArgumentException;
|
||||
|
||||
/**
|
||||
* Defines what values to pick in the case a document contains multiple values for a particular field.
|
||||
*/
|
||||
public enum SortMode {
|
||||
|
||||
/**
|
||||
* Sum of all the values.
|
||||
*/
|
||||
SUM,
|
||||
|
||||
/**
|
||||
* Average of all the values.
|
||||
*/
|
||||
AVG,
|
||||
|
||||
/**
|
||||
* Pick the lowest value.
|
||||
*/
|
||||
MIN,
|
||||
|
||||
/**
|
||||
* Pick the highest value.
|
||||
*/
|
||||
MAX;
|
||||
|
||||
public static SortMode fromString(String sortMode) {
|
||||
if ("min".equals(sortMode)) {
|
||||
return MIN;
|
||||
} else if ("max".equals(sortMode)) {
|
||||
return MAX;
|
||||
} else if ("sum".equals(sortMode)) {
|
||||
return SUM;
|
||||
} else if ("avg".equals(sortMode)) {
|
||||
return AVG;
|
||||
} else {
|
||||
throw new ElasticSearchIllegalArgumentException("Illegal sort_mode " + sortMode);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -20,9 +20,9 @@
|
|||
package org.elasticsearch.index.fielddata.plain;
|
||||
|
||||
import gnu.trove.list.array.TByteArrayList;
|
||||
import org.apache.lucene.index.*;
|
||||
import org.apache.lucene.search.FieldCache;
|
||||
import org.apache.lucene.search.FieldCache.StopFillCacheException;
|
||||
import org.apache.lucene.index.AtomicReader;
|
||||
import org.apache.lucene.index.AtomicReaderContext;
|
||||
import org.apache.lucene.index.Terms;
|
||||
import org.apache.lucene.util.BytesRef;
|
||||
import org.apache.lucene.util.BytesRefIterator;
|
||||
import org.apache.lucene.util.FixedBitSet;
|
||||
|
@ -33,14 +33,13 @@ import org.elasticsearch.common.settings.Settings;
|
|||
import org.elasticsearch.index.Index;
|
||||
import org.elasticsearch.index.fielddata.*;
|
||||
import org.elasticsearch.index.fielddata.fieldcomparator.ByteValuesComparatorSource;
|
||||
import org.elasticsearch.index.fielddata.fieldcomparator.SortMode;
|
||||
import org.elasticsearch.index.fielddata.ordinals.Ordinals;
|
||||
import org.elasticsearch.index.fielddata.ordinals.Ordinals.Docs;
|
||||
import org.elasticsearch.index.fielddata.ordinals.OrdinalsBuilder;
|
||||
import org.elasticsearch.index.mapper.FieldMapper;
|
||||
import org.elasticsearch.index.settings.IndexSettings;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
*/
|
||||
public class ByteArrayIndexFieldData extends AbstractIndexFieldData<ByteArrayAtomicFieldData> implements IndexNumericFieldData<ByteArrayAtomicFieldData> {
|
||||
|
@ -96,8 +95,8 @@ public class ByteArrayIndexFieldData extends AbstractIndexFieldData<ByteArrayAto
|
|||
OrdinalsBuilder builder = new OrdinalsBuilder(terms, reader.maxDoc());
|
||||
BytesRefIterator iter = builder.buildFromTerms(builder.wrapNumeric32Bit(terms.iterator(null)), reader.getLiveDocs());
|
||||
BytesRef term;
|
||||
while((term = iter.next()) != null) {
|
||||
values.add((byte) NumericUtils.prefixCodedToInt(term));
|
||||
while ((term = iter.next()) != null) {
|
||||
values.add((byte) NumericUtils.prefixCodedToInt(term));
|
||||
}
|
||||
try {
|
||||
Ordinals build = builder.build(fieldDataType.getSettings());
|
||||
|
@ -106,7 +105,7 @@ public class ByteArrayIndexFieldData extends AbstractIndexFieldData<ByteArrayAto
|
|||
byte[] sValues = new byte[reader.maxDoc()];
|
||||
int maxDoc = reader.maxDoc();
|
||||
for (int i = 0; i < maxDoc; i++) {
|
||||
sValues[i] = values.get(ordinals.getOrd(i));
|
||||
sValues[i] = values.get(ordinals.getOrd(i));
|
||||
}
|
||||
final FixedBitSet set = builder.buildDocsWithValuesSet();
|
||||
if (set == null) {
|
||||
|
@ -126,7 +125,7 @@ public class ByteArrayIndexFieldData extends AbstractIndexFieldData<ByteArrayAto
|
|||
}
|
||||
|
||||
@Override
|
||||
public XFieldComparatorSource comparatorSource(@Nullable Object missingValue) {
|
||||
return new ByteValuesComparatorSource(this, missingValue);
|
||||
public XFieldComparatorSource comparatorSource(@Nullable Object missingValue, SortMode sortMode) {
|
||||
return new ByteValuesComparatorSource(this, missingValue, sortMode);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,9 +19,9 @@
|
|||
|
||||
package org.elasticsearch.index.fielddata.plain;
|
||||
|
||||
import org.apache.lucene.index.*;
|
||||
import org.apache.lucene.search.FieldCache;
|
||||
import org.apache.lucene.search.FieldCache.StopFillCacheException;
|
||||
import org.apache.lucene.index.AtomicReader;
|
||||
import org.apache.lucene.index.AtomicReaderContext;
|
||||
import org.apache.lucene.index.Terms;
|
||||
import org.apache.lucene.util.BytesRef;
|
||||
import org.apache.lucene.util.BytesRefIterator;
|
||||
import org.elasticsearch.ElasticSearchException;
|
||||
|
@ -33,9 +33,8 @@ import org.elasticsearch.index.fielddata.FieldDataType;
|
|||
import org.elasticsearch.index.fielddata.IndexFieldData;
|
||||
import org.elasticsearch.index.fielddata.IndexFieldDataCache;
|
||||
import org.elasticsearch.index.fielddata.fieldcomparator.BytesRefFieldComparatorSource;
|
||||
import org.elasticsearch.index.fielddata.ordinals.Ordinals;
|
||||
import org.elasticsearch.index.fielddata.fieldcomparator.SortMode;
|
||||
import org.elasticsearch.index.fielddata.ordinals.OrdinalsBuilder;
|
||||
import org.elasticsearch.index.fielddata.ordinals.SingleArrayOrdinals;
|
||||
import org.elasticsearch.index.mapper.FieldMapper;
|
||||
import org.elasticsearch.index.settings.IndexSettings;
|
||||
|
||||
|
@ -94,7 +93,7 @@ public class ConcreteBytesRefIndexFieldData extends AbstractIndexFieldData<Concr
|
|||
try {
|
||||
BytesRefIterator iter = builder.buildFromTerms(terms.iterator(null), reader.getLiveDocs());
|
||||
BytesRef term;
|
||||
while((term = iter.next()) != null) {
|
||||
while ((term = iter.next()) != null) {
|
||||
values.add(BytesRef.deepCopyOf(term));
|
||||
}
|
||||
return new ConcreteBytesRefAtomicFieldData(values.toArray(new BytesRef[values.size()]), builder.build(fieldDataType.getSettings()));
|
||||
|
@ -104,8 +103,8 @@ public class ConcreteBytesRefIndexFieldData extends AbstractIndexFieldData<Concr
|
|||
}
|
||||
|
||||
@Override
|
||||
public XFieldComparatorSource comparatorSource(@Nullable Object missingValue) {
|
||||
public XFieldComparatorSource comparatorSource(@Nullable Object missingValue, SortMode sortMode) {
|
||||
// TODO support "missingValue" for sortMissingValue options here...
|
||||
return new BytesRefFieldComparatorSource(this);
|
||||
return new BytesRefFieldComparatorSource(this, sortMode);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,9 +20,9 @@
|
|||
package org.elasticsearch.index.fielddata.plain;
|
||||
|
||||
import gnu.trove.list.array.TDoubleArrayList;
|
||||
import org.apache.lucene.index.*;
|
||||
import org.apache.lucene.search.FieldCache;
|
||||
import org.apache.lucene.search.FieldCache.StopFillCacheException;
|
||||
import org.apache.lucene.index.AtomicReader;
|
||||
import org.apache.lucene.index.AtomicReaderContext;
|
||||
import org.apache.lucene.index.Terms;
|
||||
import org.apache.lucene.util.BytesRef;
|
||||
import org.apache.lucene.util.BytesRefIterator;
|
||||
import org.apache.lucene.util.FixedBitSet;
|
||||
|
@ -33,9 +33,10 @@ import org.elasticsearch.common.settings.Settings;
|
|||
import org.elasticsearch.index.Index;
|
||||
import org.elasticsearch.index.fielddata.*;
|
||||
import org.elasticsearch.index.fielddata.fieldcomparator.DoubleValuesComparatorSource;
|
||||
import org.elasticsearch.index.fielddata.fieldcomparator.SortMode;
|
||||
import org.elasticsearch.index.fielddata.ordinals.Ordinals;
|
||||
import org.elasticsearch.index.fielddata.ordinals.OrdinalsBuilder;
|
||||
import org.elasticsearch.index.fielddata.ordinals.Ordinals.Docs;
|
||||
import org.elasticsearch.index.fielddata.ordinals.OrdinalsBuilder;
|
||||
import org.elasticsearch.index.mapper.FieldMapper;
|
||||
import org.elasticsearch.index.settings.IndexSettings;
|
||||
|
||||
|
@ -96,7 +97,7 @@ public class DoubleArrayIndexFieldData extends AbstractIndexFieldData<DoubleArra
|
|||
try {
|
||||
final BytesRefIterator iter = builder.buildFromTerms(builder.wrapNumeric64Bit(terms.iterator(null)), reader.getLiveDocs());
|
||||
BytesRef term;
|
||||
while((term = iter.next()) != null) {
|
||||
while ((term = iter.next()) != null) {
|
||||
values.add(NumericUtils.sortableLongToDouble(NumericUtils.prefixCodedToLong(term)));
|
||||
}
|
||||
Ordinals build = builder.build(fieldDataType.getSettings());
|
||||
|
@ -105,7 +106,7 @@ public class DoubleArrayIndexFieldData extends AbstractIndexFieldData<DoubleArra
|
|||
double[] sValues = new double[reader.maxDoc()];
|
||||
int maxDoc = reader.maxDoc();
|
||||
for (int i = 0; i < maxDoc; i++) {
|
||||
sValues[i] = values.get(ordinals.getOrd(i));
|
||||
sValues[i] = values.get(ordinals.getOrd(i));
|
||||
}
|
||||
final FixedBitSet set = builder.buildDocsWithValuesSet();
|
||||
if (set == null) {
|
||||
|
@ -126,7 +127,7 @@ public class DoubleArrayIndexFieldData extends AbstractIndexFieldData<DoubleArra
|
|||
}
|
||||
|
||||
@Override
|
||||
public XFieldComparatorSource comparatorSource(@Nullable Object missingValue) {
|
||||
return new DoubleValuesComparatorSource(this, missingValue);
|
||||
public XFieldComparatorSource comparatorSource(@Nullable Object missingValue, SortMode sortMode) {
|
||||
return new DoubleValuesComparatorSource(this, missingValue, sortMode);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,9 +20,9 @@
|
|||
package org.elasticsearch.index.fielddata.plain;
|
||||
|
||||
import gnu.trove.list.array.TFloatArrayList;
|
||||
import org.apache.lucene.index.*;
|
||||
import org.apache.lucene.search.FieldCache;
|
||||
import org.apache.lucene.search.FieldCache.StopFillCacheException;
|
||||
import org.apache.lucene.index.AtomicReader;
|
||||
import org.apache.lucene.index.AtomicReaderContext;
|
||||
import org.apache.lucene.index.Terms;
|
||||
import org.apache.lucene.util.BytesRef;
|
||||
import org.apache.lucene.util.BytesRefIterator;
|
||||
import org.apache.lucene.util.FixedBitSet;
|
||||
|
@ -33,9 +33,10 @@ import org.elasticsearch.common.settings.Settings;
|
|||
import org.elasticsearch.index.Index;
|
||||
import org.elasticsearch.index.fielddata.*;
|
||||
import org.elasticsearch.index.fielddata.fieldcomparator.FloatValuesComparatorSource;
|
||||
import org.elasticsearch.index.fielddata.fieldcomparator.SortMode;
|
||||
import org.elasticsearch.index.fielddata.ordinals.Ordinals;
|
||||
import org.elasticsearch.index.fielddata.ordinals.OrdinalsBuilder;
|
||||
import org.elasticsearch.index.fielddata.ordinals.Ordinals.Docs;
|
||||
import org.elasticsearch.index.fielddata.ordinals.OrdinalsBuilder;
|
||||
import org.elasticsearch.index.mapper.FieldMapper;
|
||||
import org.elasticsearch.index.settings.IndexSettings;
|
||||
|
||||
|
@ -96,7 +97,7 @@ public class FloatArrayIndexFieldData extends AbstractIndexFieldData<FloatArrayA
|
|||
try {
|
||||
BytesRefIterator iter = builder.buildFromTerms(builder.wrapNumeric32Bit(terms.iterator(null)), reader.getLiveDocs());
|
||||
BytesRef term;
|
||||
while((term = iter.next()) != null) {
|
||||
while ((term = iter.next()) != null) {
|
||||
values.add(NumericUtils.sortableIntToFloat(NumericUtils.prefixCodedToInt(term)));
|
||||
}
|
||||
Ordinals build = builder.build(fieldDataType.getSettings());
|
||||
|
@ -105,7 +106,7 @@ public class FloatArrayIndexFieldData extends AbstractIndexFieldData<FloatArrayA
|
|||
float[] sValues = new float[reader.maxDoc()];
|
||||
int maxDoc = reader.maxDoc();
|
||||
for (int i = 0; i < maxDoc; i++) {
|
||||
sValues[i] = values.get(ordinals.getOrd(i));
|
||||
sValues[i] = values.get(ordinals.getOrd(i));
|
||||
}
|
||||
final FixedBitSet set = builder.buildDocsWithValuesSet();
|
||||
if (set == null) {
|
||||
|
@ -126,7 +127,7 @@ public class FloatArrayIndexFieldData extends AbstractIndexFieldData<FloatArrayA
|
|||
}
|
||||
|
||||
@Override
|
||||
public XFieldComparatorSource comparatorSource(@Nullable Object missingValue) {
|
||||
return new FloatValuesComparatorSource(this, missingValue);
|
||||
public XFieldComparatorSource comparatorSource(@Nullable Object missingValue, SortMode sortMode) {
|
||||
return new FloatValuesComparatorSource(this, missingValue, sortMode);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,23 +20,20 @@
|
|||
package org.elasticsearch.index.fielddata.plain;
|
||||
|
||||
import gnu.trove.list.array.TDoubleArrayList;
|
||||
import org.apache.lucene.index.*;
|
||||
import org.apache.lucene.search.FieldCache;
|
||||
import org.apache.lucene.search.FieldCache.StopFillCacheException;
|
||||
import org.apache.lucene.util.BytesRef;
|
||||
import org.apache.lucene.util.BytesRefIterator;
|
||||
import org.apache.lucene.util.CharsRef;
|
||||
import org.apache.lucene.util.FixedBitSet;
|
||||
import org.apache.lucene.util.UnicodeUtil;
|
||||
import org.apache.lucene.index.AtomicReader;
|
||||
import org.apache.lucene.index.AtomicReaderContext;
|
||||
import org.apache.lucene.index.Terms;
|
||||
import org.apache.lucene.util.*;
|
||||
import org.elasticsearch.ElasticSearchException;
|
||||
import org.elasticsearch.ElasticSearchIllegalArgumentException;
|
||||
import org.elasticsearch.common.Nullable;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.index.Index;
|
||||
import org.elasticsearch.index.fielddata.*;
|
||||
import org.elasticsearch.index.fielddata.fieldcomparator.SortMode;
|
||||
import org.elasticsearch.index.fielddata.ordinals.Ordinals;
|
||||
import org.elasticsearch.index.fielddata.ordinals.OrdinalsBuilder;
|
||||
import org.elasticsearch.index.fielddata.ordinals.Ordinals.Docs;
|
||||
import org.elasticsearch.index.fielddata.ordinals.OrdinalsBuilder;
|
||||
import org.elasticsearch.index.mapper.FieldMapper;
|
||||
import org.elasticsearch.index.settings.IndexSettings;
|
||||
|
||||
|
@ -94,13 +91,13 @@ public class GeoPointDoubleArrayIndexFieldData extends AbstractIndexFieldData<Ge
|
|||
try {
|
||||
BytesRefIterator iter = builder.buildFromTerms(terms.iterator(null), reader.getLiveDocs());
|
||||
BytesRef term;
|
||||
while((term = iter.next()) != null) {
|
||||
while ((term = iter.next()) != null) {
|
||||
UnicodeUtil.UTF8toUTF16(term, spare);
|
||||
boolean parsed = false;
|
||||
for (int i = spare.offset; i < spare.length; i++) {
|
||||
if (spare.chars[i] == ',') { // safes a string creation
|
||||
lat.add(Double.parseDouble(new String(spare.chars, spare.offset, (i - spare.offset))));
|
||||
lon.add(Double.parseDouble(new String(spare.chars, (spare.offset + (i+1)), spare.length - ((i + 1) - spare.offset))));
|
||||
lon.add(Double.parseDouble(new String(spare.chars, (spare.offset + (i + 1)), spare.length - ((i + 1) - spare.offset))));
|
||||
parsed = true;
|
||||
break;
|
||||
}
|
||||
|
@ -137,7 +134,7 @@ public class GeoPointDoubleArrayIndexFieldData extends AbstractIndexFieldData<Ge
|
|||
}
|
||||
|
||||
@Override
|
||||
public XFieldComparatorSource comparatorSource(@Nullable Object missingValue) {
|
||||
public XFieldComparatorSource comparatorSource(@Nullable Object missingValue, SortMode sortMode) {
|
||||
throw new ElasticSearchIllegalArgumentException("can't sort on geo_point field without using specific sorting feature, like geo_distance");
|
||||
}
|
||||
}
|
|
@ -20,9 +20,9 @@
|
|||
package org.elasticsearch.index.fielddata.plain;
|
||||
|
||||
import gnu.trove.list.array.TIntArrayList;
|
||||
import org.apache.lucene.index.*;
|
||||
import org.apache.lucene.search.FieldCache;
|
||||
import org.apache.lucene.search.FieldCache.StopFillCacheException;
|
||||
import org.apache.lucene.index.AtomicReader;
|
||||
import org.apache.lucene.index.AtomicReaderContext;
|
||||
import org.apache.lucene.index.Terms;
|
||||
import org.apache.lucene.util.BytesRef;
|
||||
import org.apache.lucene.util.BytesRefIterator;
|
||||
import org.apache.lucene.util.FixedBitSet;
|
||||
|
@ -33,9 +33,10 @@ import org.elasticsearch.common.settings.Settings;
|
|||
import org.elasticsearch.index.Index;
|
||||
import org.elasticsearch.index.fielddata.*;
|
||||
import org.elasticsearch.index.fielddata.fieldcomparator.IntValuesComparatorSource;
|
||||
import org.elasticsearch.index.fielddata.fieldcomparator.SortMode;
|
||||
import org.elasticsearch.index.fielddata.ordinals.Ordinals;
|
||||
import org.elasticsearch.index.fielddata.ordinals.OrdinalsBuilder;
|
||||
import org.elasticsearch.index.fielddata.ordinals.Ordinals.Docs;
|
||||
import org.elasticsearch.index.fielddata.ordinals.OrdinalsBuilder;
|
||||
import org.elasticsearch.index.mapper.FieldMapper;
|
||||
import org.elasticsearch.index.settings.IndexSettings;
|
||||
|
||||
|
@ -95,7 +96,7 @@ public class IntArrayIndexFieldData extends AbstractIndexFieldData<IntArrayAtomi
|
|||
try {
|
||||
BytesRefIterator iter = builder.buildFromTerms(builder.wrapNumeric32Bit(terms.iterator(null)), reader.getLiveDocs());
|
||||
BytesRef term;
|
||||
while((term = iter.next()) != null) {
|
||||
while ((term = iter.next()) != null) {
|
||||
values.add(NumericUtils.prefixCodedToInt(term));
|
||||
}
|
||||
Ordinals build = builder.build(fieldDataType.getSettings());
|
||||
|
@ -104,7 +105,7 @@ public class IntArrayIndexFieldData extends AbstractIndexFieldData<IntArrayAtomi
|
|||
int[] sValues = new int[reader.maxDoc()];
|
||||
int maxDoc = reader.maxDoc();
|
||||
for (int i = 0; i < maxDoc; i++) {
|
||||
sValues[i] = values.get(ordinals.getOrd(i));
|
||||
sValues[i] = values.get(ordinals.getOrd(i));
|
||||
}
|
||||
final FixedBitSet set = builder.buildDocsWithValuesSet();
|
||||
if (set == null) {
|
||||
|
@ -124,7 +125,7 @@ public class IntArrayIndexFieldData extends AbstractIndexFieldData<IntArrayAtomi
|
|||
}
|
||||
|
||||
@Override
|
||||
public XFieldComparatorSource comparatorSource(@Nullable Object missingValue) {
|
||||
return new IntValuesComparatorSource(this, missingValue);
|
||||
public XFieldComparatorSource comparatorSource(@Nullable Object missingValue, SortMode sortMode) {
|
||||
return new IntValuesComparatorSource(this, missingValue, sortMode);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,9 +20,9 @@
|
|||
package org.elasticsearch.index.fielddata.plain;
|
||||
|
||||
import gnu.trove.list.array.TLongArrayList;
|
||||
import org.apache.lucene.index.*;
|
||||
import org.apache.lucene.search.FieldCache;
|
||||
import org.apache.lucene.search.FieldCache.StopFillCacheException;
|
||||
import org.apache.lucene.index.AtomicReader;
|
||||
import org.apache.lucene.index.AtomicReaderContext;
|
||||
import org.apache.lucene.index.Terms;
|
||||
import org.apache.lucene.util.BytesRef;
|
||||
import org.apache.lucene.util.BytesRefIterator;
|
||||
import org.apache.lucene.util.FixedBitSet;
|
||||
|
@ -33,9 +33,10 @@ import org.elasticsearch.common.settings.Settings;
|
|||
import org.elasticsearch.index.Index;
|
||||
import org.elasticsearch.index.fielddata.*;
|
||||
import org.elasticsearch.index.fielddata.fieldcomparator.LongValuesComparatorSource;
|
||||
import org.elasticsearch.index.fielddata.fieldcomparator.SortMode;
|
||||
import org.elasticsearch.index.fielddata.ordinals.Ordinals;
|
||||
import org.elasticsearch.index.fielddata.ordinals.OrdinalsBuilder;
|
||||
import org.elasticsearch.index.fielddata.ordinals.Ordinals.Docs;
|
||||
import org.elasticsearch.index.fielddata.ordinals.OrdinalsBuilder;
|
||||
import org.elasticsearch.index.mapper.FieldMapper;
|
||||
import org.elasticsearch.index.settings.IndexSettings;
|
||||
|
||||
|
@ -93,8 +94,9 @@ public class LongArrayIndexFieldData extends AbstractIndexFieldData<LongArrayAto
|
|||
values.add(0); // first "t" indicates null value
|
||||
OrdinalsBuilder builder = new OrdinalsBuilder(terms, reader.maxDoc());
|
||||
try {
|
||||
BytesRefIterator iter = builder.buildFromTerms(builder.wrapNumeric64Bit(terms.iterator(null)), reader.getLiveDocs()); BytesRef term;
|
||||
while((term = iter.next()) != null) {
|
||||
BytesRefIterator iter = builder.buildFromTerms(builder.wrapNumeric64Bit(terms.iterator(null)), reader.getLiveDocs());
|
||||
BytesRef term;
|
||||
while ((term = iter.next()) != null) {
|
||||
values.add(NumericUtils.prefixCodedToLong(term));
|
||||
}
|
||||
Ordinals build = builder.build(fieldDataType.getSettings());
|
||||
|
@ -103,7 +105,7 @@ public class LongArrayIndexFieldData extends AbstractIndexFieldData<LongArrayAto
|
|||
long[] sValues = new long[reader.maxDoc()];
|
||||
int maxDoc = reader.maxDoc();
|
||||
for (int i = 0; i < maxDoc; i++) {
|
||||
sValues[i] = values.get(ordinals.getOrd(i));
|
||||
sValues[i] = values.get(ordinals.getOrd(i));
|
||||
}
|
||||
final FixedBitSet set = builder.buildDocsWithValuesSet();
|
||||
if (set == null) {
|
||||
|
@ -124,7 +126,7 @@ public class LongArrayIndexFieldData extends AbstractIndexFieldData<LongArrayAto
|
|||
}
|
||||
|
||||
@Override
|
||||
public XFieldComparatorSource comparatorSource(@Nullable Object missingValue) {
|
||||
return new LongValuesComparatorSource(this, missingValue);
|
||||
public XFieldComparatorSource comparatorSource(@Nullable Object missingValue, SortMode sortMode) {
|
||||
return new LongValuesComparatorSource(this, missingValue, sortMode);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,6 +34,7 @@ import org.elasticsearch.index.fielddata.FieldDataType;
|
|||
import org.elasticsearch.index.fielddata.IndexFieldData;
|
||||
import org.elasticsearch.index.fielddata.IndexFieldDataCache;
|
||||
import org.elasticsearch.index.fielddata.fieldcomparator.BytesRefFieldComparatorSource;
|
||||
import org.elasticsearch.index.fielddata.fieldcomparator.SortMode;
|
||||
import org.elasticsearch.index.fielddata.ordinals.Ordinals;
|
||||
import org.elasticsearch.index.fielddata.ordinals.OrdinalsBuilder;
|
||||
import org.elasticsearch.index.mapper.FieldMapper;
|
||||
|
@ -152,8 +153,8 @@ public class PagedBytesIndexFieldData extends AbstractIndexFieldData<PagedBytesA
|
|||
}
|
||||
|
||||
@Override
|
||||
public XFieldComparatorSource comparatorSource(@Nullable Object missingValue) {
|
||||
public XFieldComparatorSource comparatorSource(@Nullable Object missingValue, SortMode sortMode) {
|
||||
// TODO support "missingValue" for sortMissingValue options here...
|
||||
return new BytesRefFieldComparatorSource(this);
|
||||
return new BytesRefFieldComparatorSource(this, sortMode);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,9 +20,9 @@
|
|||
package org.elasticsearch.index.fielddata.plain;
|
||||
|
||||
import gnu.trove.list.array.TShortArrayList;
|
||||
import org.apache.lucene.index.*;
|
||||
import org.apache.lucene.search.FieldCache;
|
||||
import org.apache.lucene.search.FieldCache.StopFillCacheException;
|
||||
import org.apache.lucene.index.AtomicReader;
|
||||
import org.apache.lucene.index.AtomicReaderContext;
|
||||
import org.apache.lucene.index.Terms;
|
||||
import org.apache.lucene.util.BytesRef;
|
||||
import org.apache.lucene.util.BytesRefIterator;
|
||||
import org.apache.lucene.util.FixedBitSet;
|
||||
|
@ -33,9 +33,10 @@ import org.elasticsearch.common.settings.Settings;
|
|||
import org.elasticsearch.index.Index;
|
||||
import org.elasticsearch.index.fielddata.*;
|
||||
import org.elasticsearch.index.fielddata.fieldcomparator.ShortValuesComparatorSource;
|
||||
import org.elasticsearch.index.fielddata.fieldcomparator.SortMode;
|
||||
import org.elasticsearch.index.fielddata.ordinals.Ordinals;
|
||||
import org.elasticsearch.index.fielddata.ordinals.OrdinalsBuilder;
|
||||
import org.elasticsearch.index.fielddata.ordinals.Ordinals.Docs;
|
||||
import org.elasticsearch.index.fielddata.ordinals.OrdinalsBuilder;
|
||||
import org.elasticsearch.index.mapper.FieldMapper;
|
||||
import org.elasticsearch.index.settings.IndexSettings;
|
||||
|
||||
|
@ -95,7 +96,7 @@ public class ShortArrayIndexFieldData extends AbstractIndexFieldData<ShortArrayA
|
|||
try {
|
||||
BytesRefIterator iter = builder.buildFromTerms(builder.wrapNumeric32Bit(terms.iterator(null)), reader.getLiveDocs());
|
||||
BytesRef term;
|
||||
while((term = iter.next()) != null) {
|
||||
while ((term = iter.next()) != null) {
|
||||
values.add((short) NumericUtils.prefixCodedToInt(term));
|
||||
}
|
||||
|
||||
|
@ -105,7 +106,7 @@ public class ShortArrayIndexFieldData extends AbstractIndexFieldData<ShortArrayA
|
|||
short[] sValues = new short[reader.maxDoc()];
|
||||
int maxDoc = reader.maxDoc();
|
||||
for (int i = 0; i < maxDoc; i++) {
|
||||
sValues[i] = values.get(ordinals.getOrd(i));
|
||||
sValues[i] = values.get(ordinals.getOrd(i));
|
||||
}
|
||||
final FixedBitSet set = builder.buildDocsWithValuesSet();
|
||||
if (set == null) {
|
||||
|
@ -125,7 +126,7 @@ public class ShortArrayIndexFieldData extends AbstractIndexFieldData<ShortArrayA
|
|||
}
|
||||
|
||||
@Override
|
||||
public XFieldComparatorSource comparatorSource(@Nullable Object missingValue) {
|
||||
return new ShortValuesComparatorSource(this, missingValue);
|
||||
public XFieldComparatorSource comparatorSource(@Nullable Object missingValue, SortMode sortMode) {
|
||||
return new ShortValuesComparatorSource(this, missingValue, sortMode);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -36,6 +36,8 @@ public class FieldSortBuilder extends SortBuilder {
|
|||
|
||||
private Boolean ignoreUnampped;
|
||||
|
||||
private String sortMode;
|
||||
|
||||
/**
|
||||
* Constructs a new sort based on a document field.
|
||||
*
|
||||
|
@ -73,6 +75,17 @@ public class FieldSortBuilder extends SortBuilder {
|
|||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines what values to pick in the case a document contains multiple values for the targeted sort field.
|
||||
* Possible values: min, max, sum and avg
|
||||
* <p/>
|
||||
* The last two values are only applicable for number based fields.
|
||||
*/
|
||||
public FieldSortBuilder sortMode(String sortMode) {
|
||||
this.sortMode = sortMode;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
|
||||
builder.startObject(fieldName);
|
||||
|
@ -85,6 +98,9 @@ public class FieldSortBuilder extends SortBuilder {
|
|||
if (ignoreUnampped != null) {
|
||||
builder.field("ignore_unmapped", ignoreUnampped);
|
||||
}
|
||||
if (sortMode != null) {
|
||||
builder.field("sort_mode", sortMode);
|
||||
}
|
||||
builder.endObject();
|
||||
return builder;
|
||||
}
|
||||
|
|
|
@ -25,7 +25,9 @@ import org.apache.lucene.search.Sort;
|
|||
import org.apache.lucene.search.SortField;
|
||||
import org.elasticsearch.common.Nullable;
|
||||
import org.elasticsearch.common.xcontent.XContentParser;
|
||||
import org.elasticsearch.index.fielddata.fieldcomparator.SortMode;
|
||||
import org.elasticsearch.index.mapper.FieldMapper;
|
||||
import org.elasticsearch.index.mapper.core.NumberFieldMapper;
|
||||
import org.elasticsearch.search.SearchParseElement;
|
||||
import org.elasticsearch.search.SearchParseException;
|
||||
import org.elasticsearch.search.internal.SearchContext;
|
||||
|
@ -69,7 +71,7 @@ public class SortParseElement implements SearchParseElement {
|
|||
if (token == XContentParser.Token.START_OBJECT) {
|
||||
addCompoundSortField(parser, context, sortFields);
|
||||
} else if (token == XContentParser.Token.VALUE_STRING) {
|
||||
addSortField(context, sortFields, parser.text(), false, false, null);
|
||||
addSortField(context, sortFields, parser.text(), false, false, null, null);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -103,6 +105,7 @@ public class SortParseElement implements SearchParseElement {
|
|||
String missing = null;
|
||||
String innerJsonName = null;
|
||||
boolean ignoreUnmapped = false;
|
||||
SortMode sortMode = null;
|
||||
token = parser.nextToken();
|
||||
if (token == XContentParser.Token.VALUE_STRING) {
|
||||
String direction = parser.text();
|
||||
|
@ -111,7 +114,7 @@ public class SortParseElement implements SearchParseElement {
|
|||
} else if (direction.equals("desc")) {
|
||||
reverse = !SCORE_FIELD_NAME.equals(fieldName);
|
||||
}
|
||||
addSortField(context, sortFields, fieldName, reverse, ignoreUnmapped, missing);
|
||||
addSortField(context, sortFields, fieldName, reverse, ignoreUnmapped, missing, sortMode);
|
||||
} else {
|
||||
if (parsers.containsKey(fieldName)) {
|
||||
sortFields.add(parsers.get(fieldName).parse(parser, context));
|
||||
|
@ -132,17 +135,19 @@ public class SortParseElement implements SearchParseElement {
|
|||
missing = parser.textOrNull();
|
||||
} else if ("ignore_unmapped".equals(innerJsonName) || "ignoreUnmapped".equals(innerJsonName)) {
|
||||
ignoreUnmapped = parser.booleanValue();
|
||||
} else if ("sort_mode".equals(innerJsonName) || "sortMode".equals(innerJsonName)) {
|
||||
sortMode = SortMode.fromString(parser.text());
|
||||
}
|
||||
}
|
||||
}
|
||||
addSortField(context, sortFields, fieldName, reverse, ignoreUnmapped, missing);
|
||||
addSortField(context, sortFields, fieldName, reverse, ignoreUnmapped, missing, sortMode);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void addSortField(SearchContext context, List<SortField> sortFields, String fieldName, boolean reverse, boolean ignoreUnmapped, @Nullable final String missing) {
|
||||
private void addSortField(SearchContext context, List<SortField> sortFields, String fieldName, boolean reverse, boolean ignoreUnmapped, @Nullable final String missing, SortMode sortMode) {
|
||||
if (SCORE_FIELD_NAME.equals(fieldName)) {
|
||||
if (reverse) {
|
||||
sortFields.add(SORT_SCORE_REVERSE);
|
||||
|
@ -173,7 +178,14 @@ public class SortParseElement implements SearchParseElement {
|
|||
}
|
||||
}*/
|
||||
|
||||
sortFields.add(new SortField(fieldMapper.names().indexName(), context.fieldData().getForField(fieldMapper).comparatorSource(missing), reverse));
|
||||
// We only support AVG and SUM on number based fields
|
||||
if (!(fieldMapper instanceof NumberFieldMapper) && (sortMode == SortMode.SUM || sortMode == SortMode.AVG)) {
|
||||
sortMode = null;
|
||||
}
|
||||
if (sortMode == null) {
|
||||
sortMode = reverse ? SortMode.MAX : SortMode.MIN;
|
||||
}
|
||||
sortFields.add(new SortField(fieldMapper.names().indexName(), context.fieldData().getForField(fieldMapper).comparatorSource(missing, sortMode), reverse));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -693,6 +693,24 @@ public class SimpleSortTests extends AbstractNodesTests {
|
|||
assertThat(searchResponse.hits().getAt(2).id(), equalTo(Integer.toString(3)));
|
||||
assertThat(((Number) searchResponse.hits().getAt(2).sortValues()[0]).longValue(), equalTo(3l));
|
||||
|
||||
searchResponse = client.prepareSearch()
|
||||
.setQuery(matchAllQuery())
|
||||
.setSize(10)
|
||||
.addSort(SortBuilders.fieldSort("long_values").order(SortOrder.DESC).sortMode("sum"))
|
||||
.execute().actionGet();
|
||||
|
||||
assertThat(searchResponse.hits().getTotalHits(), equalTo(3l));
|
||||
assertThat(searchResponse.hits().hits().length, equalTo(3));
|
||||
|
||||
assertThat(searchResponse.hits().getAt(0).id(), equalTo(Integer.toString(2)));
|
||||
assertThat(((Number) searchResponse.hits().getAt(0).sortValues()[0]).longValue(), equalTo(53l));
|
||||
|
||||
assertThat(searchResponse.hits().getAt(1).id(), equalTo(Integer.toString(1)));
|
||||
assertThat(((Number) searchResponse.hits().getAt(1).sortValues()[0]).longValue(), equalTo(24l));
|
||||
|
||||
assertThat(searchResponse.hits().getAt(2).id(), equalTo(Integer.toString(3)));
|
||||
assertThat(((Number) searchResponse.hits().getAt(2).sortValues()[0]).longValue(), equalTo(2l));
|
||||
|
||||
searchResponse = client.prepareSearch()
|
||||
.setQuery(matchAllQuery())
|
||||
.setSize(10)
|
||||
|
|
|
@ -25,7 +25,9 @@ import org.apache.lucene.document.StringField;
|
|||
import org.apache.lucene.index.DirectoryReader;
|
||||
import org.apache.lucene.search.*;
|
||||
import org.elasticsearch.index.fielddata.*;
|
||||
import org.elasticsearch.index.fielddata.util.*;
|
||||
import org.elasticsearch.index.fielddata.fieldcomparator.SortMode;
|
||||
import org.elasticsearch.index.fielddata.util.DoubleArrayRef;
|
||||
import org.elasticsearch.index.fielddata.util.LongArrayRef;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
|
@ -144,14 +146,14 @@ public abstract class NumericFieldDataTests extends StringFieldDataTests {
|
|||
TopFieldDocs topDocs;
|
||||
|
||||
topDocs = searcher.search(new MatchAllDocsQuery(), 10,
|
||||
new Sort(new SortField("value", indexFieldData.comparatorSource(null))));
|
||||
new Sort(new SortField("value", indexFieldData.comparatorSource(null, SortMode.MIN))));
|
||||
assertThat(topDocs.totalHits, equalTo(3));
|
||||
assertThat(topDocs.scoreDocs[0].doc, equalTo(1));
|
||||
assertThat(topDocs.scoreDocs[1].doc, equalTo(0));
|
||||
assertThat(topDocs.scoreDocs[2].doc, equalTo(2));
|
||||
|
||||
topDocs = searcher.search(new MatchAllDocsQuery(), 10,
|
||||
new Sort(new SortField("value", indexFieldData.comparatorSource(null), true)));
|
||||
new Sort(new SortField("value", indexFieldData.comparatorSource(null, SortMode.MAX), true)));
|
||||
assertThat(topDocs.totalHits, equalTo(3));
|
||||
assertThat(topDocs.scoreDocs[0].doc, equalTo(2));
|
||||
assertThat(topDocs.scoreDocs[1].doc, equalTo(0));
|
||||
|
@ -256,42 +258,42 @@ public abstract class NumericFieldDataTests extends StringFieldDataTests {
|
|||
TopFieldDocs topDocs;
|
||||
|
||||
topDocs = searcher.search(new MatchAllDocsQuery(), 10,
|
||||
new Sort(new SortField("value", indexFieldData.comparatorSource(null)))); // defaults to _last
|
||||
new Sort(new SortField("value", indexFieldData.comparatorSource(null, SortMode.MIN)))); // defaults to _last
|
||||
assertThat(topDocs.totalHits, equalTo(3));
|
||||
assertThat(topDocs.scoreDocs[0].doc, equalTo(0));
|
||||
assertThat(topDocs.scoreDocs[1].doc, equalTo(2));
|
||||
assertThat(topDocs.scoreDocs[2].doc, equalTo(1));
|
||||
|
||||
topDocs = searcher.search(new MatchAllDocsQuery(), 10,
|
||||
new Sort(new SortField("value", indexFieldData.comparatorSource(null), true))); // defaults to _last
|
||||
new Sort(new SortField("value", indexFieldData.comparatorSource(null, SortMode.MAX), true))); // defaults to _last
|
||||
assertThat(topDocs.totalHits, equalTo(3));
|
||||
assertThat(topDocs.scoreDocs[0].doc, equalTo(2));
|
||||
assertThat(topDocs.scoreDocs[1].doc, equalTo(0));
|
||||
assertThat(topDocs.scoreDocs[2].doc, equalTo(1));
|
||||
|
||||
topDocs = searcher.search(new MatchAllDocsQuery(), 10,
|
||||
new Sort(new SortField("value", indexFieldData.comparatorSource("_first"))));
|
||||
new Sort(new SortField("value", indexFieldData.comparatorSource("_first", SortMode.MIN))));
|
||||
assertThat(topDocs.totalHits, equalTo(3));
|
||||
assertThat(topDocs.scoreDocs[0].doc, equalTo(1));
|
||||
assertThat(topDocs.scoreDocs[1].doc, equalTo(0));
|
||||
assertThat(topDocs.scoreDocs[2].doc, equalTo(2));
|
||||
|
||||
topDocs = searcher.search(new MatchAllDocsQuery(), 10,
|
||||
new Sort(new SortField("value", indexFieldData.comparatorSource("_first"), true)));
|
||||
new Sort(new SortField("value", indexFieldData.comparatorSource("_first", SortMode.MAX), true)));
|
||||
assertThat(topDocs.totalHits, equalTo(3));
|
||||
assertThat(topDocs.scoreDocs[0].doc, equalTo(1));
|
||||
assertThat(topDocs.scoreDocs[1].doc, equalTo(2));
|
||||
assertThat(topDocs.scoreDocs[2].doc, equalTo(0));
|
||||
|
||||
topDocs = searcher.search(new MatchAllDocsQuery(), 10,
|
||||
new Sort(new SortField("value", indexFieldData.comparatorSource("1"))));
|
||||
new Sort(new SortField("value", indexFieldData.comparatorSource("1", SortMode.MIN))));
|
||||
assertThat(topDocs.totalHits, equalTo(3));
|
||||
assertThat(topDocs.scoreDocs[0].doc, equalTo(1));
|
||||
assertThat(topDocs.scoreDocs[1].doc, equalTo(0));
|
||||
assertThat(topDocs.scoreDocs[2].doc, equalTo(2));
|
||||
|
||||
topDocs = searcher.search(new MatchAllDocsQuery(), 10,
|
||||
new Sort(new SortField("value", indexFieldData.comparatorSource("1"), true)));
|
||||
new Sort(new SortField("value", indexFieldData.comparatorSource("1", SortMode.MAX), true)));
|
||||
assertThat(topDocs.totalHits, equalTo(3));
|
||||
assertThat(topDocs.scoreDocs[0].doc, equalTo(2));
|
||||
assertThat(topDocs.scoreDocs[1].doc, equalTo(0));
|
||||
|
@ -610,7 +612,7 @@ public abstract class NumericFieldDataTests extends StringFieldDataTests {
|
|||
|
||||
IndexSearcher searcher = new IndexSearcher(DirectoryReader.open(writer, true));
|
||||
TopFieldDocs topDocs = searcher.search(new MatchAllDocsQuery(), 10,
|
||||
new Sort(new SortField("value", indexFieldData.comparatorSource(null)))); // defaults to _last
|
||||
new Sort(new SortField("value", indexFieldData.comparatorSource(null, SortMode.MIN)))); // defaults to _last
|
||||
assertThat(topDocs.totalHits, equalTo(8));
|
||||
assertThat(topDocs.scoreDocs.length, equalTo(8));
|
||||
assertThat(topDocs.scoreDocs[0].doc, equalTo(7));
|
||||
|
@ -631,7 +633,7 @@ public abstract class NumericFieldDataTests extends StringFieldDataTests {
|
|||
// assertThat(((FieldDoc) topDocs.scoreDocs[7]).fields[0], equalTo(null));
|
||||
|
||||
topDocs = searcher.search(new MatchAllDocsQuery(), 10,
|
||||
new Sort(new SortField("value", indexFieldData.comparatorSource(null), true))); // defaults to _last
|
||||
new Sort(new SortField("value", indexFieldData.comparatorSource(null, SortMode.MAX), true))); // defaults to _last
|
||||
assertThat(topDocs.totalHits, equalTo(8));
|
||||
assertThat(topDocs.scoreDocs.length, equalTo(8));
|
||||
assertThat(topDocs.scoreDocs[0].doc, equalTo(6));
|
||||
|
@ -651,8 +653,96 @@ public abstract class NumericFieldDataTests extends StringFieldDataTests {
|
|||
assertThat(topDocs.scoreDocs[7].doc, equalTo(5));
|
||||
// assertThat(((FieldDoc) topDocs.scoreDocs[7]).fields[0], equalTo(null));
|
||||
|
||||
searcher = new IndexSearcher(DirectoryReader.open(writer, true));
|
||||
topDocs = searcher.search(new MatchAllDocsQuery(), 10,
|
||||
new Sort(new SortField("value", indexFieldData.comparatorSource("_first"))));
|
||||
new Sort(new SortField("value", indexFieldData.comparatorSource(null, SortMode.SUM)))); // defaults to _last
|
||||
assertThat(topDocs.totalHits, equalTo(8));
|
||||
assertThat(topDocs.scoreDocs.length, equalTo(8));
|
||||
assertThat(topDocs.scoreDocs[0].doc, equalTo(7));
|
||||
assertThat(((Number) ((FieldDoc) topDocs.scoreDocs[0]).fields[0]).intValue(), equalTo(-27));
|
||||
assertThat(topDocs.scoreDocs[1].doc, equalTo(2));
|
||||
assertThat(((Number) ((FieldDoc) topDocs.scoreDocs[1]).fields[0]).intValue(), equalTo(3));
|
||||
assertThat(topDocs.scoreDocs[2].doc, equalTo(0));
|
||||
assertThat(((Number) ((FieldDoc) topDocs.scoreDocs[2]).fields[0]).intValue(), equalTo(6));
|
||||
assertThat(topDocs.scoreDocs[3].doc, equalTo(3));
|
||||
assertThat(((Number) ((FieldDoc) topDocs.scoreDocs[3]).fields[0]).intValue(), equalTo(15));
|
||||
assertThat(topDocs.scoreDocs[4].doc, equalTo(4));
|
||||
assertThat(((Number) ((FieldDoc) topDocs.scoreDocs[4]).fields[0]).intValue(), equalTo(21));
|
||||
assertThat(topDocs.scoreDocs[5].doc, equalTo(6));
|
||||
assertThat(((Number) ((FieldDoc) topDocs.scoreDocs[5]).fields[0]).intValue(), equalTo(27));
|
||||
assertThat(topDocs.scoreDocs[6].doc, equalTo(1));
|
||||
// assertThat(((FieldDoc) topDocs.scoreDocs[6]).fields[0], equalTo(null));
|
||||
assertThat(topDocs.scoreDocs[7].doc, equalTo(5));
|
||||
// assertThat(((FieldDoc) topDocs.scoreDocs[7]).fields[0], equalTo(null));
|
||||
|
||||
searcher = new IndexSearcher(DirectoryReader.open(writer, true));
|
||||
topDocs = searcher.search(new MatchAllDocsQuery(), 10,
|
||||
new Sort(new SortField("value", indexFieldData.comparatorSource(null, SortMode.SUM), true))); // defaults to _last
|
||||
assertThat(topDocs.totalHits, equalTo(8));
|
||||
assertThat(topDocs.scoreDocs.length, equalTo(8));
|
||||
assertThat(topDocs.scoreDocs[0].doc, equalTo(6));
|
||||
assertThat(((Number) ((FieldDoc) topDocs.scoreDocs[0]).fields[0]).intValue(), equalTo(27));
|
||||
assertThat(topDocs.scoreDocs[1].doc, equalTo(4));
|
||||
assertThat(((Number) ((FieldDoc) topDocs.scoreDocs[1]).fields[0]).intValue(), equalTo(21));
|
||||
assertThat(topDocs.scoreDocs[2].doc, equalTo(3));
|
||||
assertThat(((Number) ((FieldDoc) topDocs.scoreDocs[2]).fields[0]).intValue(), equalTo(15));
|
||||
assertThat(topDocs.scoreDocs[3].doc, equalTo(0));
|
||||
assertThat(((Number) ((FieldDoc) topDocs.scoreDocs[3]).fields[0]).intValue(), equalTo(6));
|
||||
assertThat(topDocs.scoreDocs[4].doc, equalTo(2));
|
||||
assertThat(((Number) ((FieldDoc) topDocs.scoreDocs[4]).fields[0]).intValue(), equalTo(3));
|
||||
assertThat(topDocs.scoreDocs[5].doc, equalTo(7));
|
||||
assertThat(((Number) ((FieldDoc) topDocs.scoreDocs[5]).fields[0]).intValue(), equalTo(-27));
|
||||
assertThat(topDocs.scoreDocs[6].doc, equalTo(1));
|
||||
// assertThat(((FieldDoc) topDocs.scoreDocs[6]).fields[0], equalTo(null));
|
||||
assertThat(topDocs.scoreDocs[7].doc, equalTo(5));
|
||||
// assertThat(((FieldDoc) topDocs.scoreDocs[7]).fields[0], equalTo(null));
|
||||
|
||||
searcher = new IndexSearcher(DirectoryReader.open(writer, true));
|
||||
topDocs = searcher.search(new MatchAllDocsQuery(), 10,
|
||||
new Sort(new SortField("value", indexFieldData.comparatorSource(null, SortMode.AVG)))); // defaults to _last
|
||||
assertThat(topDocs.totalHits, equalTo(8));
|
||||
assertThat(topDocs.scoreDocs.length, equalTo(8));
|
||||
assertThat(topDocs.scoreDocs[0].doc, equalTo(7));
|
||||
assertThat(((Number) ((FieldDoc) topDocs.scoreDocs[0]).fields[0]).intValue(), equalTo(-9));
|
||||
assertThat(topDocs.scoreDocs[1].doc, equalTo(0));
|
||||
assertThat(((Number) ((FieldDoc) topDocs.scoreDocs[1]).fields[0]).intValue(), equalTo(3));
|
||||
assertThat(topDocs.scoreDocs[2].doc, equalTo(2));
|
||||
assertThat(((Number) ((FieldDoc) topDocs.scoreDocs[2]).fields[0]).intValue(), equalTo(3));
|
||||
assertThat(topDocs.scoreDocs[3].doc, equalTo(3));
|
||||
assertThat(((Number) ((FieldDoc) topDocs.scoreDocs[3]).fields[0]).intValue(), equalTo(5));
|
||||
assertThat(topDocs.scoreDocs[4].doc, equalTo(4));
|
||||
assertThat(((Number) ((FieldDoc) topDocs.scoreDocs[4]).fields[0]).intValue(), equalTo(7));
|
||||
assertThat(topDocs.scoreDocs[5].doc, equalTo(6));
|
||||
assertThat(((Number) ((FieldDoc) topDocs.scoreDocs[5]).fields[0]).intValue(), equalTo(9));
|
||||
assertThat(topDocs.scoreDocs[6].doc, equalTo(1));
|
||||
// assertThat(((FieldDoc) topDocs.scoreDocs[6]).fields[0], equalTo(null));
|
||||
assertThat(topDocs.scoreDocs[7].doc, equalTo(5));
|
||||
// assertThat(((FieldDoc) topDocs.scoreDocs[7]).fields[0], equalTo(null));
|
||||
|
||||
searcher = new IndexSearcher(DirectoryReader.open(writer, true));
|
||||
topDocs = searcher.search(new MatchAllDocsQuery(), 10,
|
||||
new Sort(new SortField("value", indexFieldData.comparatorSource(null, SortMode.AVG), true))); // defaults to _last
|
||||
assertThat(topDocs.totalHits, equalTo(8));
|
||||
assertThat(topDocs.scoreDocs.length, equalTo(8));
|
||||
assertThat(topDocs.scoreDocs[0].doc, equalTo(6));
|
||||
assertThat(((Number) ((FieldDoc) topDocs.scoreDocs[0]).fields[0]).intValue(), equalTo(9));
|
||||
assertThat(topDocs.scoreDocs[1].doc, equalTo(4));
|
||||
assertThat(((Number) ((FieldDoc) topDocs.scoreDocs[1]).fields[0]).intValue(), equalTo(7));
|
||||
assertThat(topDocs.scoreDocs[2].doc, equalTo(3));
|
||||
assertThat(((Number) ((FieldDoc) topDocs.scoreDocs[2]).fields[0]).intValue(), equalTo(5));
|
||||
assertThat(topDocs.scoreDocs[3].doc, equalTo(0));
|
||||
assertThat(((Number) ((FieldDoc) topDocs.scoreDocs[3]).fields[0]).intValue(), equalTo(3));
|
||||
assertThat(topDocs.scoreDocs[4].doc, equalTo(2));
|
||||
assertThat(((Number) ((FieldDoc) topDocs.scoreDocs[4]).fields[0]).intValue(), equalTo(3));
|
||||
assertThat(topDocs.scoreDocs[5].doc, equalTo(7));
|
||||
assertThat(((Number) ((FieldDoc) topDocs.scoreDocs[5]).fields[0]).intValue(), equalTo(-9));
|
||||
assertThat(topDocs.scoreDocs[6].doc, equalTo(1));
|
||||
// assertThat(((FieldDoc) topDocs.scoreDocs[6]).fields[0], equalTo(null));
|
||||
assertThat(topDocs.scoreDocs[7].doc, equalTo(5));
|
||||
// assertThat(((FieldDoc) topDocs.scoreDocs[7]).fields[0], equalTo(null));
|
||||
|
||||
topDocs = searcher.search(new MatchAllDocsQuery(), 10,
|
||||
new Sort(new SortField("value", indexFieldData.comparatorSource("_first", SortMode.MIN))));
|
||||
assertThat(topDocs.totalHits, equalTo(8));
|
||||
assertThat(topDocs.scoreDocs.length, equalTo(8));
|
||||
assertThat(topDocs.scoreDocs[0].doc, equalTo(1));
|
||||
|
@ -665,7 +755,7 @@ public abstract class NumericFieldDataTests extends StringFieldDataTests {
|
|||
assertThat(topDocs.scoreDocs[7].doc, equalTo(6));
|
||||
|
||||
topDocs = searcher.search(new MatchAllDocsQuery(), 10,
|
||||
new Sort(new SortField("value", indexFieldData.comparatorSource("_first"), true)));
|
||||
new Sort(new SortField("value", indexFieldData.comparatorSource("_first", SortMode.MAX), true)));
|
||||
assertThat(topDocs.totalHits, equalTo(8));
|
||||
assertThat(topDocs.scoreDocs.length, equalTo(8));
|
||||
assertThat(topDocs.scoreDocs[0].doc, equalTo(1));
|
||||
|
@ -678,7 +768,7 @@ public abstract class NumericFieldDataTests extends StringFieldDataTests {
|
|||
assertThat(topDocs.scoreDocs[7].doc, equalTo(7));
|
||||
|
||||
topDocs = searcher.search(new MatchAllDocsQuery(), 10,
|
||||
new Sort(new SortField("value", indexFieldData.comparatorSource("-9"))));
|
||||
new Sort(new SortField("value", indexFieldData.comparatorSource("-9", SortMode.MIN))));
|
||||
assertThat(topDocs.totalHits, equalTo(8));
|
||||
assertThat(topDocs.scoreDocs.length, equalTo(8));
|
||||
assertThat(topDocs.scoreDocs[0].doc, equalTo(7));
|
||||
|
@ -691,7 +781,7 @@ public abstract class NumericFieldDataTests extends StringFieldDataTests {
|
|||
assertThat(topDocs.scoreDocs[7].doc, equalTo(6));
|
||||
|
||||
topDocs = searcher.search(new MatchAllDocsQuery(), 10,
|
||||
new Sort(new SortField("value", indexFieldData.comparatorSource("9"), true)));
|
||||
new Sort(new SortField("value", indexFieldData.comparatorSource("9", SortMode.MAX), true)));
|
||||
assertThat(topDocs.totalHits, equalTo(8));
|
||||
assertThat(topDocs.scoreDocs.length, equalTo(8));
|
||||
assertThat(topDocs.scoreDocs[0].doc, equalTo(6));
|
||||
|
|
|
@ -28,6 +28,7 @@ import org.apache.lucene.search.*;
|
|||
import org.apache.lucene.util.BytesRef;
|
||||
import org.elasticsearch.common.lucene.HashedBytesRef;
|
||||
import org.elasticsearch.index.fielddata.*;
|
||||
import org.elasticsearch.index.fielddata.fieldcomparator.SortMode;
|
||||
import org.elasticsearch.index.fielddata.util.BytesRefArrayRef;
|
||||
import org.elasticsearch.index.fielddata.util.StringArrayRef;
|
||||
import org.testng.annotations.Test;
|
||||
|
@ -197,7 +198,7 @@ public abstract class StringFieldDataTests extends AbstractFieldDataTests {
|
|||
TopFieldDocs topDocs;
|
||||
|
||||
topDocs = searcher.search(new MatchAllDocsQuery(), 10,
|
||||
new Sort(new SortField("value", indexFieldData.comparatorSource(null))));
|
||||
new Sort(new SortField("value", indexFieldData.comparatorSource(null, SortMode.MIN))));
|
||||
assertThat(topDocs.totalHits, equalTo(3));
|
||||
assertThat(topDocs.scoreDocs[0].doc, equalTo(1));
|
||||
assertThat(toString(((FieldDoc) topDocs.scoreDocs[0]).fields[0]), equalTo(one()));
|
||||
|
@ -207,7 +208,7 @@ public abstract class StringFieldDataTests extends AbstractFieldDataTests {
|
|||
assertThat(toString(((FieldDoc) topDocs.scoreDocs[2]).fields[0]), equalTo(three()));
|
||||
|
||||
topDocs = searcher.search(new MatchAllDocsQuery(), 10,
|
||||
new Sort(new SortField("value", indexFieldData.comparatorSource(null), true)));
|
||||
new Sort(new SortField("value", indexFieldData.comparatorSource(null, SortMode.MAX), true)));
|
||||
assertThat(topDocs.totalHits, equalTo(3));
|
||||
assertThat(topDocs.scoreDocs[0].doc, equalTo(2));
|
||||
assertThat(topDocs.scoreDocs[1].doc, equalTo(0));
|
||||
|
@ -487,14 +488,14 @@ public abstract class StringFieldDataTests extends AbstractFieldDataTests {
|
|||
stringValues.forEachValueInDoc(2, new StringValuesVerifierProc(2).addExpected(three()));
|
||||
|
||||
IndexSearcher searcher = new IndexSearcher(DirectoryReader.open(writer, true));
|
||||
TopFieldDocs topDocs = searcher.search(new MatchAllDocsQuery(), 10, new Sort(new SortField("value", indexFieldData.comparatorSource(null))));
|
||||
TopFieldDocs topDocs = searcher.search(new MatchAllDocsQuery(), 10, new Sort(new SortField("value", indexFieldData.comparatorSource(null, SortMode.MIN))));
|
||||
assertThat(topDocs.totalHits, equalTo(3));
|
||||
assertThat(topDocs.scoreDocs.length, equalTo(3));
|
||||
assertThat(topDocs.scoreDocs[0].doc, equalTo(1));
|
||||
assertThat(topDocs.scoreDocs[1].doc, equalTo(0));
|
||||
assertThat(topDocs.scoreDocs[2].doc, equalTo(2));
|
||||
|
||||
topDocs = searcher.search(new MatchAllDocsQuery(), 10, new Sort(new SortField("value", indexFieldData.comparatorSource(null), true)));
|
||||
topDocs = searcher.search(new MatchAllDocsQuery(), 10, new Sort(new SortField("value", indexFieldData.comparatorSource(null, SortMode.MAX), true)));
|
||||
assertThat(topDocs.totalHits, equalTo(3));
|
||||
assertThat(topDocs.scoreDocs.length, equalTo(3));
|
||||
assertThat(topDocs.scoreDocs[0].doc, equalTo(0));
|
||||
|
@ -770,7 +771,7 @@ public abstract class StringFieldDataTests extends AbstractFieldDataTests {
|
|||
|
||||
IndexSearcher searcher = new IndexSearcher(DirectoryReader.open(writer, true));
|
||||
TopFieldDocs topDocs = searcher.search(new MatchAllDocsQuery(), 10,
|
||||
new Sort(new SortField("value", indexFieldData.comparatorSource(null))));
|
||||
new Sort(new SortField("value", indexFieldData.comparatorSource(null, SortMode.MIN))));
|
||||
assertThat(topDocs.totalHits, equalTo(8));
|
||||
assertThat(topDocs.scoreDocs.length, equalTo(8));
|
||||
assertThat(topDocs.scoreDocs[0].doc, equalTo(1));
|
||||
|
@ -791,7 +792,7 @@ public abstract class StringFieldDataTests extends AbstractFieldDataTests {
|
|||
assertThat(((BytesRef) ((FieldDoc) topDocs.scoreDocs[7]).fields[0]).utf8ToString(), equalTo("08"));
|
||||
|
||||
topDocs = searcher.search(new MatchAllDocsQuery(), 10,
|
||||
new Sort(new SortField("value", indexFieldData.comparatorSource(null), true)));
|
||||
new Sort(new SortField("value", indexFieldData.comparatorSource(null, SortMode.MAX), true)));
|
||||
assertThat(topDocs.totalHits, equalTo(8));
|
||||
assertThat(topDocs.scoreDocs.length, equalTo(8));
|
||||
assertThat(topDocs.scoreDocs[0].doc, equalTo(6));
|
||||
|
|
Loading…
Reference in New Issue