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:
Martijn van Groningen 2013-02-12 20:34:26 +01:00
parent 7d13545e33
commit fc13499ff5
33 changed files with 465 additions and 220 deletions

View File

@ -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.

View File

@ -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;
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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];
}

View File

@ -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;
}
}

View File

@ -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);
}
}

View File

@ -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];
}

View File

@ -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);
}
}

View File

@ -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];
}

View File

@ -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);
}
}

View File

@ -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;
}

View File

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

View File

@ -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);
}
}

View File

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

View File

@ -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);
}
}

View File

@ -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);
}
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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");
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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;
}

View File

@ -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));
}
}
}

View File

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

View File

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

View File

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