If matching root doc's inner objects don't match the `nested_filter` then the `missing` value should be used to sort the root doc.
Closes #3020
This commit is contained in:
parent
2779967279
commit
42d5bdd337
|
@ -66,4 +66,9 @@ public final class ByteValuesComparator extends LongValuesComparatorBase<Byte> {
|
|||
public void divide(int slot, int divisor) {
|
||||
values[slot] /= divisor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void missing(int slot) {
|
||||
values[slot] = (byte) missingValue;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -66,4 +66,9 @@ public final class DoubleValuesComparator extends DoubleValuesComparatorBase<Dou
|
|||
public void divide(int slot, int divisor) {
|
||||
values[slot] /= divisor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void missing(int slot) {
|
||||
values[slot] = missingValue;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -61,6 +61,11 @@ abstract class DoubleValuesComparatorBase<T extends Number> extends NumberCompar
|
|||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareBottomMissing() {
|
||||
return compare(bottom, missingValue);
|
||||
}
|
||||
|
||||
static final int compare(double left, double right) {
|
||||
return Double.compare(left, right);
|
||||
}
|
||||
|
|
|
@ -66,4 +66,9 @@ public final class FloatValuesComparator extends DoubleValuesComparatorBase<Floa
|
|||
public void divide(int slot, int divisor) {
|
||||
values[slot] /= divisor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void missing(int slot) {
|
||||
values[slot] = (float) missingValue;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -72,4 +72,9 @@ public final class IntValuesComparator extends LongValuesComparatorBase<Integer>
|
|||
public void divide(int slot, int divisor) {
|
||||
values[slot] /= divisor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void missing(int slot) {
|
||||
values[slot] = (int) missingValue;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -65,4 +65,9 @@ public final class LongValuesComparator extends LongValuesComparatorBase<Long> {
|
|||
public void divide(int slot, int divisor) {
|
||||
values[slot] /= divisor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void missing(int slot) {
|
||||
values[slot] = missingValue;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -72,6 +72,11 @@ abstract class LongValuesComparatorBase<T extends Number> extends NumberComparat
|
|||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareBottomMissing() {
|
||||
return compare(bottom, missingValue);
|
||||
}
|
||||
|
||||
private static final class MultiValueWrapper extends LongValues.Filtered {
|
||||
|
||||
private final SortMode sortMode;
|
||||
|
|
|
@ -42,4 +42,19 @@ public abstract class NumberComparatorBase<T> extends FieldComparator<T> {
|
|||
* @param divisor The specified divisor
|
||||
*/
|
||||
public abstract void divide(int slot, int divisor);
|
||||
|
||||
/**
|
||||
* Assigns the underlying missing value to the specified slot, if the actual implementation supports missing value.
|
||||
*
|
||||
* @param slot The slot to assign the the missing value to.
|
||||
*/
|
||||
public abstract void missing(int slot);
|
||||
|
||||
/**
|
||||
* Compares the missing value to the bottom.
|
||||
*
|
||||
* @return any N < 0 if the bottom value is not competitive with the missing value, any N > 0 if the
|
||||
* bottom value is competitive with the missing value and 0 if they are equal.
|
||||
*/
|
||||
public abstract int compareBottomMissing();
|
||||
}
|
||||
|
|
|
@ -68,4 +68,9 @@ public final class ShortValuesComparator extends LongValuesComparatorBase<Short>
|
|||
public void divide(int slot, int divisor) {
|
||||
values[slot] /= divisor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void missing(int slot) {
|
||||
values[slot] = (short) missingValue;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -59,9 +59,9 @@ public class NestedFieldComparatorSource extends IndexFieldData.XFieldComparator
|
|||
case MIN:
|
||||
return new NestedFieldComparator.Lowest(wrappedComparator, rootDocumentsFilter, innerDocumentsFilter, numHits);
|
||||
case SUM:
|
||||
return new Sum((NumberComparatorBase) wrappedComparator, rootDocumentsFilter, innerDocumentsFilter, numHits);
|
||||
return new NestedFieldComparator.Sum((NumberComparatorBase) wrappedComparator, rootDocumentsFilter, innerDocumentsFilter, numHits);
|
||||
case AVG:
|
||||
return new Avg((NumberComparatorBase) wrappedComparator, rootDocumentsFilter, innerDocumentsFilter, numHits);
|
||||
return new NestedFieldComparator.Avg((NumberComparatorBase) wrappedComparator, rootDocumentsFilter, innerDocumentsFilter, numHits);
|
||||
default:
|
||||
throw new ElasticSearchIllegalArgumentException(
|
||||
String.format("Unsupported sort_mode[%s] for nested type", sortMode)
|
||||
|
@ -73,167 +73,9 @@ public class NestedFieldComparatorSource extends IndexFieldData.XFieldComparator
|
|||
public SortField.Type reducedType() {
|
||||
return wrappedSource.reducedType();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class Sum extends FieldComparator {
|
||||
|
||||
final Filter rootDocumentsFilter;
|
||||
final Filter innerDocumentsFilter;
|
||||
final int spareSlot;
|
||||
|
||||
NumberComparatorBase wrappedComparator;
|
||||
FixedBitSet rootDocuments;
|
||||
FixedBitSet innerDocuments;
|
||||
int bottomSlot;
|
||||
|
||||
Sum(NumberComparatorBase wrappedComparator, Filter rootDocumentsFilter, Filter innerDocumentsFilter, int spareSlot) {
|
||||
this.wrappedComparator = wrappedComparator;
|
||||
this.rootDocumentsFilter = rootDocumentsFilter;
|
||||
this.innerDocumentsFilter = innerDocumentsFilter;
|
||||
this.spareSlot = spareSlot;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compare(int slot1, int slot2) {
|
||||
return wrappedComparator.compare(slot1, slot2);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBottom(int slot) {
|
||||
wrappedComparator.setBottom(slot);
|
||||
this.bottomSlot = slot;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FieldComparator setNextReader(AtomicReaderContext context) throws IOException {
|
||||
DocIdSet innerDocuments = innerDocumentsFilter.getDocIdSet(context, null);
|
||||
if (DocIdSets.isEmpty(innerDocuments)) {
|
||||
this.innerDocuments = null;
|
||||
} else if (innerDocuments instanceof FixedBitSet) {
|
||||
this.innerDocuments = (FixedBitSet) innerDocuments;
|
||||
} else {
|
||||
this.innerDocuments = DocIdSets.toFixedBitSet(innerDocuments.iterator(), context.reader().maxDoc());
|
||||
}
|
||||
DocIdSet rootDocuments = rootDocumentsFilter.getDocIdSet(context, null);
|
||||
if (DocIdSets.isEmpty(rootDocuments)) {
|
||||
this.rootDocuments = null;
|
||||
} else if (rootDocuments instanceof FixedBitSet) {
|
||||
this.rootDocuments = (FixedBitSet) rootDocuments;
|
||||
} else {
|
||||
this.rootDocuments = DocIdSets.toFixedBitSet(rootDocuments.iterator(), context.reader().maxDoc());
|
||||
}
|
||||
|
||||
wrappedComparator = (NumberComparatorBase) wrappedComparator.setNextReader(context);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object value(int slot) {
|
||||
return wrappedComparator.value(slot);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareBottom(int rootDoc) throws IOException {
|
||||
if (rootDoc == 0 || rootDocuments == null || innerDocuments == null) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int prevRootDoc = rootDocuments.prevSetBit(rootDoc - 1);
|
||||
int nestedDoc = innerDocuments.nextSetBit(prevRootDoc + 1);
|
||||
if (nestedDoc >= rootDoc || nestedDoc == -1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
wrappedComparator.copy(spareSlot, nestedDoc);
|
||||
nestedDoc = innerDocuments.nextSetBit(nestedDoc + 1);
|
||||
while (nestedDoc > prevRootDoc && nestedDoc < rootDoc) {
|
||||
wrappedComparator.add(spareSlot, nestedDoc);
|
||||
nestedDoc = innerDocuments.nextSetBit(nestedDoc + 1);
|
||||
}
|
||||
return compare(bottomSlot, spareSlot);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void copy(int slot, int rootDoc) throws IOException {
|
||||
if (rootDoc == 0 || rootDocuments == null || innerDocuments == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
int prevRootDoc = rootDocuments.prevSetBit(rootDoc - 1);
|
||||
int nestedDoc = innerDocuments.nextSetBit(prevRootDoc + 1);
|
||||
if (nestedDoc >= rootDoc || nestedDoc == -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
wrappedComparator.copy(slot, nestedDoc);
|
||||
nestedDoc = innerDocuments.nextSetBit(nestedDoc + 1);
|
||||
while (nestedDoc > prevRootDoc && nestedDoc < rootDoc) {
|
||||
wrappedComparator.add(slot, nestedDoc);
|
||||
nestedDoc = innerDocuments.nextSetBit(nestedDoc + 1);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareDocToValue(int rootDoc, Object value) throws IOException {
|
||||
throw new UnsupportedOperationException("compareDocToValue() not used for sorting in ES");
|
||||
}
|
||||
}
|
||||
|
||||
final class Avg extends Sum {
|
||||
|
||||
Avg(NumberComparatorBase wrappedComparator, Filter rootDocumentsFilter, Filter innerDocumentsFilter, int spareSlot) {
|
||||
super(wrappedComparator, rootDocumentsFilter, innerDocumentsFilter, spareSlot);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareBottom(int rootDoc) throws IOException {
|
||||
if (rootDoc == 0 || rootDocuments == null || innerDocuments == null) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int prevRootDoc = rootDocuments.prevSetBit(rootDoc - 1);
|
||||
int nestedDoc = innerDocuments.nextSetBit(prevRootDoc + 1);
|
||||
if (nestedDoc >= rootDoc || nestedDoc == -1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int counter = 1;
|
||||
wrappedComparator.copy(spareSlot, nestedDoc);
|
||||
nestedDoc = innerDocuments.nextSetBit(nestedDoc + 1);
|
||||
while (nestedDoc > prevRootDoc && nestedDoc < rootDoc) {
|
||||
wrappedComparator.add(spareSlot, nestedDoc);
|
||||
nestedDoc = innerDocuments.nextSetBit(nestedDoc + 1);
|
||||
counter++;
|
||||
}
|
||||
wrappedComparator.divide(spareSlot, counter);
|
||||
return compare(bottomSlot, spareSlot);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void copy(int slot, int rootDoc) throws IOException {
|
||||
if (rootDoc == 0 || rootDocuments == null || innerDocuments == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
int prevRootDoc = rootDocuments.prevSetBit(rootDoc - 1);
|
||||
int nestedDoc = innerDocuments.nextSetBit(prevRootDoc + 1);
|
||||
if (nestedDoc >= rootDoc || nestedDoc == -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
int counter = 1;
|
||||
wrappedComparator.copy(slot, nestedDoc);
|
||||
nestedDoc = innerDocuments.nextSetBit(nestedDoc + 1);
|
||||
while (nestedDoc > prevRootDoc && nestedDoc < rootDoc) {
|
||||
wrappedComparator.add(slot, nestedDoc);
|
||||
nestedDoc = innerDocuments.nextSetBit(nestedDoc + 1);
|
||||
counter++;
|
||||
}
|
||||
wrappedComparator.divide(slot, counter);
|
||||
}
|
||||
}
|
||||
|
||||
// Move to Lucene join module
|
||||
abstract class NestedFieldComparator extends FieldComparator {
|
||||
|
||||
final Filter rootDocumentsFilter;
|
||||
|
@ -243,6 +85,7 @@ abstract class NestedFieldComparator extends FieldComparator {
|
|||
FieldComparator wrappedComparator;
|
||||
FixedBitSet rootDocuments;
|
||||
FixedBitSet innerDocuments;
|
||||
int bottomSlot;
|
||||
|
||||
NestedFieldComparator(FieldComparator wrappedComparator, Filter rootDocumentsFilter, Filter innerDocumentsFilter, int spareSlot) {
|
||||
this.wrappedComparator = wrappedComparator;
|
||||
|
@ -252,13 +95,14 @@ abstract class NestedFieldComparator extends FieldComparator {
|
|||
}
|
||||
|
||||
@Override
|
||||
public int compare(int slot1, int slot2) {
|
||||
public final int compare(int slot1, int slot2) {
|
||||
return wrappedComparator.compare(slot1, slot2);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBottom(int slot) {
|
||||
public final void setBottom(int slot) {
|
||||
wrappedComparator.setBottom(slot);
|
||||
this.bottomSlot = slot;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -285,10 +129,15 @@ abstract class NestedFieldComparator extends FieldComparator {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Object value(int slot) {
|
||||
public final Object value(int slot) {
|
||||
return wrappedComparator.value(slot);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final int compareDocToValue(int rootDoc, Object value) throws IOException {
|
||||
throw new UnsupportedOperationException("compareDocToValue() not used for sorting in ES");
|
||||
}
|
||||
|
||||
final static class Lowest extends NestedFieldComparator {
|
||||
|
||||
Lowest(FieldComparator wrappedComparator, Filter parentFilter, Filter childFilter, int spareSlot) {
|
||||
|
@ -298,14 +147,14 @@ abstract class NestedFieldComparator extends FieldComparator {
|
|||
@Override
|
||||
public int compareBottom(int rootDoc) throws IOException {
|
||||
if (rootDoc == 0 || rootDocuments == null || innerDocuments == null) {
|
||||
return 0;
|
||||
return compareBottomMissing(wrappedComparator);
|
||||
}
|
||||
|
||||
// We need to copy the lowest value from all nested docs into slot.
|
||||
int prevRootDoc = rootDocuments.prevSetBit(rootDoc - 1);
|
||||
int nestedDoc = innerDocuments.nextSetBit(prevRootDoc + 1);
|
||||
if (nestedDoc >= rootDoc || nestedDoc == -1) {
|
||||
return 0;
|
||||
return compareBottomMissing(wrappedComparator);
|
||||
}
|
||||
|
||||
// We only need to emit a single cmp value for any matching nested doc
|
||||
|
@ -333,6 +182,7 @@ abstract class NestedFieldComparator extends FieldComparator {
|
|||
@Override
|
||||
public void copy(int slot, int rootDoc) throws IOException {
|
||||
if (rootDoc == 0 || rootDocuments == null || innerDocuments == null) {
|
||||
copyMissing(wrappedComparator, slot);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -340,6 +190,7 @@ abstract class NestedFieldComparator extends FieldComparator {
|
|||
int prevRootDoc = rootDocuments.prevSetBit(rootDoc - 1);
|
||||
int nestedDoc = innerDocuments.nextSetBit(prevRootDoc + 1);
|
||||
if (nestedDoc >= rootDoc || nestedDoc == -1) {
|
||||
copyMissing(wrappedComparator, slot);
|
||||
return;
|
||||
}
|
||||
wrappedComparator.copy(spareSlot, nestedDoc);
|
||||
|
@ -357,42 +208,6 @@ abstract class NestedFieldComparator extends FieldComparator {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public int compareDocToValue(int rootDoc, Object value) throws IOException {
|
||||
if (rootDoc == 0 || rootDocuments == null || innerDocuments == null) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// We need to copy the lowest value from all nested docs into slot.
|
||||
int prevRootDoc = rootDocuments.prevSetBit(rootDoc - 1);
|
||||
int nestedDoc = innerDocuments.nextSetBit(prevRootDoc + 1);
|
||||
if (nestedDoc >= rootDoc || nestedDoc == -1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// We only need to emit a single cmp value for any matching nested doc
|
||||
int cmp = wrappedComparator.compareBottom(nestedDoc);
|
||||
if (cmp > 0) {
|
||||
return cmp;
|
||||
}
|
||||
|
||||
while (true) {
|
||||
nestedDoc = innerDocuments.nextSetBit(nestedDoc + 1);
|
||||
if (nestedDoc >= rootDoc || nestedDoc == -1) {
|
||||
return cmp;
|
||||
}
|
||||
int cmp1 = wrappedComparator.compareDocToValue(nestedDoc, value);
|
||||
if (cmp1 > 0) {
|
||||
return cmp1;
|
||||
} else {
|
||||
if (cmp1 == 0) {
|
||||
cmp = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
final static class Highest extends NestedFieldComparator {
|
||||
|
@ -404,13 +219,13 @@ abstract class NestedFieldComparator extends FieldComparator {
|
|||
@Override
|
||||
public int compareBottom(int rootDoc) throws IOException {
|
||||
if (rootDoc == 0 || rootDocuments == null || innerDocuments == null) {
|
||||
return 0;
|
||||
return compareBottomMissing(wrappedComparator);
|
||||
}
|
||||
|
||||
int prevRootDoc = rootDocuments.prevSetBit(rootDoc - 1);
|
||||
int nestedDoc = innerDocuments.nextSetBit(prevRootDoc + 1);
|
||||
if (nestedDoc >= rootDoc || nestedDoc == -1) {
|
||||
return 0;
|
||||
return compareBottomMissing(wrappedComparator);
|
||||
}
|
||||
|
||||
int cmp = wrappedComparator.compareBottom(nestedDoc);
|
||||
|
@ -437,12 +252,14 @@ abstract class NestedFieldComparator extends FieldComparator {
|
|||
@Override
|
||||
public void copy(int slot, int rootDoc) throws IOException {
|
||||
if (rootDoc == 0 || rootDocuments == null || innerDocuments == null) {
|
||||
copyMissing(wrappedComparator, slot);
|
||||
return;
|
||||
}
|
||||
|
||||
int prevRootDoc = rootDocuments.prevSetBit(rootDoc - 1);
|
||||
int nestedDoc = innerDocuments.nextSetBit(prevRootDoc + 1);
|
||||
if (nestedDoc >= rootDoc || nestedDoc == -1) {
|
||||
copyMissing(wrappedComparator, slot);
|
||||
return;
|
||||
}
|
||||
wrappedComparator.copy(spareSlot, nestedDoc);
|
||||
|
@ -460,9 +277,80 @@ abstract class NestedFieldComparator extends FieldComparator {
|
|||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
final static class Sum extends NestedFieldComparator {
|
||||
|
||||
NumberComparatorBase wrappedComparator;
|
||||
|
||||
Sum(NumberComparatorBase wrappedComparator, Filter rootDocumentsFilter, Filter innerDocumentsFilter, int spareSlot) {
|
||||
super(wrappedComparator, rootDocumentsFilter, innerDocumentsFilter, spareSlot);
|
||||
this.wrappedComparator = wrappedComparator;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public int compareDocToValue(int rootDoc, Object value) throws IOException {
|
||||
public int compareBottom(int rootDoc) throws IOException {
|
||||
if (rootDoc == 0 || rootDocuments == null || innerDocuments == null) {
|
||||
return compareBottomMissing(wrappedComparator);
|
||||
}
|
||||
|
||||
int prevRootDoc = rootDocuments.prevSetBit(rootDoc - 1);
|
||||
int nestedDoc = innerDocuments.nextSetBit(prevRootDoc + 1);
|
||||
if (nestedDoc >= rootDoc || nestedDoc == -1) {
|
||||
return compareBottomMissing(wrappedComparator);
|
||||
}
|
||||
|
||||
wrappedComparator.copy(spareSlot, nestedDoc);
|
||||
nestedDoc = innerDocuments.nextSetBit(nestedDoc + 1);
|
||||
while (nestedDoc > prevRootDoc && nestedDoc < rootDoc) {
|
||||
wrappedComparator.add(spareSlot, nestedDoc);
|
||||
nestedDoc = innerDocuments.nextSetBit(nestedDoc + 1);
|
||||
}
|
||||
return compare(bottomSlot, spareSlot);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void copy(int slot, int rootDoc) throws IOException {
|
||||
if (rootDoc == 0 || rootDocuments == null || innerDocuments == null) {
|
||||
copyMissing(wrappedComparator, slot);
|
||||
return;
|
||||
}
|
||||
|
||||
int prevRootDoc = rootDocuments.prevSetBit(rootDoc - 1);
|
||||
int nestedDoc = innerDocuments.nextSetBit(prevRootDoc + 1);
|
||||
if (nestedDoc >= rootDoc || nestedDoc == -1) {
|
||||
copyMissing(wrappedComparator, slot);
|
||||
return;
|
||||
}
|
||||
|
||||
wrappedComparator.copy(slot, nestedDoc);
|
||||
nestedDoc = innerDocuments.nextSetBit(nestedDoc + 1);
|
||||
while (nestedDoc > prevRootDoc && nestedDoc < rootDoc) {
|
||||
wrappedComparator.add(slot, nestedDoc);
|
||||
nestedDoc = innerDocuments.nextSetBit(nestedDoc + 1);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public FieldComparator setNextReader(AtomicReaderContext context) throws IOException {
|
||||
super.setNextReader(context);
|
||||
wrappedComparator = (NumberComparatorBase) super.wrappedComparator;
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
final static class Avg extends NestedFieldComparator {
|
||||
|
||||
NumberComparatorBase wrappedComparator;
|
||||
|
||||
Avg(NumberComparatorBase wrappedComparator, Filter rootDocumentsFilter, Filter innerDocumentsFilter, int spareSlot) {
|
||||
super(wrappedComparator, rootDocumentsFilter, innerDocumentsFilter, spareSlot);
|
||||
this.wrappedComparator = wrappedComparator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareBottom(int rootDoc) throws IOException {
|
||||
if (rootDoc == 0 || rootDocuments == null || innerDocuments == null) {
|
||||
return 0;
|
||||
}
|
||||
|
@ -470,30 +358,65 @@ abstract class NestedFieldComparator extends FieldComparator {
|
|||
int prevRootDoc = rootDocuments.prevSetBit(rootDoc - 1);
|
||||
int nestedDoc = innerDocuments.nextSetBit(prevRootDoc + 1);
|
||||
if (nestedDoc >= rootDoc || nestedDoc == -1) {
|
||||
return 0;
|
||||
return compareBottomMissing(wrappedComparator);
|
||||
}
|
||||
|
||||
int cmp = wrappedComparator.compareBottom(nestedDoc);
|
||||
if (cmp < 0) {
|
||||
return cmp;
|
||||
}
|
||||
|
||||
while (true) {
|
||||
int counter = 1;
|
||||
wrappedComparator.copy(spareSlot, nestedDoc);
|
||||
nestedDoc = innerDocuments.nextSetBit(nestedDoc + 1);
|
||||
while (nestedDoc > prevRootDoc && nestedDoc < rootDoc) {
|
||||
wrappedComparator.add(spareSlot, nestedDoc);
|
||||
nestedDoc = innerDocuments.nextSetBit(nestedDoc + 1);
|
||||
if (nestedDoc >= rootDoc || nestedDoc == -1) {
|
||||
return cmp;
|
||||
}
|
||||
int cmp1 = wrappedComparator.compareDocToValue(nestedDoc, value);
|
||||
if (cmp1 < 0) {
|
||||
return cmp1;
|
||||
} else {
|
||||
if (cmp1 == 0) {
|
||||
cmp = 0;
|
||||
}
|
||||
}
|
||||
counter++;
|
||||
}
|
||||
wrappedComparator.divide(spareSlot, counter);
|
||||
return compare(bottomSlot, spareSlot);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void copy(int slot, int rootDoc) throws IOException {
|
||||
if (rootDoc == 0 || rootDocuments == null || innerDocuments == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
int prevRootDoc = rootDocuments.prevSetBit(rootDoc - 1);
|
||||
int nestedDoc = innerDocuments.nextSetBit(prevRootDoc + 1);
|
||||
if (nestedDoc >= rootDoc || nestedDoc == -1) {
|
||||
copyMissing(wrappedComparator, slot);
|
||||
return;
|
||||
}
|
||||
|
||||
int counter = 1;
|
||||
wrappedComparator.copy(slot, nestedDoc);
|
||||
nestedDoc = innerDocuments.nextSetBit(nestedDoc + 1);
|
||||
while (nestedDoc > prevRootDoc && nestedDoc < rootDoc) {
|
||||
wrappedComparator.add(slot, nestedDoc);
|
||||
nestedDoc = innerDocuments.nextSetBit(nestedDoc + 1);
|
||||
counter++;
|
||||
}
|
||||
wrappedComparator.divide(slot, counter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FieldComparator setNextReader(AtomicReaderContext context) throws IOException {
|
||||
super.setNextReader(context);
|
||||
wrappedComparator = (NumberComparatorBase) super.wrappedComparator;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
static final void copyMissing(FieldComparator comparator, int slot) {
|
||||
if (comparator instanceof NumberComparatorBase) {
|
||||
((NumberComparatorBase) comparator).missing(slot);
|
||||
}
|
||||
}
|
||||
|
||||
static final int compareBottomMissing(FieldComparator comparator) {
|
||||
if (comparator instanceof NumberComparatorBase) {
|
||||
return ((NumberComparatorBase) comparator).compareBottomMissing();
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -682,6 +682,96 @@ public class SimpleNestedTests extends AbstractNodesTests {
|
|||
assertThat(searchResponse.getHits().hits()[2].sortValues()[0].toString(), equalTo("2"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSimpleNestedSorting_withNestedFilterMissing() throws Exception {
|
||||
client.admin().indices().prepareDelete().execute().actionGet();
|
||||
client.admin().indices().prepareCreate("test")
|
||||
.setSettings(settingsBuilder()
|
||||
.put("index.number_of_shards", 1)
|
||||
.put("index.number_of_replicas", 0)
|
||||
.put("index.referesh_interval", -1)
|
||||
.build()
|
||||
)
|
||||
.addMapping("type1", jsonBuilder().startObject().startObject("type1").startObject("properties")
|
||||
.startObject("nested1")
|
||||
.field("type", "nested")
|
||||
.endObject()
|
||||
.endObject().endObject().endObject())
|
||||
.execute().actionGet();
|
||||
client.admin().cluster().prepareHealth().setWaitForEvents(Priority.LANGUID).setWaitForGreenStatus().execute().actionGet();
|
||||
|
||||
client.prepareIndex("test", "type1", "1").setSource(jsonBuilder().startObject()
|
||||
.field("field1", 1)
|
||||
.startArray("nested1")
|
||||
.startObject()
|
||||
.field("field1", 5)
|
||||
.field("field2", true)
|
||||
.endObject()
|
||||
.startObject()
|
||||
.field("field1", 4)
|
||||
.field("field2", true)
|
||||
.endObject()
|
||||
.endArray()
|
||||
.endObject()).execute().actionGet();
|
||||
client.prepareIndex("test", "type1", "2").setSource(jsonBuilder().startObject()
|
||||
.field("field1", 2)
|
||||
.startArray("nested1")
|
||||
.startObject()
|
||||
.field("field1", 1)
|
||||
.field("field2", true)
|
||||
.endObject()
|
||||
.startObject()
|
||||
.field("field1", 2)
|
||||
.field("field2", true)
|
||||
.endObject()
|
||||
.endArray()
|
||||
.endObject()).execute().actionGet();
|
||||
// Doc with missing nested docs if nested filter is used
|
||||
client.admin().indices().prepareRefresh().execute().actionGet();
|
||||
client.prepareIndex("test", "type1", "3").setSource(jsonBuilder().startObject()
|
||||
.field("field1", 3)
|
||||
.startArray("nested1")
|
||||
.startObject()
|
||||
.field("field1", 3)
|
||||
.field("field2", false)
|
||||
.endObject()
|
||||
.startObject()
|
||||
.field("field1", 4)
|
||||
.field("field2", false)
|
||||
.endObject()
|
||||
.endArray()
|
||||
.endObject()).execute().actionGet();
|
||||
client.admin().indices().prepareRefresh().execute().actionGet();
|
||||
|
||||
SearchResponse searchResponse = client.prepareSearch("test")
|
||||
.setTypes("type1")
|
||||
.setQuery(QueryBuilders.matchAllQuery())
|
||||
.addSort(SortBuilders.fieldSort("nested1.field1").setNestedFilter(termFilter("nested1.field2", true)).missing(10).order(SortOrder.ASC))
|
||||
.execute().actionGet();
|
||||
|
||||
assertThat(searchResponse.getHits().totalHits(), equalTo(3l));
|
||||
assertThat(searchResponse.getHits().hits()[0].id(), equalTo("2"));
|
||||
assertThat(searchResponse.getHits().hits()[0].sortValues()[0].toString(), equalTo("1"));
|
||||
assertThat(searchResponse.getHits().hits()[1].id(), equalTo("1"));
|
||||
assertThat(searchResponse.getHits().hits()[1].sortValues()[0].toString(), equalTo("4"));
|
||||
assertThat(searchResponse.getHits().hits()[2].id(), equalTo("3"));
|
||||
assertThat(searchResponse.getHits().hits()[2].sortValues()[0].toString(), equalTo("10"));
|
||||
|
||||
searchResponse = client.prepareSearch("test")
|
||||
.setTypes("type1")
|
||||
.setQuery(QueryBuilders.matchAllQuery())
|
||||
.addSort(SortBuilders.fieldSort("nested1.field1").setNestedFilter(termFilter("nested1.field2", true)).missing(10).order(SortOrder.DESC))
|
||||
.execute().actionGet();
|
||||
|
||||
assertThat(searchResponse.getHits().totalHits(), equalTo(3l));
|
||||
assertThat(searchResponse.getHits().hits()[0].id(), equalTo("3"));
|
||||
assertThat(searchResponse.getHits().hits()[0].sortValues()[0].toString(), equalTo("10"));
|
||||
assertThat(searchResponse.getHits().hits()[1].id(), equalTo("1"));
|
||||
assertThat(searchResponse.getHits().hits()[1].sortValues()[0].toString(), equalTo("5"));
|
||||
assertThat(searchResponse.getHits().hits()[2].id(), equalTo("2"));
|
||||
assertThat(searchResponse.getHits().hits()[2].sortValues()[0].toString(), equalTo("2"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSortNestedWithNestedFilter() throws Exception {
|
||||
client.admin().indices().prepareDelete().execute().actionGet();
|
||||
|
|
|
@ -28,7 +28,6 @@ import org.apache.lucene.index.Term;
|
|||
import org.apache.lucene.search.*;
|
||||
import org.apache.lucene.search.join.ScoreMode;
|
||||
import org.apache.lucene.search.join.ToParentBlockJoinQuery;
|
||||
import org.elasticsearch.common.lucene.search.AndFilter;
|
||||
import org.elasticsearch.common.lucene.search.NotFilter;
|
||||
import org.elasticsearch.common.lucene.search.TermFilter;
|
||||
import org.elasticsearch.common.lucene.search.XFilteredQuery;
|
||||
|
@ -40,7 +39,6 @@ import org.testng.annotations.Test;
|
|||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
|
@ -148,6 +146,7 @@ public abstract class AbstractNumberNestedSortingTests extends AbstractFieldData
|
|||
document.add(createField("field1", 5, Field.Store.NO));
|
||||
docs.add(document);
|
||||
writer.addDocuments(docs);
|
||||
writer.commit();
|
||||
|
||||
docs.clear();
|
||||
document = new Document();
|
||||
|
@ -167,12 +166,14 @@ public abstract class AbstractNumberNestedSortingTests extends AbstractFieldData
|
|||
document.add(createField("field1", 6, Field.Store.NO));
|
||||
docs.add(document);
|
||||
writer.addDocuments(docs);
|
||||
writer.commit();
|
||||
|
||||
// This doc will not be included, because it doesn't have nested docs
|
||||
document = new Document();
|
||||
document.add(new StringField("__type", "parent", Field.Store.NO));
|
||||
document.add(createField("field1", 7, Field.Store.NO));
|
||||
writer.addDocument(document);
|
||||
writer.commit();
|
||||
|
||||
docs.clear();
|
||||
document = new Document();
|
||||
|
@ -207,7 +208,7 @@ public abstract class AbstractNumberNestedSortingTests extends AbstractFieldData
|
|||
|
||||
SortMode sortMode = SortMode.SUM;
|
||||
IndexSearcher searcher = new IndexSearcher(DirectoryReader.open(writer, false));
|
||||
IndexFieldData.XFieldComparatorSource innerFieldComparator = createInnerFieldComparator("field2", sortMode);
|
||||
IndexFieldData.XFieldComparatorSource innerFieldComparator = createInnerFieldComparator("field2", sortMode, null);
|
||||
Filter parentFilter = new TermFilter(new Term("__type", "parent"));
|
||||
Filter childFilter = new NotFilter(parentFilter);
|
||||
NestedFieldComparatorSource nestedComparatorSource = new NestedFieldComparatorSource(sortMode, innerFieldComparator, parentFilter, childFilter);
|
||||
|
@ -243,7 +244,7 @@ public abstract class AbstractNumberNestedSortingTests extends AbstractFieldData
|
|||
assertThat(topDocs.scoreDocs[4].doc, equalTo(3));
|
||||
assertThat(((Number) ((FieldDoc) topDocs.scoreDocs[4]).fields[0]).intValue(), equalTo(9));
|
||||
|
||||
childFilter = new AndFilter(Arrays.asList(new NotFilter(parentFilter), new TermFilter(new Term("filter_1", "T"))));
|
||||
childFilter = new TermFilter(new Term("filter_1", "T"));
|
||||
nestedComparatorSource = new NestedFieldComparatorSource(sortMode, innerFieldComparator, parentFilter, childFilter);
|
||||
query = new ToParentBlockJoinQuery(
|
||||
new XFilteredQuery(new MatchAllDocsQuery(), childFilter),
|
||||
|
@ -280,6 +281,40 @@ public abstract class AbstractNumberNestedSortingTests extends AbstractFieldData
|
|||
assertThat(topDocs.scoreDocs[4].doc, equalTo(3));
|
||||
assertThat(((Number) ((FieldDoc) topDocs.scoreDocs[4]).fields[0]).intValue(), equalTo(9));
|
||||
|
||||
innerFieldComparator = createInnerFieldComparator("field2", sortMode, 127);
|
||||
nestedComparatorSource = new NestedFieldComparatorSource(sortMode, innerFieldComparator, parentFilter, childFilter);
|
||||
sort = new Sort(new SortField("field2", nestedComparatorSource, true));
|
||||
topDocs = searcher.search(new TermQuery(new Term("__type", "parent")), 5, sort);
|
||||
assertThat(topDocs.totalHits, equalTo(8));
|
||||
assertThat(topDocs.scoreDocs.length, equalTo(5));
|
||||
assertThat(topDocs.scoreDocs[0].doc, equalTo(19));
|
||||
assertThat(((Number) ((FieldDoc) topDocs.scoreDocs[0]).fields[0]).intValue(), equalTo(127));
|
||||
assertThat(topDocs.scoreDocs[1].doc, equalTo(24));
|
||||
assertThat(((Number) ((FieldDoc) topDocs.scoreDocs[1]).fields[0]).intValue(), equalTo(127));
|
||||
assertThat(topDocs.scoreDocs[2].doc, equalTo(23));
|
||||
assertThat(((Number) ((FieldDoc) topDocs.scoreDocs[2]).fields[0]).intValue(), equalTo(12));
|
||||
assertThat(topDocs.scoreDocs[3].doc, equalTo(3));
|
||||
assertThat(((Number) ((FieldDoc) topDocs.scoreDocs[3]).fields[0]).intValue(), equalTo(9));
|
||||
assertThat(topDocs.scoreDocs[4].doc, equalTo(7));
|
||||
assertThat(((Number) ((FieldDoc) topDocs.scoreDocs[4]).fields[0]).intValue(), equalTo(8));
|
||||
|
||||
innerFieldComparator = createInnerFieldComparator("field2", sortMode, -127);
|
||||
nestedComparatorSource = new NestedFieldComparatorSource(sortMode, innerFieldComparator, parentFilter, childFilter);
|
||||
sort = new Sort(new SortField("field2", nestedComparatorSource));
|
||||
topDocs = searcher.search(new TermQuery(new Term("__type", "parent")), 5, sort);
|
||||
assertThat(topDocs.totalHits, equalTo(8));
|
||||
assertThat(topDocs.scoreDocs.length, equalTo(5));
|
||||
assertThat(topDocs.scoreDocs[0].doc, equalTo(19));
|
||||
assertThat(((Number) ((FieldDoc) topDocs.scoreDocs[0]).fields[0]).intValue(), equalTo(-127));
|
||||
assertThat(topDocs.scoreDocs[1].doc, equalTo(24));
|
||||
assertThat(((Number) ((FieldDoc) topDocs.scoreDocs[1]).fields[0]).intValue(), equalTo(-127));
|
||||
assertThat(topDocs.scoreDocs[2].doc, equalTo(15));
|
||||
assertThat(((Number) ((FieldDoc) topDocs.scoreDocs[2]).fields[0]).intValue(), equalTo(3));
|
||||
assertThat(topDocs.scoreDocs[3].doc, equalTo(28));
|
||||
assertThat(((Number) ((FieldDoc) topDocs.scoreDocs[3]).fields[0]).intValue(), equalTo(3));
|
||||
assertThat(topDocs.scoreDocs[4].doc, equalTo(11));
|
||||
assertThat(((Number) ((FieldDoc) topDocs.scoreDocs[4]).fields[0]).intValue(), equalTo(7));
|
||||
|
||||
// Moved to method, because floating point based XFieldComparatorSource have different outcome for SortMode avg,
|
||||
// than integral number based implementations...
|
||||
assertAvgScoreMode(parentFilter, searcher, innerFieldComparator);
|
||||
|
@ -309,6 +344,6 @@ public abstract class AbstractNumberNestedSortingTests extends AbstractFieldData
|
|||
|
||||
protected abstract IndexableField createField(String name, int value, Field.Store store);
|
||||
|
||||
protected abstract IndexFieldData.XFieldComparatorSource createInnerFieldComparator(String fieldName, SortMode sortMode);
|
||||
protected abstract IndexFieldData.XFieldComparatorSource createInnerFieldComparator(String fieldName, SortMode sortMode, Object missingValue);
|
||||
|
||||
}
|
||||
|
|
|
@ -38,9 +38,9 @@ public class ByteNestedSortingTests extends AbstractNumberNestedSortingTests {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected IndexFieldData.XFieldComparatorSource createInnerFieldComparator(String fieldName, SortMode sortMode) {
|
||||
protected IndexFieldData.XFieldComparatorSource createInnerFieldComparator(String fieldName, SortMode sortMode, Object missingValue) {
|
||||
ByteArrayIndexFieldData fieldData = getForField(fieldName);
|
||||
return new ByteValuesComparatorSource(fieldData, null, sortMode);
|
||||
return new ByteValuesComparatorSource(fieldData, missingValue, sortMode);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -49,9 +49,9 @@ public class DoubleNestedSortingTests extends AbstractNumberNestedSortingTests {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected IndexFieldData.XFieldComparatorSource createInnerFieldComparator(String fieldName, SortMode sortMode) {
|
||||
protected IndexFieldData.XFieldComparatorSource createInnerFieldComparator(String fieldName, SortMode sortMode, Object missingValue) {
|
||||
DoubleArrayIndexFieldData fieldData = getForField(fieldName);
|
||||
return new DoubleValuesComparatorSource(fieldData, null, sortMode);
|
||||
return new DoubleValuesComparatorSource(fieldData, missingValue, sortMode);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -49,9 +49,9 @@ public class FloatNestedSortingTests extends AbstractNumberNestedSortingTests {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected IndexFieldData.XFieldComparatorSource createInnerFieldComparator(String fieldName, SortMode sortMode) {
|
||||
protected IndexFieldData.XFieldComparatorSource createInnerFieldComparator(String fieldName, SortMode sortMode, Object missingValue) {
|
||||
FloatArrayIndexFieldData fieldData = getForField(fieldName);
|
||||
return new FloatValuesComparatorSource(fieldData, null, sortMode);
|
||||
return new FloatValuesComparatorSource(fieldData, missingValue, sortMode);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -38,9 +38,9 @@ public class IntegerNestedSortingTests extends AbstractNumberNestedSortingTests
|
|||
}
|
||||
|
||||
@Override
|
||||
protected IndexFieldData.XFieldComparatorSource createInnerFieldComparator(String fieldName, SortMode sortMode) {
|
||||
protected IndexFieldData.XFieldComparatorSource createInnerFieldComparator(String fieldName, SortMode sortMode, Object missingValue) {
|
||||
IntArrayIndexFieldData fieldData = getForField(fieldName);
|
||||
return new IntValuesComparatorSource(fieldData, null, sortMode);
|
||||
return new IntValuesComparatorSource(fieldData, missingValue, sortMode);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -38,9 +38,9 @@ public class LongNestedSortingTests extends AbstractNumberNestedSortingTests {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected IndexFieldData.XFieldComparatorSource createInnerFieldComparator(String fieldName, SortMode sortMode) {
|
||||
protected IndexFieldData.XFieldComparatorSource createInnerFieldComparator(String fieldName, SortMode sortMode, Object missingValue) {
|
||||
LongArrayIndexFieldData fieldData = getForField(fieldName);
|
||||
return new LongValuesComparatorSource(fieldData, null, sortMode);
|
||||
return new LongValuesComparatorSource(fieldData, missingValue, sortMode);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -38,9 +38,9 @@ public class ShortNestedSortingTests extends AbstractNumberNestedSortingTests {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected IndexFieldData.XFieldComparatorSource createInnerFieldComparator(String fieldName, SortMode sortMode) {
|
||||
protected IndexFieldData.XFieldComparatorSource createInnerFieldComparator(String fieldName, SortMode sortMode, Object missingValue) {
|
||||
ShortArrayIndexFieldData fieldData = getForField(fieldName);
|
||||
return new ShortValuesComparatorSource(fieldData, null, sortMode);
|
||||
return new ShortValuesComparatorSource(fieldData, missingValue, sortMode);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
Loading…
Reference in New Issue