org.elasticsearch.search.MultiValueMode Maven / Gradle / Ivy
/*
* 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) throws IOException {
int totalCount = 0;
long totalValue = 0;
for (int doc = startDoc; doc < endDoc; doc = docItr.nextDoc()) {
if (values.advanceExact(doc)) {
final int count = values.docValueCount();
for (int index = 0; index < count; ++index) {
totalValue += values.nextValue();
}
totalCount += count;
}
}
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) throws IOException {
int totalCount = 0;
double totalValue = 0;
for (int doc = startDoc; doc < endDoc; doc = docItr.nextDoc()) {
if (values.advanceExact(doc)) {
final int count = values.docValueCount();
for (int index = 0; index < count; ++index) {
totalValue += values.nextValue();
}
totalCount += count;
}
}
return totalCount > 0 ? totalValue : missingValue;
}
@Override
protected double pick(UnsortedNumericDoubleValues values) throws IOException {
final int count = values.docValueCount();
double total = 0;
for (int index = 0; index < count; ++index) {
total += values.nextValue();
}
return total;
}
},
/**
* 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) throws IOException {
int totalCount = 0;
long totalValue = 0;
for (int doc = startDoc; doc < endDoc; doc = docItr.nextDoc()) {
if (values.advanceExact(doc)) {
final int count = values.docValueCount();
for (int index = 0; index < count; ++index) {
totalValue += values.nextValue();
}
totalCount += count;
}
}
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) throws IOException {
int totalCount = 0;
double totalValue = 0;
for (int doc = startDoc; doc < endDoc; doc = docItr.nextDoc()) {
if (values.advanceExact(doc)) {
final int count = values.docValueCount();
for (int index = 0; index < count; ++index) {
totalValue += values.nextValue();
}
totalCount += count;
}
}
if (totalCount < 1) {
return missingValue;
}
return totalValue/totalCount;
}
@Override
protected double pick(UnsortedNumericDoubleValues values) throws IOException {
final int count = values.docValueCount();
double total = 0;
for (int index = 0; index < count; ++index) {
total += values.nextValue();
}
return total/count;
}
},
/**
* 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) throws IOException {
boolean hasValue = false;
long minValue = Long.MAX_VALUE;
for (int doc = startDoc; doc < endDoc; doc = docItr.nextDoc()) {
if (values.advanceExact(doc)) {
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) throws IOException {
boolean hasValue = false;
double minValue = Double.POSITIVE_INFINITY;
for (int doc = startDoc; doc < endDoc; doc = docItr.nextDoc()) {
if (values.advanceExact(doc)) {
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) throws IOException {
BytesRefBuilder value = null;
for (int doc = startDoc; doc < endDoc; doc = docItr.nextDoc()) {
if (values.advanceExact(doc)) {
final BytesRef innerValue = values.binaryValue();
if (value == null) {
builder.copyBytes(innerValue);
value = builder;
} else {
final BytesRef min = value.get().compareTo(innerValue) <= 0 ? value.get() : innerValue;
if (min == innerValue) {
value.copyBytes(min);
}
}
}
}
return value == null ? null : value.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) throws IOException {
int ord = Integer.MAX_VALUE;
boolean hasValue = false;
for (int doc = startDoc; doc < endDoc; doc = docItr.nextDoc()) {
if (values.advanceExact(doc)) {
final int innerOrd = values.ordValue();
ord = Math.min(ord, innerOrd);
hasValue = true;
}
}
return hasValue ? ord : -1;
}
@Override
protected double pick(UnsortedNumericDoubleValues values) throws IOException {
int count = values.docValueCount();
double min = Double.POSITIVE_INFINITY;
for (int index = 0; index < count; ++index) {
min = Math.min(values.nextValue(), min);
}
return min;
}
},
/**
* 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) throws IOException {
boolean hasValue = false;
long maxValue = Long.MIN_VALUE;
for (int doc = startDoc; doc < endDoc; doc = docItr.nextDoc()) {
if (values.advanceExact(doc)) {
final int count = values.docValueCount();
for (int i = 0; i < count - 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) throws IOException {
boolean hasValue = false;
double maxValue = Double.NEGATIVE_INFINITY;
for (int doc = startDoc; doc < endDoc; doc = docItr.nextDoc()) {
if (values.advanceExact(doc)) {
final int count = values.docValueCount();
for (int i = 0; i < count - 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) throws IOException {
BytesRefBuilder value = null;
for (int doc = startDoc; doc < endDoc; doc = docItr.nextDoc()) {
if (values.advanceExact(doc)) {
final BytesRef innerValue = values.binaryValue();
if (value == null) {
builder.copyBytes(innerValue);
value = builder;
} else {
final BytesRef max = value.get().compareTo(innerValue) > 0 ? value.get() : innerValue;
if (max == innerValue) {
value.copyBytes(max);
}
}
}
}
return value == null ? null : value.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) throws IOException {
int ord = -1;
for (int doc = startDoc; doc < endDoc; doc = docItr.nextDoc()) {
if (values.advanceExact(doc)) {
ord = Math.max(ord, values.ordValue());
}
}
return ord;
}
@Override
protected double pick(UnsortedNumericDoubleValues values) throws IOException {
int count = values.docValueCount();
double max = Double.NEGATIVE_INFINITY;
for (int index = 0; index < count; ++index) {
max = Math.max(values.nextValue(), max);
}
return max;
}
};
/**
* 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 long missingValue) {
final NumericDocValues singleton = DocValues.unwrapSingleton(values);
if (singleton != null) {
return new AbstractNumericDocValues() {
private boolean hasValue;
@Override
public boolean advanceExact(int target) throws IOException {
hasValue = singleton.advanceExact(target);
return true;
}
@Override
public int docID() {
return singleton.docID();
}
@Override
public long longValue() throws IOException {
return hasValue ? singleton.longValue() : missingValue;
}
};
} else {
return new AbstractNumericDocValues() {
private boolean hasValue;
@Override
public boolean advanceExact(int target) throws IOException {
hasValue = values.advanceExact(target);
return true;
}
@Override
public int docID() {
return values.docID();
}
@Override
public long longValue() throws IOException {
return hasValue ? pick(values) : missingValue;
}
};
}
}
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 rootDocs, final DocIdSetIterator innerDocs, int maxDoc) throws IOException {
if (rootDocs == null || innerDocs == null) {
return select(DocValues.emptySortedNumeric(maxDoc), missingValue);
}
return new AbstractNumericDocValues() {
int lastSeenRootDoc = -1;
long lastEmittedValue = missingValue;
@Override
public boolean advanceExact(int rootDoc) throws IOException {
assert rootDocs.get(rootDoc) : "can only sort root documents";
assert rootDoc >= lastSeenRootDoc : "can only evaluate current and upcoming root docs";
if (rootDoc == lastSeenRootDoc) {
return true;
} else if (rootDoc == 0) {
lastEmittedValue = missingValue;
return true;
}
final int prevRootDoc = rootDocs.prevSetBit(rootDoc - 1);
final int firstNestedDoc;
if (innerDocs.docID() > prevRootDoc) {
firstNestedDoc = innerDocs.docID();
} else {
firstNestedDoc = innerDocs.advance(prevRootDoc + 1);
}
lastSeenRootDoc = rootDoc;
lastEmittedValue = pick(values, missingValue, innerDocs, firstNestedDoc, rootDoc);
return true;
}
@Override
public int docID() {
return lastSeenRootDoc;
}
@Override
public long longValue() {
return lastEmittedValue;
}
};
}
protected long pick(SortedNumericDocValues values, long missingValue, DocIdSetIterator docItr, int startDoc, int endDoc) 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 double missingValue) {
final NumericDoubleValues singleton = FieldData.unwrapSingleton(values);
if (singleton != null) {
return new NumericDoubleValues() {
private boolean hasValue;
@Override
public boolean advanceExact(int doc) throws IOException {
hasValue = singleton.advanceExact(doc);
return true;
}
@Override
public double doubleValue() throws IOException {
return hasValue ? singleton.doubleValue() : missingValue;
}
};
} else {
return new NumericDoubleValues() {
private boolean hasValue;
@Override
public boolean advanceExact(int target) throws IOException {
hasValue = values.advanceExact(target);
return true;
}
@Override
public double doubleValue() throws IOException {
return hasValue ? pick(values) : missingValue;
}
};
}
}
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 rootDocs, final DocIdSetIterator innerDocs, int maxDoc) throws IOException {
if (rootDocs == null || innerDocs == null) {
return select(FieldData.emptySortedNumericDoubles(), missingValue);
}
return new NumericDoubleValues() {
int lastSeenRootDoc = 0;
double lastEmittedValue = missingValue;
@Override
public boolean advanceExact(int rootDoc) throws IOException {
assert rootDocs.get(rootDoc) : "can only sort root documents";
assert rootDoc >= lastSeenRootDoc : "can only evaluate current and upcoming root docs";
if (rootDoc == lastSeenRootDoc) {
return true;
}
final int prevRootDoc = rootDocs.prevSetBit(rootDoc - 1);
final int firstNestedDoc;
if (innerDocs.docID() > prevRootDoc) {
firstNestedDoc = innerDocs.docID();
} else {
firstNestedDoc = innerDocs.advance(prevRootDoc + 1);
}
lastSeenRootDoc = rootDoc;
lastEmittedValue = pick(values, missingValue, innerDocs, firstNestedDoc, rootDoc);
return true;
}
@Override
public double doubleValue() throws IOException {
return lastEmittedValue;
}
};
}
protected double pick(SortedNumericDoubleValues values, double missingValue, DocIdSetIterator docItr, int startDoc, int endDoc) 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 boolean hasValue;
@Override
public boolean advanceExact(int target) throws IOException {
hasValue = singleton.advanceExact(target);
return true;
}
@Override
public BytesRef binaryValue() throws IOException {
return hasValue ? singleton.binaryValue() : missingValue;
}
};
} 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 rootDocs, final DocIdSetIterator innerDocs, int maxDoc) throws IOException {
if (rootDocs == null || innerDocs == null) {
return select(FieldData.emptySortedBinary(), missingValue);
}
final BinaryDocValues selectedValues = select(values, null);
return new AbstractBinaryDocValues() {
final BytesRefBuilder builder = new BytesRefBuilder();
int lastSeenRootDoc = 0;
BytesRef lastEmittedValue = missingValue;
@Override
public boolean advanceExact(int rootDoc) throws IOException {
assert rootDocs.get(rootDoc) : "can only sort root documents";
assert rootDoc >= lastSeenRootDoc : "can only evaluate current and upcoming root docs";
if (rootDoc == lastSeenRootDoc) {
return true;
}
final int prevRootDoc = rootDocs.prevSetBit(rootDoc - 1);
final int firstNestedDoc;
if (innerDocs.docID() > prevRootDoc) {
firstNestedDoc = innerDocs.docID();
} else {
firstNestedDoc = innerDocs.advance(prevRootDoc + 1);
}
lastSeenRootDoc = rootDoc;
lastEmittedValue = pick(selectedValues, builder, innerDocs, firstNestedDoc, rootDoc);
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) 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 rootDocs, final DocIdSetIterator innerDocs) throws IOException {
if (rootDocs == null || innerDocs == null) {
return select(DocValues.emptySortedSet());
}
final SortedDocValues selectedValues = select(values);
return new AbstractSortedDocValues() {
int docID = -1;
int lastSeenRootDoc = 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 rootDoc) throws IOException {
assert rootDocs.get(rootDoc) : "can only sort root documents";
assert rootDoc >= lastSeenRootDoc : "can only evaluate current and upcoming root docs";
if (rootDoc == lastSeenRootDoc) {
return lastEmittedOrd != -1;
}
final int prevRootDoc = rootDocs.prevSetBit(rootDoc - 1);
final int firstNestedDoc;
if (innerDocs.docID() > prevRootDoc) {
firstNestedDoc = innerDocs.docID();
} else {
firstNestedDoc = innerDocs.advance(prevRootDoc + 1);
}
docID = lastSeenRootDoc = rootDoc;
lastEmittedOrd = pick(selectedValues, innerDocs, firstNestedDoc, rootDoc);
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) 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, MIN, MAX
*/
public NumericDoubleValues select(final UnsortedNumericDoubleValues values, final double missingValue) {
return new NumericDoubleValues() {
private boolean hasValue;
@Override
public boolean advanceExact(int doc) throws IOException {
hasValue = values.advanceExact(doc);
return true;
}
@Override
public double doubleValue() throws IOException {
return hasValue ? pick(values) : missingValue;
}
};
}
protected double pick(UnsortedNumericDoubleValues values) throws IOException {
throw new IllegalArgumentException("Unsupported sort mode: " + this);
}
/**
* Interface allowing custom value generators to be used in MultiValueMode.
*/
// TODO: why do we need it???
public interface UnsortedNumericDoubleValues {
boolean advanceExact(int doc) throws IOException;
int docValueCount() throws IOException;
double nextValue() throws IOException;
}
@Override
public void writeTo(StreamOutput out) throws IOException {
out.writeEnum(this);
}
public static MultiValueMode readMultiValueModeFrom(StreamInput in) throws IOException {
return in.readEnum(MultiValueMode.class);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy