org.elasticsearch.search.MultiValueMode Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of elasticsearch Show documentation
Show all versions of elasticsearch Show documentation
Elasticsearch subproject :server
/*
* Licensed to Elasticsearch under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.elasticsearch.search;
import org.apache.lucene.index.BinaryDocValues;
import org.apache.lucene.index.DocValues;
import org.apache.lucene.index.NumericDocValues;
import org.apache.lucene.index.SortedDocValues;
import org.apache.lucene.index.SortedNumericDocValues;
import org.apache.lucene.index.SortedSetDocValues;
import org.apache.lucene.search.DocIdSetIterator;
import org.apache.lucene.util.BitSet;
import org.apache.lucene.util.BytesRef;
import org.apache.lucene.util.BytesRefBuilder;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.common.io.stream.Writeable;
import org.elasticsearch.index.fielddata.AbstractBinaryDocValues;
import org.elasticsearch.index.fielddata.AbstractNumericDocValues;
import org.elasticsearch.index.fielddata.AbstractSortedDocValues;
import org.elasticsearch.index.fielddata.FieldData;
import org.elasticsearch.index.fielddata.NumericDoubleValues;
import org.elasticsearch.index.fielddata.SortedBinaryDocValues;
import org.elasticsearch.index.fielddata.SortedNumericDoubleValues;
import java.io.IOException;
import java.util.Locale;
/**
* Defines what values to pick in the case a document contains multiple values for a particular field.
*/
public enum MultiValueMode implements Writeable {
/**
* Pick the sum of all the values.
*/
SUM {
@Override
protected long pick(SortedNumericDocValues values) throws IOException {
final int count = values.docValueCount();
long total = 0;
for (int index = 0; index < count; ++index) {
total += values.nextValue();
}
return total;
}
@Override
protected long pick(SortedNumericDocValues values, long missingValue, DocIdSetIterator docItr, int startDoc, int endDoc,
int maxChildren) throws IOException {
int totalCount = 0;
long totalValue = 0;
int count = 0;
for (int doc = startDoc; doc < endDoc; doc = docItr.nextDoc()) {
if (values.advanceExact(doc)) {
if (++count > maxChildren) {
break;
}
final int docCount = values.docValueCount();
for (int index = 0; index < docCount; ++index) {
totalValue += values.nextValue();
}
totalCount += docCount;
}
}
return totalCount > 0 ? totalValue : missingValue;
}
@Override
protected double pick(SortedNumericDoubleValues values) throws IOException {
final int count = values.docValueCount();
double total = 0;
for (int index = 0; index < count; ++index) {
total += values.nextValue();
}
return total;
}
@Override
protected double pick(SortedNumericDoubleValues values, double missingValue, DocIdSetIterator docItr, int startDoc, int endDoc,
int maxChildren) throws IOException {
int totalCount = 0;
double totalValue = 0;
int count = 0;
for (int doc = startDoc; doc < endDoc; doc = docItr.nextDoc()) {
if (values.advanceExact(doc)) {
if (++count > maxChildren) {
break;
}
final int docCount = values.docValueCount();
for (int index = 0; index < docCount; ++index) {
totalValue += values.nextValue();
}
totalCount += docCount;
}
}
return totalCount > 0 ? totalValue : missingValue;
}
},
/**
* Pick the average of all the values.
*/
AVG {
@Override
protected long pick(SortedNumericDocValues values) throws IOException {
final int count = values.docValueCount();
long total = 0;
for (int index = 0; index < count; ++index) {
total += values.nextValue();
}
return count > 1 ? Math.round((double) total / (double) count) : total;
}
@Override
protected long pick(SortedNumericDocValues values, long missingValue, DocIdSetIterator docItr, int startDoc, int endDoc,
int maxChildren) throws IOException {
int totalCount = 0;
long totalValue = 0;
int count = 0;
for (int doc = startDoc; doc < endDoc; doc = docItr.nextDoc()) {
if (values.advanceExact(doc)) {
if (++count > maxChildren) {
break;
}
final int docCount = values.docValueCount();
for (int index = 0; index < docCount; ++index) {
totalValue += values.nextValue();
}
totalCount += docCount;
}
}
if (totalCount < 1) {
return missingValue;
}
return totalCount > 1 ? Math.round((double) totalValue / (double) totalCount) : totalValue;
}
@Override
protected double pick(SortedNumericDoubleValues values) throws IOException {
final int count = values.docValueCount();
double total = 0;
for (int index = 0; index < count; ++index) {
total += values.nextValue();
}
return total / count;
}
@Override
protected double pick(SortedNumericDoubleValues values, double missingValue, DocIdSetIterator docItr, int startDoc, int endDoc,
int maxChildren) throws IOException {
int totalCount = 0;
double totalValue = 0;
int count = 0;
for (int doc = startDoc; doc < endDoc; doc = docItr.nextDoc()) {
if (values.advanceExact(doc)) {
if (++count > maxChildren) {
break;
}
final int docCount = values.docValueCount();
for (int index = 0; index < docCount; ++index) {
totalValue += values.nextValue();
}
totalCount += docCount;
}
}
if (totalCount < 1) {
return missingValue;
}
return totalValue / totalCount;
}
},
/**
* Pick the median of the values.
*/
MEDIAN {
@Override
protected long pick(SortedNumericDocValues values) throws IOException {
int count = values.docValueCount();
for (int i = 0; i < (count - 1) / 2; ++i) {
values.nextValue();
}
if (count % 2 == 0) {
return Math.round(((double) values.nextValue() + values.nextValue()) / 2);
} else {
return values.nextValue();
}
}
@Override
protected double pick(SortedNumericDoubleValues values) throws IOException {
int count = values.docValueCount();
for (int i = 0; i < (count - 1) / 2; ++i) {
values.nextValue();
}
if (count % 2 == 0) {
return (values.nextValue() + values.nextValue()) / 2;
} else {
return values.nextValue();
}
}
},
/**
* Pick the lowest value.
*/
MIN {
@Override
protected long pick(SortedNumericDocValues values) throws IOException {
return values.nextValue();
}
@Override
protected long pick(SortedNumericDocValues values, long missingValue, DocIdSetIterator docItr, int startDoc, int endDoc,
int maxChildren) throws IOException {
boolean hasValue = false;
long minValue = Long.MAX_VALUE;
int count = 0;
for (int doc = startDoc; doc < endDoc; doc = docItr.nextDoc()) {
if (values.advanceExact(doc)) {
if (++count > maxChildren) {
break;
}
minValue = Math.min(minValue, values.nextValue());
hasValue = true;
}
}
return hasValue ? minValue : missingValue;
}
@Override
protected double pick(SortedNumericDoubleValues values) throws IOException {
return values.nextValue();
}
@Override
protected double pick(SortedNumericDoubleValues values, double missingValue, DocIdSetIterator docItr, int startDoc, int endDoc,
int maxChildren) throws IOException {
boolean hasValue = false;
double minValue = Double.POSITIVE_INFINITY;
int count = 0;
for (int doc = startDoc; doc < endDoc; doc = docItr.nextDoc()) {
if (values.advanceExact(doc)) {
if (++count > maxChildren) {
break;
}
minValue = Math.min(minValue, values.nextValue());
hasValue = true;
}
}
return hasValue ? minValue : missingValue;
}
@Override
protected BytesRef pick(SortedBinaryDocValues values) throws IOException {
return values.nextValue();
}
@Override
protected BytesRef pick(BinaryDocValues values, BytesRefBuilder builder, DocIdSetIterator docItr, int startDoc, int endDoc,
int maxChildren) throws IOException {
BytesRefBuilder bytesRefBuilder = null;
int count = 0;
for (int doc = startDoc; doc < endDoc; doc = docItr.nextDoc()) {
if (values.advanceExact(doc)) {
if (++count > maxChildren) {
break;
}
final BytesRef innerValue = values.binaryValue();
if (bytesRefBuilder == null) {
builder.copyBytes(innerValue);
bytesRefBuilder = builder;
} else {
final BytesRef min = bytesRefBuilder.get().compareTo(innerValue) <= 0 ? bytesRefBuilder.get() : innerValue;
if (min == innerValue) {
bytesRefBuilder.copyBytes(min);
}
}
}
}
return bytesRefBuilder == null ? null : bytesRefBuilder.get();
}
@Override
protected int pick(SortedSetDocValues values) throws IOException {
return Math.toIntExact(values.nextOrd());
}
@Override
protected int pick(SortedDocValues values, DocIdSetIterator docItr, int startDoc, int endDoc, int maxChildren) throws IOException {
int ord = Integer.MAX_VALUE;
boolean hasValue = false;
int count = 0;
for (int doc = startDoc; doc < endDoc; doc = docItr.nextDoc()) {
if (values.advanceExact(doc)) {
if (++count > maxChildren) {
break;
}
final int innerOrd = values.ordValue();
ord = Math.min(ord, innerOrd);
hasValue = true;
}
}
return hasValue ? ord : -1;
}
},
/**
* Pick the highest value.
*/
MAX {
@Override
protected long pick(SortedNumericDocValues values) throws IOException {
final int count = values.docValueCount();
for (int i = 0; i < count - 1; ++i) {
values.nextValue();
}
return values.nextValue();
}
@Override
protected long pick(SortedNumericDocValues values, long missingValue, DocIdSetIterator docItr, int startDoc, int endDoc,
int maxChildren) throws IOException {
boolean hasValue = false;
long maxValue = Long.MIN_VALUE;
int count = 0;
for (int doc = startDoc; doc < endDoc; doc = docItr.nextDoc()) {
if (values.advanceExact(doc)) {
if (++count > maxChildren) {
break;
}
final int docCount = values.docValueCount();
for (int i = 0; i < docCount - 1; ++i) {
values.nextValue();
}
maxValue = Math.max(maxValue, values.nextValue());
hasValue = true;
}
}
return hasValue ? maxValue : missingValue;
}
@Override
protected double pick(SortedNumericDoubleValues values) throws IOException {
final int count = values.docValueCount();
for (int i = 0; i < count - 1; ++i) {
values.nextValue();
}
return values.nextValue();
}
@Override
protected double pick(SortedNumericDoubleValues values, double missingValue, DocIdSetIterator docItr, int startDoc, int endDoc,
int maxChildren) throws IOException {
boolean hasValue = false;
double maxValue = Double.NEGATIVE_INFINITY;
int count = 0;
for (int doc = startDoc; doc < endDoc; doc = docItr.nextDoc()) {
if (values.advanceExact(doc)) {
if (++count > maxChildren) {
break;
}
final int docCount = values.docValueCount();
for (int i = 0; i < docCount - 1; ++i) {
values.nextValue();
}
maxValue = Math.max(maxValue, values.nextValue());
hasValue = true;
}
}
return hasValue ? maxValue : missingValue;
}
@Override
protected BytesRef pick(SortedBinaryDocValues values) throws IOException {
int count = values.docValueCount();
for (int i = 0; i < count - 1; ++i) {
values.nextValue();
}
return values.nextValue();
}
@Override
protected BytesRef pick(BinaryDocValues values, BytesRefBuilder builder, DocIdSetIterator docItr, int startDoc, int endDoc,
int maxChildren) throws IOException {
BytesRefBuilder bytesRefBuilder = null;
int count = 0;
for (int doc = startDoc; doc < endDoc; doc = docItr.nextDoc()) {
if (values.advanceExact(doc)) {
if (++count > maxChildren) {
break;
}
final BytesRef innerValue = values.binaryValue();
if (bytesRefBuilder == null) {
builder.copyBytes(innerValue);
bytesRefBuilder = builder;
} else {
final BytesRef max = bytesRefBuilder.get().compareTo(innerValue) > 0 ? bytesRefBuilder.get() : innerValue;
if (max == innerValue) {
bytesRefBuilder.copyBytes(max);
}
}
}
}
return bytesRefBuilder == null ? null : bytesRefBuilder.get();
}
@Override
protected int pick(SortedSetDocValues values) throws IOException {
long maxOrd = -1;
for (long ord = values.nextOrd(); ord != SortedSetDocValues.NO_MORE_ORDS; ord = values.nextOrd()) {
maxOrd = ord;
}
return Math.toIntExact(maxOrd);
}
@Override
protected int pick(SortedDocValues values, DocIdSetIterator docItr, int startDoc, int endDoc, int maxChildren) throws IOException {
int ord = -1;
int count = 0;
for (int doc = startDoc; doc < endDoc; doc = docItr.nextDoc()) {
if (values.advanceExact(doc)) {
if (++count > maxChildren) {
break;
}
ord = Math.max(ord, values.ordValue());
}
}
return ord;
}
};
/**
* A case insensitive version of {@link #valueOf(String)}
*
* @throws IllegalArgumentException if the given string doesn't match a sort mode or is null
.
*/
public static MultiValueMode fromString(String sortMode) {
try {
return valueOf(sortMode.toUpperCase(Locale.ROOT));
} catch (Exception e) {
throw new IllegalArgumentException("Illegal sort mode: " + sortMode);
}
}
/**
* Return a {@link NumericDocValues} instance that can be used to sort documents
* with this mode and the provided values. When a document has no value,
* missingValue
is returned.
*
* Allowed Modes: SUM, AVG, MEDIAN, MIN, MAX
*/
public NumericDocValues select(final SortedNumericDocValues values) {
final NumericDocValues singleton = DocValues.unwrapSingleton(values);
if (singleton != null) {
return singleton;
} else {
return new AbstractNumericDocValues() {
private long value;
@Override
public boolean advanceExact(int target) throws IOException {
if (values.advanceExact(target)) {
value = pick(values);
return true;
}
return false;
}
@Override
public int docID() {
return values.docID();
}
@Override
public long longValue() throws IOException {
return value;
}
};
}
}
protected long pick(SortedNumericDocValues values) throws IOException {
throw new IllegalArgumentException("Unsupported sort mode: " + this);
}
/**
* Return a {@link NumericDocValues} instance that can be used to sort root documents
* with this mode, the provided values and filters for root/inner documents.
*
* For every root document, the values of its inner documents will be aggregated.
* If none of the inner documents has a value, then missingValue
is returned.
*
* Allowed Modes: SUM, AVG, MIN, MAX
*
* NOTE: Calling the returned instance on docs that are not root docs is illegal
* The returned instance can only be evaluate the current and upcoming docs
*/
public NumericDocValues select(final SortedNumericDocValues values, final long missingValue, final BitSet parentDocs,
final DocIdSetIterator childDocs, int maxDoc, int maxChildren) throws IOException {
if (parentDocs == null || childDocs == null) {
return FieldData.replaceMissing(DocValues.emptyNumeric(), missingValue);
}
return new AbstractNumericDocValues() {
int lastSeenParentDoc = -1;
long lastEmittedValue = missingValue;
@Override
public boolean advanceExact(int parentDoc) throws IOException {
assert parentDoc >= lastSeenParentDoc : "can only evaluate current and upcoming parent docs";
if (parentDoc == lastSeenParentDoc) {
return true;
} else if (parentDoc == 0) {
lastEmittedValue = missingValue;
return true;
}
final int prevParentDoc = parentDocs.prevSetBit(parentDoc - 1);
final int firstChildDoc;
if (childDocs.docID() > prevParentDoc) {
firstChildDoc = childDocs.docID();
} else {
firstChildDoc = childDocs.advance(prevParentDoc + 1);
}
lastSeenParentDoc = parentDoc;
lastEmittedValue = pick(values, missingValue, childDocs, firstChildDoc, parentDoc, maxChildren);
return true;
}
@Override
public int docID() {
return lastSeenParentDoc;
}
@Override
public long longValue() {
return lastEmittedValue;
}
};
}
protected long pick(SortedNumericDocValues values, long missingValue, DocIdSetIterator docItr, int startDoc, int endDoc,
int maxChildren) throws IOException {
throw new IllegalArgumentException("Unsupported sort mode: " + this);
}
/**
* Return a {@link NumericDoubleValues} instance that can be used to sort documents
* with this mode and the provided values. When a document has no value,
* missingValue
is returned.
*
* Allowed Modes: SUM, AVG, MEDIAN, MIN, MAX
*/
public NumericDoubleValues select(final SortedNumericDoubleValues values) {
final NumericDoubleValues singleton = FieldData.unwrapSingleton(values);
if (singleton != null) {
return singleton;
} else {
return new NumericDoubleValues() {
private double value;
@Override
public boolean advanceExact(int target) throws IOException {
if (values.advanceExact(target)) {
value = pick(values);
return true;
}
return false;
}
@Override
public double doubleValue() throws IOException {
return this.value;
}
};
}
}
protected double pick(SortedNumericDoubleValues values) throws IOException {
throw new IllegalArgumentException("Unsupported sort mode: " + this);
}
/**
* Return a {@link NumericDoubleValues} instance that can be used to sort root documents
* with this mode, the provided values and filters for root/inner documents.
*
* For every root document, the values of its inner documents will be aggregated.
* If none of the inner documents has a value, then missingValue
is returned.
*
* Allowed Modes: SUM, AVG, MIN, MAX
*
* NOTE: Calling the returned instance on docs that are not root docs is illegal
* The returned instance can only be evaluate the current and upcoming docs
*/
public NumericDoubleValues select(final SortedNumericDoubleValues values, final double missingValue, final BitSet parentDocs,
final DocIdSetIterator childDocs, int maxDoc, int maxChildren) throws IOException {
if (parentDocs == null || childDocs == null) {
return FieldData.replaceMissing(FieldData.emptyNumericDouble(), missingValue);
}
return new NumericDoubleValues() {
int lastSeenParentDoc = 0;
double lastEmittedValue = missingValue;
@Override
public boolean advanceExact(int parentDoc) throws IOException {
assert parentDoc >= lastSeenParentDoc : "can only evaluate current and upcoming parent docs";
if (parentDoc == lastSeenParentDoc) {
return true;
}
final int prevParentDoc = parentDocs.prevSetBit(parentDoc - 1);
final int firstChildDoc;
if (childDocs.docID() > prevParentDoc) {
firstChildDoc = childDocs.docID();
} else {
firstChildDoc = childDocs.advance(prevParentDoc + 1);
}
lastSeenParentDoc = parentDoc;
lastEmittedValue = pick(values, missingValue, childDocs, firstChildDoc, parentDoc, maxChildren);
return true;
}
@Override
public double doubleValue() throws IOException {
return lastEmittedValue;
}
};
}
protected double pick(SortedNumericDoubleValues values, double missingValue, DocIdSetIterator docItr, int startDoc, int endDoc,
int maxChildren) throws IOException {
throw new IllegalArgumentException("Unsupported sort mode: " + this);
}
/**
* Return a {@link BinaryDocValues} instance that can be used to sort documents
* with this mode and the provided values. When a document has no value,
* missingValue
is returned.
*
* Allowed Modes: MIN, MAX
*/
public BinaryDocValues select(final SortedBinaryDocValues values, final BytesRef missingValue) {
final BinaryDocValues singleton = FieldData.unwrapSingleton(values);
if (singleton != null) {
if (missingValue == null) {
return singleton;
}
return new AbstractBinaryDocValues() {
private BytesRef value;
@Override
public boolean advanceExact(int target) throws IOException {
this.value = singleton.advanceExact(target) ? singleton.binaryValue() : missingValue;
return true;
}
@Override
public BytesRef binaryValue() throws IOException {
return this.value;
}
};
} else {
return new AbstractBinaryDocValues() {
private BytesRef value;
@Override
public boolean advanceExact(int target) throws IOException {
if (values.advanceExact(target)) {
value = pick(values);
return true;
} else {
value = missingValue;
return missingValue != null;
}
}
@Override
public BytesRef binaryValue() throws IOException {
return value;
}
};
}
}
protected BytesRef pick(SortedBinaryDocValues values) throws IOException {
throw new IllegalArgumentException("Unsupported sort mode: " + this);
}
/**
* Return a {@link BinaryDocValues} instance that can be used to sort root documents
* with this mode, the provided values and filters for root/inner documents.
*
* For every root document, the values of its inner documents will be aggregated.
* If none of the inner documents has a value, then missingValue
is returned.
*
* Allowed Modes: MIN, MAX
*
* NOTE: Calling the returned instance on docs that are not root docs is illegal
* The returned instance can only be evaluate the current and upcoming docs
*/
public BinaryDocValues select(final SortedBinaryDocValues values, final BytesRef missingValue, final BitSet parentDocs,
final DocIdSetIterator childDocs, int maxDoc, int maxChildren) throws IOException {
if (parentDocs == null || childDocs == null) {
return select(FieldData.emptySortedBinary(), missingValue);
}
final BinaryDocValues selectedValues = select(values, null);
return new AbstractBinaryDocValues() {
final BytesRefBuilder builder = new BytesRefBuilder();
int lastSeenParentDoc = 0;
BytesRef lastEmittedValue = missingValue;
@Override
public boolean advanceExact(int parentDoc) throws IOException {
assert parentDoc >= lastSeenParentDoc : "can only evaluate current and upcoming root docs";
if (parentDoc == lastSeenParentDoc) {
return true;
}
final int prevParentDoc = parentDocs.prevSetBit(parentDoc - 1);
final int firstChildDoc;
if (childDocs.docID() > prevParentDoc) {
firstChildDoc = childDocs.docID();
} else {
firstChildDoc = childDocs.advance(prevParentDoc + 1);
}
lastSeenParentDoc = parentDoc;
lastEmittedValue = pick(selectedValues, builder, childDocs, firstChildDoc, parentDoc, maxChildren);
if (lastEmittedValue == null) {
lastEmittedValue = missingValue;
}
return true;
}
@Override
public BytesRef binaryValue() throws IOException {
return lastEmittedValue;
}
};
}
protected BytesRef pick(BinaryDocValues values, BytesRefBuilder builder, DocIdSetIterator docItr, int startDoc, int endDoc,
int maxChildren) throws IOException {
throw new IllegalArgumentException("Unsupported sort mode: " + this);
}
/**
* Return a {@link SortedDocValues} instance that can be used to sort documents
* with this mode and the provided values.
*
* Allowed Modes: MIN, MAX
*/
public SortedDocValues select(final SortedSetDocValues values) {
if (values.getValueCount() >= Integer.MAX_VALUE) {
throw new UnsupportedOperationException("fields containing more than " + (Integer.MAX_VALUE - 1) +
" unique terms are unsupported");
}
final SortedDocValues singleton = DocValues.unwrapSingleton(values);
if (singleton != null) {
return singleton;
} else {
return new AbstractSortedDocValues() {
int ord;
@Override
public boolean advanceExact(int target) throws IOException {
if (values.advanceExact(target)) {
ord = pick(values);
return true;
} else {
ord = -1;
return false;
}
}
@Override
public int docID() {
return values.docID();
}
@Override
public int ordValue() {
assert ord != -1;
return ord;
}
@Override
public BytesRef lookupOrd(int ord) throws IOException {
return values.lookupOrd(ord);
}
@Override
public int getValueCount() {
return (int) values.getValueCount();
}
};
}
}
protected int pick(SortedSetDocValues values) throws IOException {
throw new IllegalArgumentException("Unsupported sort mode: " + this);
}
/**
* Return a {@link SortedDocValues} instance that can be used to sort root documents
* with this mode, the provided values and filters for root/inner documents.
*
* For every root document, the values of its inner documents will be aggregated.
*
* Allowed Modes: MIN, MAX
*
* NOTE: Calling the returned instance on docs that are not root docs is illegal
* The returned instance can only be evaluate the current and upcoming docs
*/
public SortedDocValues select(final SortedSetDocValues values, final BitSet parentDocs, final DocIdSetIterator childDocs,
int maxChildren) throws IOException {
if (parentDocs == null || childDocs == null) {
return select(DocValues.emptySortedSet());
}
final SortedDocValues selectedValues = select(values);
return new AbstractSortedDocValues() {
int docID = -1;
int lastSeenParentDoc = 0;
int lastEmittedOrd = -1;
@Override
public BytesRef lookupOrd(int ord) throws IOException {
return selectedValues.lookupOrd(ord);
}
@Override
public int getValueCount() {
return selectedValues.getValueCount();
}
@Override
public boolean advanceExact(int parentDoc) throws IOException {
assert parentDoc >= lastSeenParentDoc : "can only evaluate current and upcoming root docs";
if (parentDoc == lastSeenParentDoc) {
return lastEmittedOrd != -1;
}
final int prevParentDoc = parentDocs.prevSetBit(parentDoc - 1);
final int firstChildDoc;
if (childDocs.docID() > prevParentDoc) {
firstChildDoc = childDocs.docID();
} else {
firstChildDoc = childDocs.advance(prevParentDoc + 1);
}
docID = lastSeenParentDoc = parentDoc;
lastEmittedOrd = pick(selectedValues, childDocs, firstChildDoc, parentDoc, maxChildren);
return lastEmittedOrd != -1;
}
@Override
public int docID() {
return docID;
}
@Override
public int ordValue() {
return lastEmittedOrd;
}
};
}
protected int pick(SortedDocValues values, DocIdSetIterator docItr, int startDoc, int endDoc, int maxChildren) throws IOException {
throw new IllegalArgumentException("Unsupported sort mode: " + this);
}
@Override
public void writeTo(StreamOutput out) throws IOException {
out.writeEnum(this);
}
public static MultiValueMode readMultiValueModeFrom(StreamInput in) throws IOException {
return in.readEnum(MultiValueMode.class);
}
}