Added sort by field that have multiple values per document.
Closes #2634
This commit is contained in:
parent
033d6e4306
commit
8c7779057c
|
@ -23,6 +23,7 @@ import org.apache.lucene.index.AtomicReaderContext;
|
|||
import org.apache.lucene.search.FieldComparator;
|
||||
import org.elasticsearch.index.fielddata.ByteValues;
|
||||
import org.elasticsearch.index.fielddata.IndexNumericFieldData;
|
||||
import org.elasticsearch.index.fielddata.util.ByteArrayRef;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
|
@ -32,14 +33,16 @@ public class ByteValuesComparator extends FieldComparator<Byte> {
|
|||
|
||||
private final IndexNumericFieldData indexFieldData;
|
||||
private final byte missingValue;
|
||||
private final boolean reversed;
|
||||
|
||||
protected final byte[] values;
|
||||
private final byte[] values;
|
||||
private byte bottom;
|
||||
private ByteValues readerValues;
|
||||
|
||||
public ByteValuesComparator(IndexNumericFieldData indexFieldData, byte missingValue, int numHits) {
|
||||
public ByteValuesComparator(IndexNumericFieldData indexFieldData, byte missingValue, int numHits, boolean reversed) {
|
||||
this.indexFieldData = indexFieldData;
|
||||
this.missingValue = missingValue;
|
||||
this.reversed = reversed;
|
||||
this.values = new byte[numHits];
|
||||
}
|
||||
|
||||
|
@ -81,7 +84,10 @@ public class ByteValuesComparator extends FieldComparator<Byte> {
|
|||
|
||||
@Override
|
||||
public FieldComparator<Byte> setNextReader(AtomicReaderContext context) throws IOException {
|
||||
this.readerValues = indexFieldData.load(context).getByteValues();
|
||||
readerValues = indexFieldData.load(context).getByteValues();
|
||||
if (readerValues.isMultiValued()) {
|
||||
readerValues = new MultiValuedBytesWrapper(readerValues, reversed);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -102,4 +108,80 @@ public class ByteValuesComparator extends FieldComparator<Byte> {
|
|||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
public static class FilteredByteValues implements ByteValues {
|
||||
|
||||
protected final ByteValues delegate;
|
||||
|
||||
public FilteredByteValues(ByteValues delegate) {
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
public boolean isMultiValued() {
|
||||
return delegate.isMultiValued();
|
||||
}
|
||||
|
||||
public boolean hasValue(int docId) {
|
||||
return delegate.hasValue(docId);
|
||||
}
|
||||
|
||||
public byte getValue(int docId) {
|
||||
return delegate.getValue(docId);
|
||||
}
|
||||
|
||||
public byte getValueMissing(int docId, byte missingValue) {
|
||||
return delegate.getValueMissing(docId, missingValue);
|
||||
}
|
||||
|
||||
public ByteArrayRef getValues(int docId) {
|
||||
return delegate.getValues(docId);
|
||||
}
|
||||
|
||||
public Iter getIter(int docId) {
|
||||
return delegate.getIter(docId);
|
||||
}
|
||||
|
||||
public void forEachValueInDoc(int docId, ValueInDocProc proc) {
|
||||
delegate.forEachValueInDoc(docId, proc);
|
||||
}
|
||||
}
|
||||
|
||||
private static final class MultiValuedBytesWrapper extends FilteredByteValues {
|
||||
|
||||
private final boolean reversed;
|
||||
|
||||
public MultiValuedBytesWrapper(ByteValues delegate, boolean reversed) {
|
||||
super(delegate);
|
||||
this.reversed = reversed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte getValueMissing(int docId, byte missing) {
|
||||
ByteValues.Iter iter = delegate.getIter(docId);
|
||||
if (!iter.hasNext()) {
|
||||
return missing;
|
||||
}
|
||||
|
||||
byte currentVal = iter.next();
|
||||
byte relevantVal = currentVal;
|
||||
while (true) {
|
||||
if (reversed) {
|
||||
if (currentVal > relevantVal) {
|
||||
relevantVal = currentVal;
|
||||
}
|
||||
} else {
|
||||
if (currentVal < relevantVal) {
|
||||
relevantVal = currentVal;
|
||||
}
|
||||
}
|
||||
if (!iter.hasNext()) {
|
||||
break;
|
||||
}
|
||||
currentVal = iter.next();
|
||||
}
|
||||
return relevantVal;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -57,6 +57,6 @@ public class ByteValuesComparatorSource extends IndexFieldData.XFieldComparatorS
|
|||
dMissingValue = missingValue instanceof Number ? ((Number) missingValue).byteValue() : Byte.parseByte(missingValue.toString());
|
||||
}
|
||||
|
||||
return new ByteValuesComparator(indexFieldData, dMissingValue, numHits);
|
||||
return new ByteValuesComparator(indexFieldData, dMissingValue, numHits, reversed);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -44,8 +44,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);
|
||||
return new BytesRefOrdValComparator((IndexFieldData.WithOrdinals) indexFieldData, numHits, reversed);
|
||||
}
|
||||
return new BytesRefValComparator(indexFieldData, numHits);
|
||||
return new BytesRefValComparator(indexFieldData, numHits, reversed);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,7 +22,6 @@ package org.elasticsearch.index.fielddata.fieldcomparator;
|
|||
import org.apache.lucene.index.AtomicReaderContext;
|
||||
import org.apache.lucene.search.FieldComparator;
|
||||
import org.apache.lucene.util.BytesRef;
|
||||
import org.elasticsearch.ElasticSearchIllegalArgumentException;
|
||||
import org.elasticsearch.index.fielddata.BytesValues;
|
||||
import org.elasticsearch.index.fielddata.IndexFieldData;
|
||||
import org.elasticsearch.index.fielddata.ordinals.Ordinals;
|
||||
|
@ -48,6 +47,8 @@ public final class BytesRefOrdValComparator extends FieldComparator<BytesRef> {
|
|||
@lucene.internal */
|
||||
final int[] ords;
|
||||
|
||||
final boolean reversed;
|
||||
|
||||
/* Values for each slot.
|
||||
@lucene.internal */
|
||||
final BytesRef[] values;
|
||||
|
@ -88,8 +89,9 @@ public final class BytesRefOrdValComparator extends FieldComparator<BytesRef> {
|
|||
|
||||
final BytesRef tempBR = new BytesRef();
|
||||
|
||||
public BytesRefOrdValComparator(IndexFieldData.WithOrdinals indexFieldData, int numHits) {
|
||||
public BytesRefOrdValComparator(IndexFieldData.WithOrdinals indexFieldData, int numHits, boolean reversed) {
|
||||
this.indexFieldData = indexFieldData;
|
||||
this.reversed = reversed;
|
||||
ords = new int[numHits];
|
||||
values = new BytesRef[numHits];
|
||||
readerGen = new int[numHits];
|
||||
|
@ -378,13 +380,12 @@ public final class BytesRefOrdValComparator extends FieldComparator<BytesRef> {
|
|||
public FieldComparator<BytesRef> setNextReader(AtomicReaderContext context) throws IOException {
|
||||
final int docBase = context.docBase;
|
||||
termsIndex = indexFieldData.load(context).getBytesValues();
|
||||
// TODO, we should support sorting on multi valued field, take the best ascending value out of all the values
|
||||
FieldComparator<BytesRef> perSegComp = null;
|
||||
if (termsIndex.isMultiValued()) {
|
||||
throw new ElasticSearchIllegalArgumentException("can't sort on a multi valued field");
|
||||
}
|
||||
perSegComp = new MultiAnyOrdComparator(termsIndex);
|
||||
} else {
|
||||
final Ordinals.Docs docToOrd = termsIndex.ordinals();
|
||||
Object ordsStorage = docToOrd.ordinals().getBackingStorage();
|
||||
FieldComparator<BytesRef> perSegComp = null;
|
||||
|
||||
if (docToOrd.ordinals().hasSingleArrayBackingStorage()) {
|
||||
if (ordsStorage instanceof byte[]) {
|
||||
|
@ -403,12 +404,11 @@ public final class BytesRefOrdValComparator extends FieldComparator<BytesRef> {
|
|||
if (perSegComp == null) {
|
||||
perSegComp = new AnyOrdComparator(indexFieldData, termsIndex, docBase);
|
||||
}
|
||||
|
||||
}
|
||||
currentReaderGen++;
|
||||
if (bottomSlot != -1) {
|
||||
perSegComp.setBottom(bottomSlot);
|
||||
}
|
||||
|
||||
return perSegComp;
|
||||
}
|
||||
|
||||
|
@ -473,4 +473,128 @@ public final class BytesRefOrdValComparator extends FieldComparator<BytesRef> {
|
|||
}
|
||||
return -(low + 1);
|
||||
}
|
||||
|
||||
|
||||
class MultiAnyOrdComparator extends PerSegmentComparator {
|
||||
|
||||
private final BytesValues.WithOrdinals termsIndex;
|
||||
private final Ordinals.Docs readerOrds;
|
||||
|
||||
private MultiAnyOrdComparator(BytesValues.WithOrdinals termsIndex) {
|
||||
this.termsIndex = termsIndex;
|
||||
this.readerOrds = termsIndex.ordinals();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareBottom(int doc) throws IOException {
|
||||
final int docOrd = getRelevantOrd(readerOrds, doc, reversed);
|
||||
if (bottomSameReader) {
|
||||
// ord is precisely comparable, even in the equal case
|
||||
return bottomOrd - docOrd;
|
||||
} else if (bottomOrd >= docOrd) {
|
||||
// the equals case always means bottom is > doc
|
||||
// (because we set bottomOrd to the lower bound in
|
||||
// setBottom):
|
||||
return 1;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void copy(int slot, int doc) throws IOException {
|
||||
final int ord = getRelevantOrd(readerOrds, doc, reversed);
|
||||
ords[slot] = ord;
|
||||
if (ord == 0) {
|
||||
values[slot] = null;
|
||||
} else {
|
||||
assert ord > 0;
|
||||
if (values[slot] == null) {
|
||||
values[slot] = new BytesRef();
|
||||
}
|
||||
termsIndex.getValueScratchByOrd(ord, values[slot]);
|
||||
}
|
||||
readerGen[slot] = currentReaderGen;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareDocToValue(int doc, BytesRef value) {
|
||||
BytesRef docValue = getRelevantValue(termsIndex, doc, reversed);
|
||||
if (docValue == null) {
|
||||
if (value == null) {
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
} else if (value == null) {
|
||||
return 1;
|
||||
}
|
||||
return docValue.compareTo(value);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static BytesRef getRelevantValue(BytesValues.WithOrdinals readerValues, int docId, boolean reversed) {
|
||||
BytesValues.Iter iter = readerValues.getIter(docId);
|
||||
if (!iter.hasNext()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
BytesRef currentVal = iter.next();
|
||||
BytesRef relevantVal = currentVal;
|
||||
while (true) {
|
||||
int cmp = currentVal.compareTo(relevantVal);
|
||||
if (reversed) {
|
||||
if (cmp > 0) {
|
||||
relevantVal = currentVal;
|
||||
}
|
||||
} else {
|
||||
if (cmp < 0) {
|
||||
relevantVal = currentVal;
|
||||
}
|
||||
}
|
||||
if (!iter.hasNext()) {
|
||||
break;
|
||||
}
|
||||
currentVal = iter.next();
|
||||
}
|
||||
return relevantVal;
|
||||
}
|
||||
|
||||
static int getRelevantOrd(Ordinals.Docs readerOrds, int docId, boolean reversed) {
|
||||
Ordinals.Docs.Iter iter = readerOrds.getIter(docId);
|
||||
int currentVal = iter.next();
|
||||
if (currentVal == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int relevantVal = currentVal;
|
||||
while (true) {
|
||||
if (reversed) {
|
||||
if (currentVal > relevantVal) {
|
||||
relevantVal = currentVal;
|
||||
}
|
||||
} else {
|
||||
if (currentVal < relevantVal) {
|
||||
relevantVal = currentVal;
|
||||
}
|
||||
}
|
||||
currentVal = iter.next();
|
||||
if (currentVal == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return relevantVal;
|
||||
// Enable this when the api can tell us that the ords per doc are ordered
|
||||
/*if (reversed) {
|
||||
IntArrayRef ref = readerOrds.getOrds(docId);
|
||||
if (ref.isEmpty()) {
|
||||
return 0;
|
||||
} else {
|
||||
return ref.values[ref.end - 1]; // last element is the highest value.
|
||||
}
|
||||
} else {
|
||||
return readerOrds.getOrd(docId); // returns the lowest value
|
||||
}*/
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@ import org.apache.lucene.search.FieldComparator;
|
|||
import org.apache.lucene.util.BytesRef;
|
||||
import org.elasticsearch.index.fielddata.BytesValues;
|
||||
import org.elasticsearch.index.fielddata.IndexFieldData;
|
||||
import org.elasticsearch.index.fielddata.util.BytesRefArrayRef;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
|
@ -36,11 +37,14 @@ import java.io.IOException;
|
|||
public final class BytesRefValComparator extends FieldComparator<BytesRef> {
|
||||
|
||||
private final IndexFieldData indexFieldData;
|
||||
private BytesRef[] values;
|
||||
private BytesValues docTerms;
|
||||
private BytesRef bottom;
|
||||
private final boolean reversed;
|
||||
|
||||
BytesRefValComparator(IndexFieldData indexFieldData, int numHits) {
|
||||
private final BytesRef[] values;
|
||||
private BytesRef bottom;
|
||||
private BytesValues docTerms;
|
||||
|
||||
BytesRefValComparator(IndexFieldData indexFieldData, int numHits, boolean reversed) {
|
||||
this.reversed = reversed;
|
||||
values = new BytesRef[numHits];
|
||||
this.indexFieldData = indexFieldData;
|
||||
}
|
||||
|
@ -62,7 +66,7 @@ public final class BytesRefValComparator extends FieldComparator<BytesRef> {
|
|||
}
|
||||
|
||||
@Override
|
||||
public int compareBottom(int doc) {
|
||||
public int compareBottom(int doc) throws IOException {
|
||||
BytesRef val2 = docTerms.getValue(doc);
|
||||
if (bottom == null) {
|
||||
if (val2 == null) {
|
||||
|
@ -76,7 +80,7 @@ public final class BytesRefValComparator extends FieldComparator<BytesRef> {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void copy(int slot, int doc) {
|
||||
public void copy(int slot, int doc) throws IOException {
|
||||
if (values[slot] == null) {
|
||||
values[slot] = new BytesRef();
|
||||
}
|
||||
|
@ -86,6 +90,9 @@ public final class BytesRefValComparator extends FieldComparator<BytesRef> {
|
|||
@Override
|
||||
public FieldComparator<BytesRef> setNextReader(AtomicReaderContext context) throws IOException {
|
||||
docTerms = indexFieldData.load(context).getBytesValues();
|
||||
if (docTerms.isMultiValued()) {
|
||||
docTerms = new MultiValuedBytesWrapper(docTerms, reversed);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -116,4 +123,95 @@ public final class BytesRefValComparator extends FieldComparator<BytesRef> {
|
|||
public int compareDocToValue(int doc, BytesRef value) {
|
||||
return docTerms.getValue(doc).compareTo(value);
|
||||
}
|
||||
|
||||
public static class FilteredByteValues implements BytesValues {
|
||||
|
||||
protected final BytesValues delegate;
|
||||
|
||||
public FilteredByteValues(BytesValues delegate) {
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
public boolean isMultiValued() {
|
||||
return delegate.isMultiValued();
|
||||
}
|
||||
|
||||
public boolean hasValue(int docId) {
|
||||
return delegate.hasValue(docId);
|
||||
}
|
||||
|
||||
public BytesRef getValue(int docId) {
|
||||
return delegate.getValue(docId);
|
||||
}
|
||||
|
||||
public BytesRef makeSafe(BytesRef bytes) {
|
||||
return delegate.makeSafe(bytes);
|
||||
}
|
||||
|
||||
public BytesRef getValueScratch(int docId, BytesRef ret) {
|
||||
return delegate.getValueScratch(docId, ret);
|
||||
}
|
||||
|
||||
public BytesRefArrayRef getValues(int docId) {
|
||||
return delegate.getValues(docId);
|
||||
}
|
||||
|
||||
public Iter getIter(int docId) {
|
||||
return delegate.getIter(docId);
|
||||
}
|
||||
|
||||
public void forEachValueInDoc(int docId, ValueInDocProc proc) {
|
||||
delegate.forEachValueInDoc(docId, proc);
|
||||
}
|
||||
}
|
||||
|
||||
private static final class MultiValuedBytesWrapper extends FilteredByteValues {
|
||||
|
||||
private final boolean reversed;
|
||||
|
||||
public MultiValuedBytesWrapper(BytesValues delegate, boolean reversed) {
|
||||
super(delegate);
|
||||
this.reversed = reversed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BytesRef getValueScratch(int docId, BytesRef scratch) {
|
||||
BytesValues.Iter iter = delegate.getIter(docId);
|
||||
if (!iter.hasNext()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
BytesRef currentVal = iter.next();
|
||||
BytesRef relevantVal = currentVal;
|
||||
while (true) {
|
||||
int cmp = currentVal.compareTo(relevantVal);
|
||||
if (reversed) {
|
||||
if (cmp > 0) {
|
||||
relevantVal = currentVal;
|
||||
}
|
||||
} else {
|
||||
if (cmp < 0) {
|
||||
relevantVal = currentVal;
|
||||
}
|
||||
}
|
||||
if (!iter.hasNext()) {
|
||||
break;
|
||||
}
|
||||
currentVal = iter.next();
|
||||
}
|
||||
return relevantVal;
|
||||
/*if (reversed) {
|
||||
BytesRefArrayRef ref = readerValues.getValues(docId);
|
||||
if (ref.isEmpty()) {
|
||||
return null;
|
||||
} else {
|
||||
return ref.values[ref.end - 1]; // last element is the highest value.
|
||||
}
|
||||
} else {
|
||||
return readerValues.getValue(docId); // returns the lowest value
|
||||
}*/
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@ 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 org.elasticsearch.index.fielddata.util.DoubleArrayRef;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
|
@ -32,14 +33,16 @@ public class DoubleValuesComparator extends FieldComparator<Double> {
|
|||
|
||||
private final IndexNumericFieldData indexFieldData;
|
||||
private final double missingValue;
|
||||
private final boolean reversed;
|
||||
|
||||
protected final double[] values;
|
||||
private final double[] values;
|
||||
private double bottom;
|
||||
private DoubleValues readerValues;
|
||||
|
||||
public DoubleValuesComparator(IndexNumericFieldData indexFieldData, double missingValue, int numHits) {
|
||||
public DoubleValuesComparator(IndexNumericFieldData indexFieldData, double missingValue, int numHits, boolean reversed) {
|
||||
this.indexFieldData = indexFieldData;
|
||||
this.missingValue = missingValue;
|
||||
this.reversed = reversed;
|
||||
this.values = new double[numHits];
|
||||
}
|
||||
|
||||
|
@ -81,7 +84,10 @@ public class DoubleValuesComparator extends FieldComparator<Double> {
|
|||
|
||||
@Override
|
||||
public FieldComparator<Double> setNextReader(AtomicReaderContext context) throws IOException {
|
||||
this.readerValues = indexFieldData.load(context).getDoubleValues();
|
||||
readerValues = indexFieldData.load(context).getDoubleValues();
|
||||
if (readerValues.isMultiValued()) {
|
||||
readerValues = new MultiValuedBytesWrapper(readerValues, reversed);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -102,4 +108,81 @@ public class DoubleValuesComparator extends FieldComparator<Double> {
|
|||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
public static class FilteredByteValues implements DoubleValues {
|
||||
|
||||
protected final DoubleValues delegate;
|
||||
|
||||
public FilteredByteValues(DoubleValues delegate) {
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
public boolean isMultiValued() {
|
||||
return delegate.isMultiValued();
|
||||
}
|
||||
|
||||
public boolean hasValue(int docId) {
|
||||
return delegate.hasValue(docId);
|
||||
}
|
||||
|
||||
public double getValue(int docId) {
|
||||
return delegate.getValue(docId);
|
||||
}
|
||||
|
||||
public double getValueMissing(int docId, double missingValue) {
|
||||
return delegate.getValueMissing(docId, missingValue);
|
||||
}
|
||||
|
||||
public DoubleArrayRef getValues(int docId) {
|
||||
return delegate.getValues(docId);
|
||||
}
|
||||
|
||||
public Iter getIter(int docId) {
|
||||
return delegate.getIter(docId);
|
||||
}
|
||||
|
||||
public void forEachValueInDoc(int docId, ValueInDocProc proc) {
|
||||
delegate.forEachValueInDoc(docId, proc);
|
||||
}
|
||||
}
|
||||
|
||||
private static final class MultiValuedBytesWrapper extends FilteredByteValues {
|
||||
|
||||
private final boolean reversed;
|
||||
|
||||
public MultiValuedBytesWrapper(DoubleValues delegate, boolean reversed) {
|
||||
super(delegate);
|
||||
this.reversed = reversed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getValueMissing(int docId, double missing) {
|
||||
DoubleValues.Iter iter = delegate.getIter(docId);
|
||||
if (!iter.hasNext()) {
|
||||
return missing;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
currentVal = iter.next();
|
||||
}
|
||||
return relevantVal;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -57,6 +57,6 @@ public class DoubleValuesComparatorSource extends IndexFieldData.XFieldComparato
|
|||
dMissingValue = missingValue instanceof Number ? ((Number) missingValue).doubleValue() : Double.parseDouble(missingValue.toString());
|
||||
}
|
||||
|
||||
return new DoubleValuesComparator(indexFieldData, dMissingValue, numHits);
|
||||
return new DoubleValuesComparator(indexFieldData, dMissingValue, numHits, reversed);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@ import org.apache.lucene.index.AtomicReaderContext;
|
|||
import org.apache.lucene.search.FieldComparator;
|
||||
import org.elasticsearch.index.fielddata.FloatValues;
|
||||
import org.elasticsearch.index.fielddata.IndexNumericFieldData;
|
||||
import org.elasticsearch.index.fielddata.util.FloatArrayRef;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
|
@ -32,14 +33,16 @@ public class FloatValuesComparator extends FieldComparator<Float> {
|
|||
|
||||
private final IndexNumericFieldData indexFieldData;
|
||||
private final float missingValue;
|
||||
private final boolean reversed;
|
||||
|
||||
protected final float[] values;
|
||||
private final float[] values;
|
||||
private float bottom;
|
||||
private FloatValues readerValues;
|
||||
|
||||
public FloatValuesComparator(IndexNumericFieldData indexFieldData, float missingValue, int numHits) {
|
||||
public FloatValuesComparator(IndexNumericFieldData indexFieldData, float missingValue, int numHits, boolean reversed) {
|
||||
this.indexFieldData = indexFieldData;
|
||||
this.missingValue = missingValue;
|
||||
this.reversed = reversed;
|
||||
this.values = new float[numHits];
|
||||
}
|
||||
|
||||
|
@ -81,7 +84,10 @@ public class FloatValuesComparator extends FieldComparator<Float> {
|
|||
|
||||
@Override
|
||||
public FieldComparator<Float> setNextReader(AtomicReaderContext context) throws IOException {
|
||||
this.readerValues = indexFieldData.load(context).getFloatValues();
|
||||
readerValues = indexFieldData.load(context).getFloatValues();
|
||||
if (readerValues.isMultiValued()) {
|
||||
readerValues = new MultiValuedBytesWrapper(readerValues, reversed);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -102,4 +108,81 @@ public class FloatValuesComparator extends FieldComparator<Float> {
|
|||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
public static class FilteredByteValues implements FloatValues {
|
||||
|
||||
protected final FloatValues delegate;
|
||||
|
||||
public FilteredByteValues(FloatValues delegate) {
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
public boolean isMultiValued() {
|
||||
return delegate.isMultiValued();
|
||||
}
|
||||
|
||||
public boolean hasValue(int docId) {
|
||||
return delegate.hasValue(docId);
|
||||
}
|
||||
|
||||
public float getValue(int docId) {
|
||||
return delegate.getValue(docId);
|
||||
}
|
||||
|
||||
public float getValueMissing(int docId, float missingValue) {
|
||||
return delegate.getValueMissing(docId, missingValue);
|
||||
}
|
||||
|
||||
public FloatArrayRef getValues(int docId) {
|
||||
return delegate.getValues(docId);
|
||||
}
|
||||
|
||||
public Iter getIter(int docId) {
|
||||
return delegate.getIter(docId);
|
||||
}
|
||||
|
||||
public void forEachValueInDoc(int docId, ValueInDocProc proc) {
|
||||
delegate.forEachValueInDoc(docId, proc);
|
||||
}
|
||||
}
|
||||
|
||||
private static final class MultiValuedBytesWrapper extends FilteredByteValues {
|
||||
|
||||
private final boolean reversed;
|
||||
|
||||
public MultiValuedBytesWrapper(FloatValues delegate, boolean reversed) {
|
||||
super(delegate);
|
||||
this.reversed = reversed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getValueMissing(int docId, float missing) {
|
||||
FloatValues.Iter iter = delegate.getIter(docId);
|
||||
if (!iter.hasNext()) {
|
||||
return missing;
|
||||
}
|
||||
|
||||
float currentVal = iter.next();
|
||||
float relevantVal = currentVal;
|
||||
while (true) {
|
||||
int cmp = Float.compare(currentVal, relevantVal);
|
||||
if (reversed) {
|
||||
if (cmp > 0) {
|
||||
relevantVal = currentVal;
|
||||
}
|
||||
} else {
|
||||
if (cmp < 0) {
|
||||
relevantVal = currentVal;
|
||||
}
|
||||
}
|
||||
if (!iter.hasNext()) {
|
||||
break;
|
||||
}
|
||||
currentVal = iter.next();
|
||||
}
|
||||
return relevantVal;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -57,6 +57,6 @@ public class FloatValuesComparatorSource extends IndexFieldData.XFieldComparator
|
|||
dMissingValue = missingValue instanceof Number ? ((Number) missingValue).floatValue() : Float.parseFloat(missingValue.toString());
|
||||
}
|
||||
|
||||
return new FloatValuesComparator(indexFieldData, dMissingValue, numHits);
|
||||
return new FloatValuesComparator(indexFieldData, dMissingValue, numHits, reversed);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@ import org.apache.lucene.index.AtomicReaderContext;
|
|||
import org.apache.lucene.search.FieldComparator;
|
||||
import org.elasticsearch.index.fielddata.IndexNumericFieldData;
|
||||
import org.elasticsearch.index.fielddata.IntValues;
|
||||
import org.elasticsearch.index.fielddata.util.IntArrayRef;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
|
@ -32,14 +33,16 @@ public class IntValuesComparator extends FieldComparator<Integer> {
|
|||
|
||||
private final IndexNumericFieldData indexFieldData;
|
||||
private final int missingValue;
|
||||
private final boolean reversed;
|
||||
|
||||
protected final int[] values;
|
||||
private final int[] values;
|
||||
private int bottom;
|
||||
private IntValues readerValues;
|
||||
|
||||
public IntValuesComparator(IndexNumericFieldData indexFieldData, int missingValue, int numHits) {
|
||||
public IntValuesComparator(IndexNumericFieldData indexFieldData, int missingValue, int numHits, boolean reversed) {
|
||||
this.indexFieldData = indexFieldData;
|
||||
this.missingValue = missingValue;
|
||||
this.reversed = reversed;
|
||||
this.values = new int[numHits];
|
||||
}
|
||||
|
||||
|
@ -81,7 +84,10 @@ public class IntValuesComparator extends FieldComparator<Integer> {
|
|||
|
||||
@Override
|
||||
public FieldComparator<Integer> setNextReader(AtomicReaderContext context) throws IOException {
|
||||
this.readerValues = indexFieldData.load(context).getIntValues();
|
||||
readerValues = indexFieldData.load(context).getIntValues();
|
||||
if (readerValues.isMultiValued()) {
|
||||
readerValues = new MultiValuedBytesWrapper(readerValues, reversed);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -102,4 +108,80 @@ public class IntValuesComparator extends FieldComparator<Integer> {
|
|||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
public static class FilteredByteValues implements IntValues {
|
||||
|
||||
protected final IntValues delegate;
|
||||
|
||||
public FilteredByteValues(IntValues delegate) {
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
public boolean isMultiValued() {
|
||||
return delegate.isMultiValued();
|
||||
}
|
||||
|
||||
public boolean hasValue(int docId) {
|
||||
return delegate.hasValue(docId);
|
||||
}
|
||||
|
||||
public int getValue(int docId) {
|
||||
return delegate.getValue(docId);
|
||||
}
|
||||
|
||||
public int getValueMissing(int docId, int missingValue) {
|
||||
return delegate.getValueMissing(docId, missingValue);
|
||||
}
|
||||
|
||||
public IntArrayRef getValues(int docId) {
|
||||
return delegate.getValues(docId);
|
||||
}
|
||||
|
||||
public Iter getIter(int docId) {
|
||||
return delegate.getIter(docId);
|
||||
}
|
||||
|
||||
public void forEachValueInDoc(int docId, ValueInDocProc proc) {
|
||||
delegate.forEachValueInDoc(docId, proc);
|
||||
}
|
||||
}
|
||||
|
||||
private static final class MultiValuedBytesWrapper extends FilteredByteValues {
|
||||
|
||||
private final boolean reversed;
|
||||
|
||||
public MultiValuedBytesWrapper(IntValues delegate, boolean reversed) {
|
||||
super(delegate);
|
||||
this.reversed = reversed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getValueMissing(int docId, int missing) {
|
||||
IntValues.Iter iter = delegate.getIter(docId);
|
||||
if (!iter.hasNext()) {
|
||||
return missing;
|
||||
}
|
||||
|
||||
int currentVal = iter.next();
|
||||
int relevantVal = currentVal;
|
||||
while (true) {
|
||||
if (reversed) {
|
||||
if (currentVal > relevantVal) {
|
||||
relevantVal = currentVal;
|
||||
}
|
||||
} else {
|
||||
if (currentVal < relevantVal) {
|
||||
relevantVal = currentVal;
|
||||
}
|
||||
}
|
||||
if (!iter.hasNext()) {
|
||||
break;
|
||||
}
|
||||
currentVal = iter.next();
|
||||
}
|
||||
return relevantVal;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -57,6 +57,6 @@ public class IntValuesComparatorSource extends IndexFieldData.XFieldComparatorSo
|
|||
dMissingValue = missingValue instanceof Number ? ((Number) missingValue).intValue() : Integer.parseInt(missingValue.toString());
|
||||
}
|
||||
|
||||
return new IntValuesComparator(indexFieldData, dMissingValue, numHits);
|
||||
return new IntValuesComparator(indexFieldData, dMissingValue, numHits, reversed);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@ 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 org.elasticsearch.index.fielddata.util.LongArrayRef;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
|
@ -32,15 +33,17 @@ public class LongValuesComparator extends FieldComparator<Long> {
|
|||
|
||||
private final IndexNumericFieldData indexFieldData;
|
||||
private final long missingValue;
|
||||
private final boolean reversed;
|
||||
|
||||
protected final long[] values;
|
||||
private long bottom;
|
||||
private final long[] values;
|
||||
private LongValues readerValues;
|
||||
private long bottom;
|
||||
|
||||
public LongValuesComparator(IndexNumericFieldData indexFieldData, long missingValue, int numHits) {
|
||||
public LongValuesComparator(IndexNumericFieldData indexFieldData, long missingValue, int numHits, boolean reversed) {
|
||||
this.indexFieldData = indexFieldData;
|
||||
this.missingValue = missingValue;
|
||||
this.values = new long[numHits];
|
||||
this.reversed = reversed;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -64,7 +67,6 @@ public class LongValuesComparator extends FieldComparator<Long> {
|
|||
@Override
|
||||
public int compareBottom(int doc) throws IOException {
|
||||
long v2 = readerValues.getValueMissing(doc, missingValue);
|
||||
|
||||
if (bottom > v2) {
|
||||
return 1;
|
||||
} else if (bottom < v2) {
|
||||
|
@ -81,7 +83,10 @@ public class LongValuesComparator extends FieldComparator<Long> {
|
|||
|
||||
@Override
|
||||
public FieldComparator<Long> setNextReader(AtomicReaderContext context) throws IOException {
|
||||
this.readerValues = indexFieldData.load(context).getLongValues();
|
||||
readerValues = indexFieldData.load(context).getLongValues();
|
||||
if (readerValues.isMultiValued()) {
|
||||
readerValues = new MultiValuedBytesWrapper(readerValues, reversed);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -102,4 +107,96 @@ public class LongValuesComparator extends FieldComparator<Long> {
|
|||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// THIS SHOULD GO INTO the fielddata package
|
||||
public static class FilteredByteValues implements LongValues {
|
||||
|
||||
protected final LongValues delegate;
|
||||
|
||||
public FilteredByteValues(LongValues delegate) {
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
public boolean isMultiValued() {
|
||||
return delegate.isMultiValued();
|
||||
}
|
||||
|
||||
public boolean hasValue(int docId) {
|
||||
return delegate.hasValue(docId);
|
||||
}
|
||||
|
||||
public long getValue(int docId) {
|
||||
return delegate.getValue(docId);
|
||||
}
|
||||
|
||||
public long getValueMissing(int docId, long missingValue) {
|
||||
return delegate.getValueMissing(docId, missingValue);
|
||||
}
|
||||
|
||||
public LongArrayRef getValues(int docId) {
|
||||
return delegate.getValues(docId);
|
||||
}
|
||||
|
||||
public Iter getIter(int docId) {
|
||||
return delegate.getIter(docId);
|
||||
}
|
||||
|
||||
public void forEachValueInDoc(int docId, ValueInDocProc proc) {
|
||||
delegate.forEachValueInDoc(docId, proc);
|
||||
}
|
||||
}
|
||||
|
||||
private static final class MultiValuedBytesWrapper extends FilteredByteValues {
|
||||
|
||||
private final boolean reversed;
|
||||
|
||||
public MultiValuedBytesWrapper(LongValues delegate, boolean reversed) {
|
||||
super(delegate);
|
||||
this.reversed = reversed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getValueMissing(int docId, long missing) {
|
||||
LongValues.Iter iter = delegate.getIter(docId);
|
||||
if (!iter.hasNext()) {
|
||||
return missing;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
currentVal = iter.next();
|
||||
}
|
||||
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
|
||||
// For example a impl that read values from the _source field might not read values in order)
|
||||
/*if (reversed) {
|
||||
// Would be nice if there is a way to get highest value from LongValues. The values are sorted anyway.
|
||||
LongArrayRef ref = readerValues.getValues(doc);
|
||||
if (ref.isEmpty()) {
|
||||
return missing;
|
||||
} else {
|
||||
return ref.values[ref.end - 1]; // last element is the highest value.
|
||||
}
|
||||
} else {
|
||||
return readerValues.getValueMissing(doc, missing); // returns lowest
|
||||
}*/
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -57,6 +57,6 @@ public class LongValuesComparatorSource extends IndexFieldData.XFieldComparatorS
|
|||
dMissingValue = missingValue instanceof Number ? ((Number) missingValue).longValue() : Long.parseLong(missingValue.toString());
|
||||
}
|
||||
|
||||
return new LongValuesComparator(indexFieldData, dMissingValue, numHits);
|
||||
return new LongValuesComparator(indexFieldData, dMissingValue, numHits, reversed);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@ import org.apache.lucene.index.AtomicReaderContext;
|
|||
import org.apache.lucene.search.FieldComparator;
|
||||
import org.elasticsearch.index.fielddata.IndexNumericFieldData;
|
||||
import org.elasticsearch.index.fielddata.ShortValues;
|
||||
import org.elasticsearch.index.fielddata.util.ShortArrayRef;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
|
@ -32,14 +33,16 @@ public class ShortValuesComparator extends FieldComparator<Short> {
|
|||
|
||||
private final IndexNumericFieldData indexFieldData;
|
||||
private final short missingValue;
|
||||
private final boolean reversed;
|
||||
|
||||
protected final short[] values;
|
||||
private final short[] values;
|
||||
private short bottom;
|
||||
private ShortValues readerValues;
|
||||
|
||||
public ShortValuesComparator(IndexNumericFieldData indexFieldData, short missingValue, int numHits) {
|
||||
public ShortValuesComparator(IndexNumericFieldData indexFieldData, short missingValue, int numHits, boolean reversed) {
|
||||
this.indexFieldData = indexFieldData;
|
||||
this.missingValue = missingValue;
|
||||
this.reversed = reversed;
|
||||
this.values = new short[numHits];
|
||||
}
|
||||
|
||||
|
@ -81,7 +84,10 @@ public class ShortValuesComparator extends FieldComparator<Short> {
|
|||
|
||||
@Override
|
||||
public FieldComparator<Short> setNextReader(AtomicReaderContext context) throws IOException {
|
||||
this.readerValues = indexFieldData.load(context).getShortValues();
|
||||
readerValues = indexFieldData.load(context).getShortValues();
|
||||
if (readerValues.isMultiValued()) {
|
||||
readerValues = new MultiValuedBytesWrapper(readerValues, reversed);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -102,4 +108,80 @@ public class ShortValuesComparator extends FieldComparator<Short> {
|
|||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
public static class FilteredByteValues implements ShortValues {
|
||||
|
||||
protected final ShortValues delegate;
|
||||
|
||||
public FilteredByteValues(ShortValues delegate) {
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
public boolean isMultiValued() {
|
||||
return delegate.isMultiValued();
|
||||
}
|
||||
|
||||
public boolean hasValue(int docId) {
|
||||
return delegate.hasValue(docId);
|
||||
}
|
||||
|
||||
public short getValue(int docId) {
|
||||
return delegate.getValue(docId);
|
||||
}
|
||||
|
||||
public short getValueMissing(int docId, short missingValue) {
|
||||
return delegate.getValueMissing(docId, missingValue);
|
||||
}
|
||||
|
||||
public ShortArrayRef getValues(int docId) {
|
||||
return delegate.getValues(docId);
|
||||
}
|
||||
|
||||
public Iter getIter(int docId) {
|
||||
return delegate.getIter(docId);
|
||||
}
|
||||
|
||||
public void forEachValueInDoc(int docId, ValueInDocProc proc) {
|
||||
delegate.forEachValueInDoc(docId, proc);
|
||||
}
|
||||
}
|
||||
|
||||
private static final class MultiValuedBytesWrapper extends FilteredByteValues {
|
||||
|
||||
private final boolean reversed;
|
||||
|
||||
public MultiValuedBytesWrapper(ShortValues delegate, boolean reversed) {
|
||||
super(delegate);
|
||||
this.reversed = reversed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public short getValueMissing(int docId, short missing) {
|
||||
ShortValues.Iter iter = delegate.getIter(docId);
|
||||
if (!iter.hasNext()) {
|
||||
return missing;
|
||||
}
|
||||
|
||||
short currentVal = iter.next();
|
||||
short relevantVal = currentVal;
|
||||
while (true) {
|
||||
if (reversed) {
|
||||
if (currentVal > relevantVal) {
|
||||
relevantVal = currentVal;
|
||||
}
|
||||
} else {
|
||||
if (currentVal < relevantVal) {
|
||||
relevantVal = currentVal;
|
||||
}
|
||||
}
|
||||
if (!iter.hasNext()) {
|
||||
break;
|
||||
}
|
||||
currentVal = iter.next();
|
||||
}
|
||||
return relevantVal;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -57,6 +57,6 @@ public class ShortValuesComparatorSource extends IndexFieldData.XFieldComparator
|
|||
dMissingValue = missingValue instanceof Number ? ((Number) missingValue).shortValue() : Short.parseShort(missingValue.toString());
|
||||
}
|
||||
|
||||
return new ShortValuesComparator(indexFieldData, dMissingValue, numHits);
|
||||
return new ShortValuesComparator(indexFieldData, dMissingValue, numHits, reversed);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -64,7 +64,7 @@ public class ByteArrayRef extends AbstractList<Byte> implements RandomAccess {
|
|||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return size() != 0;
|
||||
return size() == 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -53,6 +53,10 @@ public class BytesRefArrayRef {
|
|||
}
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
return size() == 0;
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return end - start;
|
||||
}
|
||||
|
|
|
@ -64,7 +64,7 @@ public class DoubleArrayRef extends AbstractList<Double> implements RandomAccess
|
|||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return size() != 0;
|
||||
return size() == 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -64,7 +64,7 @@ public class FloatArrayRef extends AbstractList<Float> implements RandomAccess {
|
|||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return size() != 0;
|
||||
return size() == 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -70,7 +70,7 @@ public class IntArrayRef extends AbstractList<Integer> implements RandomAccess {
|
|||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return size() != 0;
|
||||
return size() == 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -64,7 +64,7 @@ public class LongArrayRef extends AbstractList<Long> implements RandomAccess {
|
|||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return size() != 0;
|
||||
return size() == 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -64,7 +64,7 @@ public class ShortArrayRef extends AbstractList<Short> implements RandomAccess {
|
|||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return size() != 0;
|
||||
return size() == 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -163,6 +163,16 @@ public class SortParseElement implements SearchParseElement {
|
|||
}
|
||||
throw new SearchParseException(context, "No mapping found for [" + fieldName + "] in order to sort on");
|
||||
}
|
||||
|
||||
// Enable when we also know how to detect fields that do tokenize, but only emit one token
|
||||
/*if (fieldMapper instanceof StringFieldMapper) {
|
||||
StringFieldMapper stringFieldMapper = (StringFieldMapper) fieldMapper;
|
||||
if (stringFieldMapper.fieldType().tokenized()) {
|
||||
// Fail early
|
||||
throw new SearchParseException(context, "Can't sort on tokenized string field[" + fieldName + "]");
|
||||
}
|
||||
}*/
|
||||
|
||||
sortFields.add(new SortField(fieldMapper.names().indexName(), context.fieldData().getForField(fieldMapper).comparatorSource(missing), reverse));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -604,4 +604,69 @@ public class SimpleSortTests extends AbstractNodesTests {
|
|||
|
||||
assertThat(searchResponse.failedShards(), equalTo(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSortLongMVField() throws Exception {
|
||||
try {
|
||||
client.admin().indices().prepareDelete("test").execute().actionGet();
|
||||
} catch (Exception e) {
|
||||
// ignore
|
||||
}
|
||||
client.admin().indices().prepareCreate("test")
|
||||
.setSettings(ImmutableSettings.settingsBuilder().put("index.number_of_shards", 1).put("index.number_of_replicas", 0))
|
||||
.addMapping("type1", XContentFactory.jsonBuilder().startObject().startObject("type1").startObject("properties")
|
||||
.startObject("long_values").field("type", "long").endObject()
|
||||
.endObject().endObject().endObject())
|
||||
.execute().actionGet();
|
||||
client.admin().cluster().prepareHealth().setWaitForGreenStatus().execute().actionGet();
|
||||
|
||||
client.prepareIndex("test", "type1", Integer.toString(1)).setSource(jsonBuilder().startObject()
|
||||
.array("long_values", 1l, 5l, 10l, 8l)
|
||||
.endObject()).execute().actionGet();
|
||||
client.prepareIndex("test", "type1", Integer.toString(2)).setSource(jsonBuilder().startObject()
|
||||
.array("long_values", 11l, 15l, 20l, 7l)
|
||||
.endObject()).execute().actionGet();
|
||||
client.prepareIndex("test", "type1", Integer.toString(3)).setSource(jsonBuilder().startObject()
|
||||
.array("long_values", 2l, 1l, 3l, -4l)
|
||||
.endObject()).execute().actionGet();
|
||||
|
||||
client.admin().indices().prepareRefresh().execute().actionGet();
|
||||
|
||||
SearchResponse searchResponse = client.prepareSearch()
|
||||
.setQuery(matchAllQuery())
|
||||
.setSize(10)
|
||||
.addSort("long_values", SortOrder.ASC)
|
||||
.execute().actionGet();
|
||||
|
||||
assertThat(searchResponse.hits().getTotalHits(), equalTo(3l));
|
||||
assertThat(searchResponse.hits().hits().length, equalTo(3));
|
||||
|
||||
assertThat(searchResponse.hits().getAt(0).id(), equalTo(Integer.toString(3)));
|
||||
assertThat(((Number) searchResponse.hits().getAt(0).sortValues()[0]).longValue(), equalTo(-4l));
|
||||
|
||||
assertThat(searchResponse.hits().getAt(1).id(), equalTo(Integer.toString(1)));
|
||||
assertThat(((Number) searchResponse.hits().getAt(1).sortValues()[0]).longValue(), equalTo(1l));
|
||||
|
||||
assertThat(searchResponse.hits().getAt(2).id(), equalTo(Integer.toString(2)));
|
||||
assertThat(((Number) searchResponse.hits().getAt(2).sortValues()[0]).longValue(), equalTo(7l));
|
||||
|
||||
searchResponse = client.prepareSearch()
|
||||
.setQuery(matchAllQuery())
|
||||
.setSize(10)
|
||||
.addSort("long_values", SortOrder.DESC)
|
||||
.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(20l));
|
||||
|
||||
assertThat(searchResponse.hits().getAt(1).id(), equalTo(Integer.toString(1)));
|
||||
assertThat(((Number) searchResponse.hits().getAt(1).sortValues()[0]).longValue(), equalTo(10l));
|
||||
|
||||
assertThat(searchResponse.hits().getAt(2).id(), equalTo(Integer.toString(3)));
|
||||
assertThat(((Number) searchResponse.hits().getAt(2).sortValues()[0]).longValue(), equalTo(3l));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -30,4 +30,5 @@ public class ByteFieldDataTests extends IntFieldDataTests {
|
|||
return new FieldDataType("byte");
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -124,4 +124,56 @@ public class DoubleFieldDataTests extends NumericFieldDataTests {
|
|||
d.add(new DoubleField("value", 3.0f, Field.Store.NO));
|
||||
writer.addDocument(d);
|
||||
}
|
||||
|
||||
protected void fillExtendedMvSet() throws Exception {
|
||||
Document d = new Document();
|
||||
d.add(new StringField("_id", "1", Field.Store.NO));
|
||||
d.add(new DoubleField("value", 2, Field.Store.NO));
|
||||
d.add(new DoubleField("value", 4, Field.Store.NO));
|
||||
writer.addDocument(d);
|
||||
|
||||
d = new Document();
|
||||
d.add(new StringField("_id", "2", Field.Store.NO));
|
||||
writer.addDocument(d);
|
||||
|
||||
d = new Document();
|
||||
d.add(new StringField("_id", "3", Field.Store.NO));
|
||||
d.add(new DoubleField("value", 3, Field.Store.NO));
|
||||
writer.addDocument(d);
|
||||
writer.commit();
|
||||
|
||||
d = new Document();
|
||||
d.add(new StringField("_id", "4", Field.Store.NO));
|
||||
d.add(new DoubleField("value", 4, Field.Store.NO));
|
||||
d.add(new DoubleField("value", 5, Field.Store.NO));
|
||||
d.add(new DoubleField("value", 6, Field.Store.NO));
|
||||
writer.addDocument(d);
|
||||
|
||||
d = new Document();
|
||||
d.add(new StringField("_id", "5", Field.Store.NO));
|
||||
d.add(new DoubleField("value", 6, Field.Store.NO));
|
||||
d.add(new DoubleField("value", 7, Field.Store.NO));
|
||||
d.add(new DoubleField("value", 8, Field.Store.NO));
|
||||
writer.addDocument(d);
|
||||
|
||||
d = new Document();
|
||||
d.add(new StringField("_id", "6", Field.Store.NO));
|
||||
writer.addDocument(d);
|
||||
|
||||
d = new Document();
|
||||
d.add(new StringField("_id", "7", Field.Store.NO));
|
||||
d.add(new DoubleField("value", 8, Field.Store.NO));
|
||||
d.add(new DoubleField("value", 9, Field.Store.NO));
|
||||
d.add(new DoubleField("value", 10, Field.Store.NO));
|
||||
writer.addDocument(d);
|
||||
writer.commit();
|
||||
|
||||
d = new Document();
|
||||
d.add(new StringField("_id", "8", Field.Store.NO));
|
||||
d.add(new DoubleField("value", -8, Field.Store.NO));
|
||||
d.add(new DoubleField("value", -9, Field.Store.NO));
|
||||
d.add(new DoubleField("value", -10, Field.Store.NO));
|
||||
writer.addDocument(d);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -124,4 +124,56 @@ public class FloatFieldDataTests extends NumericFieldDataTests {
|
|||
d.add(new FloatField("value", 3.0f, Field.Store.NO));
|
||||
writer.addDocument(d);
|
||||
}
|
||||
|
||||
protected void fillExtendedMvSet() throws Exception {
|
||||
Document d = new Document();
|
||||
d.add(new StringField("_id", "1", Field.Store.NO));
|
||||
d.add(new FloatField("value", 2, Field.Store.NO));
|
||||
d.add(new FloatField("value", 4, Field.Store.NO));
|
||||
writer.addDocument(d);
|
||||
|
||||
d = new Document();
|
||||
d.add(new StringField("_id", "2", Field.Store.NO));
|
||||
writer.addDocument(d);
|
||||
|
||||
d = new Document();
|
||||
d.add(new StringField("_id", "3", Field.Store.NO));
|
||||
d.add(new FloatField("value", 3, Field.Store.NO));
|
||||
writer.addDocument(d);
|
||||
writer.commit();
|
||||
|
||||
d = new Document();
|
||||
d.add(new StringField("_id", "4", Field.Store.NO));
|
||||
d.add(new FloatField("value", 4, Field.Store.NO));
|
||||
d.add(new FloatField("value", 5, Field.Store.NO));
|
||||
d.add(new FloatField("value", 6, Field.Store.NO));
|
||||
writer.addDocument(d);
|
||||
|
||||
d = new Document();
|
||||
d.add(new StringField("_id", "5", Field.Store.NO));
|
||||
d.add(new FloatField("value", 6, Field.Store.NO));
|
||||
d.add(new FloatField("value", 7, Field.Store.NO));
|
||||
d.add(new FloatField("value", 8, Field.Store.NO));
|
||||
writer.addDocument(d);
|
||||
|
||||
d = new Document();
|
||||
d.add(new StringField("_id", "6", Field.Store.NO));
|
||||
writer.addDocument(d);
|
||||
|
||||
d = new Document();
|
||||
d.add(new StringField("_id", "7", Field.Store.NO));
|
||||
d.add(new FloatField("value", 8, Field.Store.NO));
|
||||
d.add(new FloatField("value", 9, Field.Store.NO));
|
||||
d.add(new FloatField("value", 10, Field.Store.NO));
|
||||
writer.addDocument(d);
|
||||
writer.commit();
|
||||
|
||||
d = new Document();
|
||||
d.add(new StringField("_id", "8", Field.Store.NO));
|
||||
d.add(new FloatField("value", -8, Field.Store.NO));
|
||||
d.add(new FloatField("value", -9, Field.Store.NO));
|
||||
d.add(new FloatField("value", -10, Field.Store.NO));
|
||||
writer.addDocument(d);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -19,7 +19,10 @@
|
|||
|
||||
package org.elasticsearch.test.unit.index.fielddata;
|
||||
|
||||
import org.apache.lucene.document.*;
|
||||
import org.apache.lucene.document.Document;
|
||||
import org.apache.lucene.document.Field;
|
||||
import org.apache.lucene.document.IntField;
|
||||
import org.apache.lucene.document.StringField;
|
||||
import org.elasticsearch.index.fielddata.FieldDataType;
|
||||
|
||||
/**
|
||||
|
@ -104,4 +107,56 @@ public class IntFieldDataTests extends NumericFieldDataTests {
|
|||
d.add(new IntField("value", 3, Field.Store.NO));
|
||||
writer.addDocument(d);
|
||||
}
|
||||
|
||||
protected void fillExtendedMvSet() throws Exception {
|
||||
Document d = new Document();
|
||||
d.add(new StringField("_id", "1", Field.Store.NO));
|
||||
d.add(new IntField("value", 2, Field.Store.NO));
|
||||
d.add(new IntField("value", 4, Field.Store.NO));
|
||||
writer.addDocument(d);
|
||||
|
||||
d = new Document();
|
||||
d.add(new StringField("_id", "2", Field.Store.NO));
|
||||
writer.addDocument(d);
|
||||
|
||||
d = new Document();
|
||||
d.add(new StringField("_id", "3", Field.Store.NO));
|
||||
d.add(new IntField("value", 3, Field.Store.NO));
|
||||
writer.addDocument(d);
|
||||
writer.commit();
|
||||
|
||||
d = new Document();
|
||||
d.add(new StringField("_id", "4", Field.Store.NO));
|
||||
d.add(new IntField("value", 4, Field.Store.NO));
|
||||
d.add(new IntField("value", 5, Field.Store.NO));
|
||||
d.add(new IntField("value", 6, Field.Store.NO));
|
||||
writer.addDocument(d);
|
||||
|
||||
d = new Document();
|
||||
d.add(new StringField("_id", "5", Field.Store.NO));
|
||||
d.add(new IntField("value", 6, Field.Store.NO));
|
||||
d.add(new IntField("value", 7, Field.Store.NO));
|
||||
d.add(new IntField("value", 8, Field.Store.NO));
|
||||
writer.addDocument(d);
|
||||
|
||||
d = new Document();
|
||||
d.add(new StringField("_id", "6", Field.Store.NO));
|
||||
writer.addDocument(d);
|
||||
|
||||
d = new Document();
|
||||
d.add(new StringField("_id", "7", Field.Store.NO));
|
||||
d.add(new IntField("value", 8, Field.Store.NO));
|
||||
d.add(new IntField("value", 9, Field.Store.NO));
|
||||
d.add(new IntField("value", 10, Field.Store.NO));
|
||||
writer.addDocument(d);
|
||||
writer.commit();
|
||||
|
||||
d = new Document();
|
||||
d.add(new StringField("_id", "8", Field.Store.NO));
|
||||
d.add(new IntField("value", -8, Field.Store.NO));
|
||||
d.add(new IntField("value", -9, Field.Store.NO));
|
||||
d.add(new IntField("value", -10, Field.Store.NO));
|
||||
writer.addDocument(d);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -107,4 +107,56 @@ public class LongFieldDataTests extends NumericFieldDataTests {
|
|||
d.add(new LongField("value", 3, Field.Store.NO));
|
||||
writer.addDocument(d);
|
||||
}
|
||||
|
||||
protected void fillExtendedMvSet() throws Exception {
|
||||
Document d = new Document();
|
||||
d.add(new StringField("_id", "1", Field.Store.NO));
|
||||
d.add(new LongField("value", 2, Field.Store.NO));
|
||||
d.add(new LongField("value", 4, Field.Store.NO));
|
||||
writer.addDocument(d);
|
||||
|
||||
d = new Document();
|
||||
d.add(new StringField("_id", "2", Field.Store.NO));
|
||||
writer.addDocument(d);
|
||||
|
||||
d = new Document();
|
||||
d.add(new StringField("_id", "3", Field.Store.NO));
|
||||
d.add(new LongField("value", 3, Field.Store.NO));
|
||||
writer.addDocument(d);
|
||||
writer.commit();
|
||||
|
||||
d = new Document();
|
||||
d.add(new StringField("_id", "4", Field.Store.NO));
|
||||
d.add(new LongField("value", 4, Field.Store.NO));
|
||||
d.add(new LongField("value", 5, Field.Store.NO));
|
||||
d.add(new LongField("value", 6, Field.Store.NO));
|
||||
writer.addDocument(d);
|
||||
|
||||
d = new Document();
|
||||
d.add(new StringField("_id", "5", Field.Store.NO));
|
||||
d.add(new LongField("value", 6, Field.Store.NO));
|
||||
d.add(new LongField("value", 7, Field.Store.NO));
|
||||
d.add(new LongField("value", 8, Field.Store.NO));
|
||||
writer.addDocument(d);
|
||||
|
||||
d = new Document();
|
||||
d.add(new StringField("_id", "6", Field.Store.NO));
|
||||
writer.addDocument(d);
|
||||
|
||||
d = new Document();
|
||||
d.add(new StringField("_id", "7", Field.Store.NO));
|
||||
d.add(new LongField("value", 8, Field.Store.NO));
|
||||
d.add(new LongField("value", 9, Field.Store.NO));
|
||||
d.add(new LongField("value", 10, Field.Store.NO));
|
||||
writer.addDocument(d);
|
||||
writer.commit();
|
||||
|
||||
d = new Document();
|
||||
d.add(new StringField("_id", "8", Field.Store.NO));
|
||||
d.add(new LongField("value", -8, Field.Store.NO));
|
||||
d.add(new LongField("value", -9, Field.Store.NO));
|
||||
d.add(new LongField("value", -10, Field.Store.NO));
|
||||
writer.addDocument(d);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@ package org.elasticsearch.test.unit.index.fielddata;
|
|||
import org.apache.lucene.document.Document;
|
||||
import org.apache.lucene.document.Field;
|
||||
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.*;
|
||||
|
@ -1489,4 +1490,106 @@ public abstract class NumericFieldDataTests extends StringFieldDataTests {
|
|||
d.add(new StringField("_id", "3", Field.Store.NO));
|
||||
writer.addDocument(d);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSortMultiValuesFields() throws Exception {
|
||||
fillExtendedMvSet();
|
||||
IndexFieldData indexFieldData = getForField("value");
|
||||
|
||||
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
|
||||
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(-10));
|
||||
assertThat(topDocs.scoreDocs[1].doc, equalTo(0));
|
||||
assertThat(((Number) ((FieldDoc) topDocs.scoreDocs[1]).fields[0]).intValue(), equalTo(2));
|
||||
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(4));
|
||||
assertThat(topDocs.scoreDocs[4].doc, equalTo(4));
|
||||
assertThat(((Number) ((FieldDoc) topDocs.scoreDocs[4]).fields[0]).intValue(), equalTo(6));
|
||||
assertThat(topDocs.scoreDocs[5].doc, equalTo(6));
|
||||
assertThat(((Number) ((FieldDoc) topDocs.scoreDocs[5]).fields[0]).intValue(), equalTo(8));
|
||||
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(null), 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(10));
|
||||
assertThat(topDocs.scoreDocs[1].doc, equalTo(4));
|
||||
assertThat(((Number) ((FieldDoc) topDocs.scoreDocs[1]).fields[0]).intValue(), equalTo(8));
|
||||
assertThat(topDocs.scoreDocs[2].doc, equalTo(3));
|
||||
assertThat(((Number) ((FieldDoc) topDocs.scoreDocs[2]).fields[0]).intValue(), equalTo(6));
|
||||
assertThat(topDocs.scoreDocs[3].doc, equalTo(0));
|
||||
assertThat(((Number) ((FieldDoc) topDocs.scoreDocs[3]).fields[0]).intValue(), equalTo(4));
|
||||
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(-8));
|
||||
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"))));
|
||||
assertThat(topDocs.totalHits, equalTo(8));
|
||||
assertThat(topDocs.scoreDocs.length, equalTo(8));
|
||||
assertThat(topDocs.scoreDocs[0].doc, equalTo(1));
|
||||
assertThat(topDocs.scoreDocs[1].doc, equalTo(5));
|
||||
assertThat(topDocs.scoreDocs[2].doc, equalTo(7));
|
||||
assertThat(topDocs.scoreDocs[3].doc, equalTo(0));
|
||||
assertThat(topDocs.scoreDocs[4].doc, equalTo(2));
|
||||
assertThat(topDocs.scoreDocs[5].doc, equalTo(3));
|
||||
assertThat(topDocs.scoreDocs[6].doc, equalTo(4));
|
||||
assertThat(topDocs.scoreDocs[7].doc, equalTo(6));
|
||||
|
||||
topDocs = searcher.search(new MatchAllDocsQuery(), 10,
|
||||
new Sort(new SortField("value", indexFieldData.comparatorSource("_first"), true)));
|
||||
assertThat(topDocs.totalHits, equalTo(8));
|
||||
assertThat(topDocs.scoreDocs.length, equalTo(8));
|
||||
assertThat(topDocs.scoreDocs[0].doc, equalTo(1));
|
||||
assertThat(topDocs.scoreDocs[1].doc, equalTo(5));
|
||||
assertThat(topDocs.scoreDocs[2].doc, equalTo(6));
|
||||
assertThat(topDocs.scoreDocs[3].doc, equalTo(4));
|
||||
assertThat(topDocs.scoreDocs[4].doc, equalTo(3));
|
||||
assertThat(topDocs.scoreDocs[5].doc, equalTo(0));
|
||||
assertThat(topDocs.scoreDocs[6].doc, equalTo(2));
|
||||
assertThat(topDocs.scoreDocs[7].doc, equalTo(7));
|
||||
|
||||
topDocs = searcher.search(new MatchAllDocsQuery(), 10,
|
||||
new Sort(new SortField("value", indexFieldData.comparatorSource("-9"))));
|
||||
assertThat(topDocs.totalHits, equalTo(8));
|
||||
assertThat(topDocs.scoreDocs.length, equalTo(8));
|
||||
assertThat(topDocs.scoreDocs[0].doc, equalTo(7));
|
||||
assertThat(topDocs.scoreDocs[1].doc, equalTo(1));
|
||||
assertThat(topDocs.scoreDocs[2].doc, equalTo(5));
|
||||
assertThat(topDocs.scoreDocs[3].doc, equalTo(0));
|
||||
assertThat(topDocs.scoreDocs[4].doc, equalTo(2));
|
||||
assertThat(topDocs.scoreDocs[5].doc, equalTo(3));
|
||||
assertThat(topDocs.scoreDocs[6].doc, equalTo(4));
|
||||
assertThat(topDocs.scoreDocs[7].doc, equalTo(6));
|
||||
|
||||
topDocs = searcher.search(new MatchAllDocsQuery(), 10,
|
||||
new Sort(new SortField("value", indexFieldData.comparatorSource("9"), true)));
|
||||
assertThat(topDocs.totalHits, equalTo(8));
|
||||
assertThat(topDocs.scoreDocs.length, equalTo(8));
|
||||
assertThat(topDocs.scoreDocs[0].doc, equalTo(6));
|
||||
assertThat(topDocs.scoreDocs[1].doc, equalTo(1));
|
||||
assertThat(topDocs.scoreDocs[2].doc, equalTo(5));
|
||||
assertThat(topDocs.scoreDocs[3].doc, equalTo(4));
|
||||
assertThat(topDocs.scoreDocs[4].doc, equalTo(3));
|
||||
assertThat(topDocs.scoreDocs[5].doc, equalTo(0));
|
||||
assertThat(topDocs.scoreDocs[6].doc, equalTo(2));
|
||||
assertThat(topDocs.scoreDocs[7].doc, equalTo(7));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@ import org.apache.lucene.document.Document;
|
|||
import org.apache.lucene.document.Field;
|
||||
import org.apache.lucene.document.StringField;
|
||||
import org.apache.lucene.index.AtomicReaderContext;
|
||||
import org.apache.lucene.index.DirectoryReader;
|
||||
import org.apache.lucene.search.*;
|
||||
import org.apache.lucene.util.BytesRef;
|
||||
import org.elasticsearch.common.lucene.HashedBytesRef;
|
||||
|
@ -358,6 +359,7 @@ public abstract class StringFieldDataTests extends AbstractFieldDataTests {
|
|||
d.add(new StringField("_id", "2", Field.Store.NO));
|
||||
d.add(new StringField("value", "1", Field.Store.NO));
|
||||
writer.addDocument(d);
|
||||
writer.commit(); // TODO: Have tests with more docs for sorting
|
||||
|
||||
d = new Document();
|
||||
d.add(new StringField("_id", "3", Field.Store.NO));
|
||||
|
@ -483,6 +485,21 @@ public abstract class StringFieldDataTests extends AbstractFieldDataTests {
|
|||
stringValues.forEachValueInDoc(0, new StringValuesVerifierProc(0).addExpected(two()).addExpected(four()));
|
||||
stringValues.forEachValueInDoc(1, new StringValuesVerifierProc(1).addExpected(one()));
|
||||
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))));
|
||||
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)));
|
||||
assertThat(topDocs.totalHits, equalTo(3));
|
||||
assertThat(topDocs.scoreDocs.length, equalTo(3));
|
||||
assertThat(topDocs.scoreDocs[0].doc, equalTo(0));
|
||||
assertThat(topDocs.scoreDocs[1].doc, equalTo(2));
|
||||
assertThat(topDocs.scoreDocs[2].doc, equalTo(1));
|
||||
}
|
||||
|
||||
protected void fillMultiValueWithMissing() throws Exception {
|
||||
|
@ -745,4 +762,105 @@ public abstract class StringFieldDataTests extends AbstractFieldDataTests {
|
|||
d.add(new StringField("_id", "3", Field.Store.NO));
|
||||
writer.addDocument(d);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSortMultiValuesFields() throws Exception {
|
||||
fillExtendedMvSet();
|
||||
IndexFieldData indexFieldData = getForField("value");
|
||||
|
||||
IndexSearcher searcher = new IndexSearcher(DirectoryReader.open(writer, true));
|
||||
TopFieldDocs topDocs = searcher.search(new MatchAllDocsQuery(), 10,
|
||||
new Sort(new SortField("value", indexFieldData.comparatorSource(null))));
|
||||
assertThat(topDocs.totalHits, equalTo(8));
|
||||
assertThat(topDocs.scoreDocs.length, equalTo(8));
|
||||
assertThat(topDocs.scoreDocs[0].doc, equalTo(1));
|
||||
assertThat(((FieldDoc) topDocs.scoreDocs[0]).fields[0], equalTo(null));
|
||||
assertThat(topDocs.scoreDocs[1].doc, equalTo(5));
|
||||
assertThat(((FieldDoc) topDocs.scoreDocs[1]).fields[0], equalTo(null));
|
||||
assertThat(topDocs.scoreDocs[2].doc, equalTo(7));
|
||||
assertThat(((BytesRef) ((FieldDoc) topDocs.scoreDocs[2]).fields[0]).utf8ToString(), equalTo("!08"));
|
||||
assertThat(topDocs.scoreDocs[3].doc, equalTo(0));
|
||||
assertThat(((BytesRef) ((FieldDoc) topDocs.scoreDocs[3]).fields[0]).utf8ToString(), equalTo("02"));
|
||||
assertThat(topDocs.scoreDocs[4].doc, equalTo(2));
|
||||
assertThat(((BytesRef) ((FieldDoc) topDocs.scoreDocs[4]).fields[0]).utf8ToString(), equalTo("03"));
|
||||
assertThat(topDocs.scoreDocs[5].doc, equalTo(3));
|
||||
assertThat(((BytesRef) ((FieldDoc) topDocs.scoreDocs[5]).fields[0]).utf8ToString(), equalTo("04"));
|
||||
assertThat(topDocs.scoreDocs[6].doc, equalTo(4));
|
||||
assertThat(((BytesRef) ((FieldDoc) topDocs.scoreDocs[6]).fields[0]).utf8ToString(), equalTo("06"));
|
||||
assertThat(topDocs.scoreDocs[7].doc, equalTo(6));
|
||||
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)));
|
||||
assertThat(topDocs.totalHits, equalTo(8));
|
||||
assertThat(topDocs.scoreDocs.length, equalTo(8));
|
||||
assertThat(topDocs.scoreDocs[0].doc, equalTo(6));
|
||||
assertThat(((BytesRef) ((FieldDoc) topDocs.scoreDocs[0]).fields[0]).utf8ToString(), equalTo("10"));
|
||||
assertThat(topDocs.scoreDocs[1].doc, equalTo(4));
|
||||
assertThat(((BytesRef) ((FieldDoc) topDocs.scoreDocs[1]).fields[0]).utf8ToString(), equalTo("08"));
|
||||
assertThat(topDocs.scoreDocs[2].doc, equalTo(3));
|
||||
assertThat(((BytesRef) ((FieldDoc) topDocs.scoreDocs[2]).fields[0]).utf8ToString(), equalTo("06"));
|
||||
assertThat(topDocs.scoreDocs[3].doc, equalTo(0));
|
||||
assertThat(((BytesRef) ((FieldDoc) topDocs.scoreDocs[3]).fields[0]).utf8ToString(), equalTo("04"));
|
||||
assertThat(topDocs.scoreDocs[4].doc, equalTo(2));
|
||||
assertThat(((BytesRef) ((FieldDoc) topDocs.scoreDocs[4]).fields[0]).utf8ToString(), equalTo("03"));
|
||||
assertThat(topDocs.scoreDocs[5].doc, equalTo(7));
|
||||
assertThat(((BytesRef) ((FieldDoc) topDocs.scoreDocs[5]).fields[0]).utf8ToString(), equalTo("!10"));
|
||||
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));
|
||||
}
|
||||
|
||||
protected void fillExtendedMvSet() throws Exception {
|
||||
Document d = new Document();
|
||||
d.add(new StringField("_id", "1", Field.Store.NO));
|
||||
d.add(new StringField("value", "02", Field.Store.NO));
|
||||
d.add(new StringField("value", "04", Field.Store.NO));
|
||||
writer.addDocument(d);
|
||||
|
||||
d = new Document();
|
||||
d.add(new StringField("_id", "2", Field.Store.NO));
|
||||
writer.addDocument(d);
|
||||
|
||||
d = new Document();
|
||||
d.add(new StringField("_id", "3", Field.Store.NO));
|
||||
d.add(new StringField("value", "03", Field.Store.NO));
|
||||
writer.addDocument(d);
|
||||
writer.commit();
|
||||
|
||||
d = new Document();
|
||||
d.add(new StringField("_id", "4", Field.Store.NO));
|
||||
d.add(new StringField("value", "04", Field.Store.NO));
|
||||
d.add(new StringField("value", "05", Field.Store.NO));
|
||||
d.add(new StringField("value", "06", Field.Store.NO));
|
||||
writer.addDocument(d);
|
||||
|
||||
d = new Document();
|
||||
d.add(new StringField("_id", "5", Field.Store.NO));
|
||||
d.add(new StringField("value", "06", Field.Store.NO));
|
||||
d.add(new StringField("value", "07", Field.Store.NO));
|
||||
d.add(new StringField("value", "08", Field.Store.NO));
|
||||
writer.addDocument(d);
|
||||
|
||||
d = new Document();
|
||||
d.add(new StringField("_id", "6", Field.Store.NO));
|
||||
writer.addDocument(d);
|
||||
|
||||
d = new Document();
|
||||
d.add(new StringField("_id", "7", Field.Store.NO));
|
||||
d.add(new StringField("value", "08", Field.Store.NO));
|
||||
d.add(new StringField("value", "09", Field.Store.NO));
|
||||
d.add(new StringField("value", "10", Field.Store.NO));
|
||||
writer.addDocument(d);
|
||||
writer.commit();
|
||||
|
||||
d = new Document();
|
||||
d.add(new StringField("_id", "8", Field.Store.NO));
|
||||
d.add(new StringField("value", "!08", Field.Store.NO));
|
||||
d.add(new StringField("value", "!09", Field.Store.NO));
|
||||
d.add(new StringField("value", "!10", Field.Store.NO));
|
||||
writer.addDocument(d);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue