diff --git a/src/main/java/org/elasticsearch/index/fielddata/IndexFieldData.java b/src/main/java/org/elasticsearch/index/fielddata/IndexFieldData.java index 1f36d941472..1141c8f3ac4 100644 --- a/src/main/java/org/elasticsearch/index/fielddata/IndexFieldData.java +++ b/src/main/java/org/elasticsearch/index/fielddata/IndexFieldData.java @@ -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 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. diff --git a/src/main/java/org/elasticsearch/index/fielddata/fieldcomparator/ByteValuesComparator.java b/src/main/java/org/elasticsearch/index/fielddata/fieldcomparator/ByteValuesComparator.java index 0996c396daa..4b5239e6682 100644 --- a/src/main/java/org/elasticsearch/index/fielddata/fieldcomparator/ByteValuesComparator.java +++ b/src/main/java/org/elasticsearch/index/fielddata/fieldcomparator/ByteValuesComparator.java @@ -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 { 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; } diff --git a/src/main/java/org/elasticsearch/index/fielddata/fieldcomparator/ByteValuesComparatorSource.java b/src/main/java/org/elasticsearch/index/fielddata/fieldcomparator/ByteValuesComparatorSource.java index 59cad9a78d2..7d503a21c51 100644 --- a/src/main/java/org/elasticsearch/index/fielddata/fieldcomparator/ByteValuesComparatorSource.java +++ b/src/main/java/org/elasticsearch/index/fielddata/fieldcomparator/ByteValuesComparatorSource.java @@ -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); } } diff --git a/src/main/java/org/elasticsearch/index/fielddata/fieldcomparator/BytesRefFieldComparatorSource.java b/src/main/java/org/elasticsearch/index/fielddata/fieldcomparator/BytesRefFieldComparatorSource.java index 60f98fb0881..32f9f5bc1cb 100644 --- a/src/main/java/org/elasticsearch/index/fielddata/fieldcomparator/BytesRefFieldComparatorSource.java +++ b/src/main/java/org/elasticsearch/index/fielddata/fieldcomparator/BytesRefFieldComparatorSource.java @@ -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); } } diff --git a/src/main/java/org/elasticsearch/index/fielddata/fieldcomparator/BytesRefOrdValComparator.java b/src/main/java/org/elasticsearch/index/fielddata/fieldcomparator/BytesRefOrdValComparator.java index 55a5f356c91..97fad10ca81 100644 --- a/src/main/java/org/elasticsearch/index/fielddata/fieldcomparator/BytesRefOrdValComparator.java +++ b/src/main/java/org/elasticsearch/index/fielddata/fieldcomparator/BytesRefOrdValComparator.java @@ -47,7 +47,7 @@ public final class BytesRefOrdValComparator extends FieldComparator { @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 { 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 { @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 { @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 { @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 { } - 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 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 { 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 { int relevantVal = currentVal; while (true) { - if (reversed) { + if (sortMode == SortMode.MAX) { if (currentVal > relevantVal) { relevantVal = currentVal; } diff --git a/src/main/java/org/elasticsearch/index/fielddata/fieldcomparator/BytesRefValComparator.java b/src/main/java/org/elasticsearch/index/fielddata/fieldcomparator/BytesRefValComparator.java index 115cedf723d..c4e7253acef 100644 --- a/src/main/java/org/elasticsearch/index/fielddata/fieldcomparator/BytesRefValComparator.java +++ b/src/main/java/org/elasticsearch/index/fielddata/fieldcomparator/BytesRefValComparator.java @@ -37,14 +37,14 @@ import java.io.IOException; public final class BytesRefValComparator extends FieldComparator { 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 { public FieldComparator 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 { 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 relevantVal = currentVal; while (true) { int cmp = currentVal.compareTo(relevantVal); - if (reversed) { + if (sortMode == SortMode.MAX) { if (cmp > 0) { relevantVal = currentVal; } diff --git a/src/main/java/org/elasticsearch/index/fielddata/fieldcomparator/DoubleValuesComparator.java b/src/main/java/org/elasticsearch/index/fielddata/fieldcomparator/DoubleValuesComparator.java index ad35e9b28e2..82236dd7ab4 100644 --- a/src/main/java/org/elasticsearch/index/fielddata/fieldcomparator/DoubleValuesComparator.java +++ b/src/main/java/org/elasticsearch/index/fielddata/fieldcomparator/DoubleValuesComparator.java @@ -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 { 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]; } diff --git a/src/main/java/org/elasticsearch/index/fielddata/fieldcomparator/DoubleValuesComparatorBase.java b/src/main/java/org/elasticsearch/index/fielddata/fieldcomparator/DoubleValuesComparatorBase.java index 5cecbd47985..46843594e79 100644 --- a/src/main/java/org/elasticsearch/index/fielddata/fieldcomparator/DoubleValuesComparatorBase.java +++ b/src/main/java/org/elasticsearch/index/fielddata/fieldcomparator/DoubleValuesComparatorBase.java @@ -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 extends FieldComparator { - protected final IndexNumericFieldDataindexFieldData; + 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 @@ -43,23 +44,23 @@ abstract class DoubleValuesComparatorBase extends FieldCompara final double v2 = readerValues.getValueMissing(doc, missingValue); return compare(bottom, v2); } - + @Override public final int compareDocToValue(int doc, T valueObj) throws IOException { final double value = valueObj.doubleValue(); final double docValue = readerValues.getValueMissing(doc, missingValue); return compare(docValue, value); } - + @Override public final FieldComparator 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; } - + static final int compare(double left, double right) { if (left > right) { return 1; @@ -69,14 +70,14 @@ abstract class DoubleValuesComparatorBase extends FieldCompara return 0; } } - + static final class MultiValuedBytesWrapper extends DoubleValues.FilteredDoubleValues { - private final boolean reversed; - - public MultiValuedBytesWrapper(DoubleValues delegate, boolean reversed) { + private final SortMode sortMode; + + public MultiValuedBytesWrapper(DoubleValues delegate, SortMode sortMode) { super(delegate); - this.reversed = reversed; + this.sortMode = sortMode; } @Override @@ -88,23 +89,35 @@ abstract class DoubleValuesComparatorBase 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; } } diff --git a/src/main/java/org/elasticsearch/index/fielddata/fieldcomparator/DoubleValuesComparatorSource.java b/src/main/java/org/elasticsearch/index/fielddata/fieldcomparator/DoubleValuesComparatorSource.java index fc37b127e9a..cbfa5a3dd76 100644 --- a/src/main/java/org/elasticsearch/index/fielddata/fieldcomparator/DoubleValuesComparatorSource.java +++ b/src/main/java/org/elasticsearch/index/fielddata/fieldcomparator/DoubleValuesComparatorSource.java @@ -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); } } diff --git a/src/main/java/org/elasticsearch/index/fielddata/fieldcomparator/FloatValuesComparator.java b/src/main/java/org/elasticsearch/index/fielddata/fieldcomparator/FloatValuesComparator.java index 3e13e87ae36..eba6ee529a9 100644 --- a/src/main/java/org/elasticsearch/index/fielddata/fieldcomparator/FloatValuesComparator.java +++ b/src/main/java/org/elasticsearch/index/fielddata/fieldcomparator/FloatValuesComparator.java @@ -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 { 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]; } diff --git a/src/main/java/org/elasticsearch/index/fielddata/fieldcomparator/FloatValuesComparatorSource.java b/src/main/java/org/elasticsearch/index/fielddata/fieldcomparator/FloatValuesComparatorSource.java index 5fe1df1bbe9..023b1b122c6 100644 --- a/src/main/java/org/elasticsearch/index/fielddata/fieldcomparator/FloatValuesComparatorSource.java +++ b/src/main/java/org/elasticsearch/index/fielddata/fieldcomparator/FloatValuesComparatorSource.java @@ -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); } } diff --git a/src/main/java/org/elasticsearch/index/fielddata/fieldcomparator/IntValuesComparator.java b/src/main/java/org/elasticsearch/index/fielddata/fieldcomparator/IntValuesComparator.java index 5d5c2011eee..ecad6524438 100644 --- a/src/main/java/org/elasticsearch/index/fielddata/fieldcomparator/IntValuesComparator.java +++ b/src/main/java/org/elasticsearch/index/fielddata/fieldcomparator/IntValuesComparator.java @@ -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 { 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]; } diff --git a/src/main/java/org/elasticsearch/index/fielddata/fieldcomparator/IntValuesComparatorSource.java b/src/main/java/org/elasticsearch/index/fielddata/fieldcomparator/IntValuesComparatorSource.java index 53459fe94e2..4688122872e 100644 --- a/src/main/java/org/elasticsearch/index/fielddata/fieldcomparator/IntValuesComparatorSource.java +++ b/src/main/java/org/elasticsearch/index/fielddata/fieldcomparator/IntValuesComparatorSource.java @@ -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); } } diff --git a/src/main/java/org/elasticsearch/index/fielddata/fieldcomparator/LongValuesComparator.java b/src/main/java/org/elasticsearch/index/fielddata/fieldcomparator/LongValuesComparator.java index 9952ec3d07c..dcf00b7de88 100644 --- a/src/main/java/org/elasticsearch/index/fielddata/fieldcomparator/LongValuesComparator.java +++ b/src/main/java/org/elasticsearch/index/fielddata/fieldcomparator/LongValuesComparator.java @@ -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 { 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; } @@ -50,7 +50,7 @@ public final class LongValuesComparator extends LongValuesComparatorBase { public void copy(int slot, int doc) throws IOException { values[slot] = readerValues.getValueMissing(doc, missingValue); } - + @Override public Long value(int slot) { return Long.valueOf(values[slot]); diff --git a/src/main/java/org/elasticsearch/index/fielddata/fieldcomparator/LongValuesComparatorBase.java b/src/main/java/org/elasticsearch/index/fielddata/fieldcomparator/LongValuesComparatorBase.java index f68b04baa2d..e9da18ef4a5 100644 --- a/src/main/java/org/elasticsearch/index/fielddata/fieldcomparator/LongValuesComparatorBase.java +++ b/src/main/java/org/elasticsearch/index/fielddata/fieldcomparator/LongValuesComparatorBase.java @@ -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 extends FieldComparator { 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 @@ -44,14 +45,14 @@ abstract class LongValuesComparatorBase extends FieldComparato long v2 = readerValues.getValueMissing(doc, missingValue); return compare(bottom, v2); } - + @Override public final int compareDocToValue(int doc, T valueObj) throws IOException { final long value = valueObj.longValue(); long docValue = readerValues.getValueMissing(doc, missingValue); return compare(docValue, value); } - + static final int compare(long left, long right) { if (left > right) { return 1; @@ -61,23 +62,23 @@ abstract class LongValuesComparatorBase extends FieldComparato return 0; } } - + @Override public final FieldComparator 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 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 diff --git a/src/main/java/org/elasticsearch/index/fielddata/fieldcomparator/LongValuesComparatorSource.java b/src/main/java/org/elasticsearch/index/fielddata/fieldcomparator/LongValuesComparatorSource.java index 767ca8d9137..a695adf9b90 100644 --- a/src/main/java/org/elasticsearch/index/fielddata/fieldcomparator/LongValuesComparatorSource.java +++ b/src/main/java/org/elasticsearch/index/fielddata/fieldcomparator/LongValuesComparatorSource.java @@ -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); } } diff --git a/src/main/java/org/elasticsearch/index/fielddata/fieldcomparator/ShortValuesComparator.java b/src/main/java/org/elasticsearch/index/fielddata/fieldcomparator/ShortValuesComparator.java index 64b51808b47..bfbe35d3396 100644 --- a/src/main/java/org/elasticsearch/index/fielddata/fieldcomparator/ShortValuesComparator.java +++ b/src/main/java/org/elasticsearch/index/fielddata/fieldcomparator/ShortValuesComparator.java @@ -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 { 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 diff --git a/src/main/java/org/elasticsearch/index/fielddata/fieldcomparator/ShortValuesComparatorSource.java b/src/main/java/org/elasticsearch/index/fielddata/fieldcomparator/ShortValuesComparatorSource.java index df9fdc1c0b0..2932d3b5785 100644 --- a/src/main/java/org/elasticsearch/index/fielddata/fieldcomparator/ShortValuesComparatorSource.java +++ b/src/main/java/org/elasticsearch/index/fielddata/fieldcomparator/ShortValuesComparatorSource.java @@ -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); } } diff --git a/src/main/java/org/elasticsearch/index/fielddata/fieldcomparator/SortMode.java b/src/main/java/org/elasticsearch/index/fielddata/fieldcomparator/SortMode.java new file mode 100644 index 00000000000..02f30835bb1 --- /dev/null +++ b/src/main/java/org/elasticsearch/index/fielddata/fieldcomparator/SortMode.java @@ -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); + } + } + +} diff --git a/src/main/java/org/elasticsearch/index/fielddata/plain/ByteArrayIndexFieldData.java b/src/main/java/org/elasticsearch/index/fielddata/plain/ByteArrayIndexFieldData.java index 76ec1ca44e0..06a472b8ff1 100644 --- a/src/main/java/org/elasticsearch/index/fielddata/plain/ByteArrayIndexFieldData.java +++ b/src/main/java/org/elasticsearch/index/fielddata/plain/ByteArrayIndexFieldData.java @@ -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 implements IndexNumericFieldData { @@ -96,8 +95,8 @@ public class ByteArrayIndexFieldData extends AbstractIndexFieldData + * 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; } diff --git a/src/main/java/org/elasticsearch/search/sort/SortParseElement.java b/src/main/java/org/elasticsearch/search/sort/SortParseElement.java index 5575f3e3165..fa02da2bde4 100644 --- a/src/main/java/org/elasticsearch/search/sort/SortParseElement.java +++ b/src/main/java/org/elasticsearch/search/sort/SortParseElement.java @@ -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 sortFields, String fieldName, boolean reverse, boolean ignoreUnmapped, @Nullable final String missing) { + private void addSortField(SearchContext context, List 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)); } } } diff --git a/src/test/java/org/elasticsearch/test/integration/search/sort/SimpleSortTests.java b/src/test/java/org/elasticsearch/test/integration/search/sort/SimpleSortTests.java index 8f64590342b..e681f3633fe 100644 --- a/src/test/java/org/elasticsearch/test/integration/search/sort/SimpleSortTests.java +++ b/src/test/java/org/elasticsearch/test/integration/search/sort/SimpleSortTests.java @@ -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) diff --git a/src/test/java/org/elasticsearch/test/unit/index/fielddata/NumericFieldDataTests.java b/src/test/java/org/elasticsearch/test/unit/index/fielddata/NumericFieldDataTests.java index 1c4e93763a7..7fe54b82e66 100644 --- a/src/test/java/org/elasticsearch/test/unit/index/fielddata/NumericFieldDataTests.java +++ b/src/test/java/org/elasticsearch/test/unit/index/fielddata/NumericFieldDataTests.java @@ -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)); diff --git a/src/test/java/org/elasticsearch/test/unit/index/fielddata/StringFieldDataTests.java b/src/test/java/org/elasticsearch/test/unit/index/fielddata/StringFieldDataTests.java index fa9fc88f4e8..e42f795ab24 100644 --- a/src/test/java/org/elasticsearch/test/unit/index/fielddata/StringFieldDataTests.java +++ b/src/test/java/org/elasticsearch/test/unit/index/fielddata/StringFieldDataTests.java @@ -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));