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 - Open Source, Distributed, RESTful Search Engine
/*
* 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.RandomAccessOrds;
import org.apache.lucene.index.SortedDocValues;
import org.apache.lucene.index.SortedNumericDocValues;
import org.apache.lucene.search.DocIdSetIterator;
import org.apache.lucene.util.BitSet;
import org.apache.lucene.util.Bits;
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.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, long missingValue, int doc) {
values.setDocument(doc);
final int count = values.count();
if (count > 0) {
long total = 0;
for (int index = 0; index < count; ++index) {
total += values.valueAt(index);
}
return total;
} else {
return missingValue;
}
}
@Override
protected long pick(SortedNumericDocValues values, long missingValue, DocIdSetIterator docItr, int startDoc, int endDoc) {
try {
int totalCount = 0;
long totalValue = 0;
for (int doc = startDoc; doc < endDoc; doc = docItr.nextDoc()) {
values.setDocument(doc);
final int count = values.count();
for (int index = 0; index < count; ++index) {
totalValue += values.valueAt(index);
}
totalCount += count;
}
return totalCount > 0 ? totalValue : missingValue;
} catch (IOException ioException) {
throw new RuntimeException(ioException);
}
}
@Override
protected double pick(SortedNumericDoubleValues values, double missingValue, int doc) {
values.setDocument(doc);
final int count = values.count();
if (count > 0) {
double total = 0;
for (int index = 0; index < count; ++index) {
total += values.valueAt(index);
}
return total;
} else {
return missingValue;
}
}
@Override
protected double pick(SortedNumericDoubleValues values, double missingValue, DocIdSetIterator docItr, int startDoc, int endDoc) {
try {
int totalCount = 0;
double totalValue = 0;
for (int doc = startDoc; doc < endDoc; doc = docItr.nextDoc()) {
values.setDocument(doc);
final int count = values.count();
for (int index = 0; index < count; ++index) {
totalValue += values.valueAt(index);
}
totalCount += count;
}
return totalCount > 0 ? totalValue : missingValue;
} catch (IOException ioException) {
throw new RuntimeException(ioException);
}
}
@Override
protected double pick(UnsortedNumericDoubleValues values, double missingValue, int doc) {
values.setDocument(doc);
final int count = values.count();
if (count > 0) {
double total = 0;
for (int index = 0; index < count; ++index) {
total += values.valueAt(index);
}
return total;
} else {
return missingValue;
}
}
},
/**
* Pick the average of all the values.
*/
AVG {
@Override
protected long pick(SortedNumericDocValues values, long missingValue, int doc) {
values.setDocument(doc);
final int count = values.count();
if (count > 0) {
long total = 0;
for (int index = 0; index < count; ++index) {
total += values.valueAt(index);
}
return count > 1 ? Math.round((double)total/(double)count) : total;
} else {
return missingValue;
}
}
@Override
protected long pick(SortedNumericDocValues values, long missingValue, DocIdSetIterator docItr, int startDoc, int endDoc) {
try {
int totalCount = 0;
long totalValue = 0;
for (int doc = startDoc; doc < endDoc; doc = docItr.nextDoc()) {
values.setDocument(doc);
final int count = values.count();
for (int index = 0; index < count; ++index) {
totalValue += values.valueAt(index);
}
totalCount += count;
}
if (totalCount < 1) {
return missingValue;
}
return totalCount > 1 ? Math.round((double)totalValue/(double)totalCount) : totalValue;
} catch (IOException ioException) {
throw new RuntimeException(ioException);
}
}
@Override
protected double pick(SortedNumericDoubleValues values, double missingValue, int doc) {
values.setDocument(doc);
final int count = values.count();
if (count > 0) {
double total = 0;
for (int index = 0; index < count; ++index) {
total += values.valueAt(index);
}
return total/count;
} else {
return missingValue;
}
}
@Override
protected double pick(SortedNumericDoubleValues values, double missingValue, DocIdSetIterator docItr, int startDoc, int endDoc) {
try {
int totalCount = 0;
double totalValue = 0;
for (int doc = startDoc; doc < endDoc; doc = docItr.nextDoc()) {
values.setDocument(doc);
final int count = values.count();
for (int index = 0; index < count; ++index) {
totalValue += values.valueAt(index);
}
totalCount += count;
}
if (totalCount < 1) {
return missingValue;
}
return totalValue/totalCount;
} catch (IOException ioException) {
throw new RuntimeException(ioException);
}
}
@Override
protected double pick(UnsortedNumericDoubleValues values, double missingValue, int doc) {
values.setDocument(doc);
final int count = values.count();
if (count > 0) {
double total = 0;
for (int index = 0; index < count; ++index) {
total += values.valueAt(index);
}
return total/count;
} else {
return missingValue;
}
}
},
/**
* Pick the median of the values.
*/
MEDIAN {
@Override
protected long pick(SortedNumericDocValues values, long missingValue, int doc) {
values.setDocument(doc);
int count = values.count();
if (count > 0) {
if (count % 2 == 0) {
count /= 2;
return Math.round((values.valueAt(count - 1) + values.valueAt(count))/2.0);
} else {
count /= 2;
return values.valueAt(count);
}
} else {
return missingValue;
}
}
@Override
protected double pick(SortedNumericDoubleValues values, double missingValue, int doc) {
values.setDocument(doc);
int count = values.count();
if (count > 0) {
if (count % 2 == 0) {
count /= 2;
return (values.valueAt(count - 1) + values.valueAt(count))/2.0;
} else {
count /= 2;
return values.valueAt(count);
}
} else {
return missingValue;
}
}
},
/**
* Pick the lowest value.
*/
MIN {
@Override
protected long pick(SortedNumericDocValues values, long missingValue, int doc) {
values.setDocument(doc);
final int count = values.count();
return count > 0 ? values.valueAt(0) : missingValue;
}
@Override
protected long pick(SortedNumericDocValues values, long missingValue, DocIdSetIterator docItr, int startDoc, int endDoc) {
try {
int totalCount = 0;
long minValue = Long.MAX_VALUE;
for (int doc = startDoc; doc < endDoc; doc = docItr.nextDoc()) {
values.setDocument(doc);
final int count = values.count();
if (count > 0) {
minValue = Math.min(minValue, values.valueAt(0));
}
totalCount += count;
}
return totalCount > 0 ? minValue : missingValue;
} catch (IOException ioException) {
throw new RuntimeException(ioException);
}
}
@Override
protected double pick(SortedNumericDoubleValues values, double missingValue, int doc) {
values.setDocument(doc);
int count = values.count();
return count > 0 ? values.valueAt(0) : missingValue;
}
@Override
protected double pick(SortedNumericDoubleValues values, double missingValue, DocIdSetIterator docItr, int startDoc, int endDoc) {
try {
int totalCount = 0;
double minValue = Double.MAX_VALUE;
for (int doc = startDoc; doc < endDoc; doc = docItr.nextDoc()) {
values.setDocument(doc);
final int count = values.count();
if (count > 0) {
minValue = Math.min(minValue, values.valueAt(0));
}
totalCount += count;
}
return totalCount > 0 ? minValue : missingValue;
} catch (IOException ioException) {
throw new RuntimeException(ioException);
}
}
@Override
protected BytesRef pick(SortedBinaryDocValues values, BytesRef missingValue, int doc) {
values.setDocument(doc);
final int count = values.count();
return count > 0 ? values.valueAt(0) : missingValue;
}
@Override
protected BytesRef pick(BinaryDocValues values, BytesRefBuilder builder, DocIdSetIterator docItr, int startDoc, int endDoc) {
try {
BytesRefBuilder value = null;
for (int doc = startDoc; doc < endDoc; doc = docItr.nextDoc()) {
final BytesRef innerValue = values.get(doc);
if (innerValue != null) {
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();
} catch (IOException ioException) {
throw new RuntimeException(ioException);
}
}
@Override
protected int pick(RandomAccessOrds values, int doc) {
values.setDocument(doc);
return values.cardinality() > 0 ? (int)values.ordAt(0) : -1;
}
@Override
protected int pick(SortedDocValues values, DocIdSetIterator docItr, int startDoc, int endDoc) {
try {
int ord = -1;
for (int doc = startDoc; doc < endDoc; doc = docItr.nextDoc()) {
final int innerOrd = values.getOrd(doc);
if (innerOrd != -1) {
ord = ord == -1 ? innerOrd : Math.min(ord, innerOrd);
}
}
return ord;
} catch (IOException ioException) {
throw new RuntimeException(ioException);
}
}
@Override
protected double pick(UnsortedNumericDoubleValues values, double missingValue, int doc) {
values.setDocument(doc);
int count = values.count();
double min = Double.MAX_VALUE;
for (int index = 0; index < count; ++index) {
min = Math.min(values.valueAt(index), min);
}
return count > 0 ? min : missingValue;
}
},
/**
* Pick the highest value.
*/
MAX {
@Override
protected long pick(SortedNumericDocValues values, long missingValue, int doc) {
values.setDocument(doc);
final int count = values.count();
return count > 0 ? values.valueAt(count - 1) : missingValue;
}
@Override
protected long pick(SortedNumericDocValues values, long missingValue, DocIdSetIterator docItr, int startDoc, int endDoc) {
try {
int totalCount = 0;
long maxValue = Long.MIN_VALUE;
for (int doc = startDoc; doc < endDoc; doc = docItr.nextDoc()) {
values.setDocument(doc);
final int count = values.count();
if (count > 0) {
maxValue = Math.max(maxValue, values.valueAt(count - 1));
}
totalCount += count;
}
return totalCount > 0 ? maxValue : missingValue;
} catch (IOException ioException) {
throw new RuntimeException(ioException);
}
}
@Override
protected double pick(SortedNumericDoubleValues values, double missingValue, int doc) {
values.setDocument(doc);
final int count = values.count();
return count > 0 ? values.valueAt(count - 1) : missingValue;
}
@Override
protected double pick(SortedNumericDoubleValues values, double missingValue, DocIdSetIterator docItr, int startDoc, int endDoc) {
try {
int totalCount = 0;
double maxValue = Double.MIN_VALUE;
for (int doc = startDoc; doc < endDoc; doc = docItr.nextDoc()) {
values.setDocument(doc);
final int count = values.count();
if (count > 0) {
maxValue = Math.max(maxValue, values.valueAt(count - 1));
}
totalCount += count;
}
return totalCount > 0 ? maxValue : missingValue;
} catch (IOException ioException) {
throw new RuntimeException(ioException);
}
}
@Override
protected BytesRef pick(SortedBinaryDocValues values, BytesRef missingValue, int doc) {
values.setDocument(doc);
final int count = values.count();
return count > 0 ? values.valueAt(count - 1) : missingValue;
}
@Override
protected BytesRef pick(BinaryDocValues values, BytesRefBuilder builder, DocIdSetIterator docItr, int startDoc, int endDoc) {
try {
BytesRefBuilder value = null;
for (int doc = startDoc; doc < endDoc; doc = docItr.nextDoc()) {
final BytesRef innerValue = values.get(doc);
if (innerValue != null) {
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();
} catch (IOException ioException) {
throw new RuntimeException(ioException);
}
}
@Override
protected int pick(RandomAccessOrds values, int doc) {
values.setDocument(doc);
final int count = values.cardinality();
return count > 0 ? (int)values.ordAt(count - 1) : -1;
}
@Override
protected int pick(SortedDocValues values, DocIdSetIterator docItr, int startDoc, int endDoc) {
try {
int ord = -1;
for (int doc = startDoc; doc < endDoc; doc = docItr.nextDoc()) {
final int innerOrd = values.getOrd(doc);
if (innerOrd != -1) {
ord = Math.max(ord, innerOrd);
}
}
return ord;
} catch (IOException ioException) {
throw new RuntimeException(ioException);
}
}
@Override
protected double pick(UnsortedNumericDoubleValues values, double missingValue, int doc) {
values.setDocument(doc);
int count = values.count();
double max = Double.MIN_VALUE;
for (int index = 0; index < count; ++index) {
max = Math.max(values.valueAt(index), max);
}
return count > 0 ? max : missingValue;
}
};
/**
* 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) {
final Bits docsWithField = DocValues.unwrapSingletonBits(values);
if (docsWithField == null || missingValue == 0) {
return singleton;
} else {
return new NumericDocValues() {
@Override
public long get(int docID) {
final long value = singleton.get(docID);
if (value == 0 && docsWithField.get(docID) == false) {
return missingValue;
}
return value;
}
};
}
} else {
return new NumericDocValues() {
@Override
public long get(int docID) {
return pick(values, missingValue, docID);
}
};
}
}
protected long pick(SortedNumericDocValues values, long missingValue, int doc) {
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 NumericDocValues() {
int lastSeenRootDoc = 0;
long lastEmittedValue = missingValue;
@Override
public long get(int rootDoc) {
assert rootDocs.get(rootDoc) : "can only sort root documents";
assert rootDoc >= lastSeenRootDoc : "can only evaluate current and upcoming root docs";
if (rootDoc == lastSeenRootDoc) {
return lastEmittedValue;
}
try {
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 lastEmittedValue;
} catch (IOException e) {
throw new RuntimeException(e);
}
}
};
}
protected long pick(SortedNumericDocValues values, long missingValue, DocIdSetIterator docItr, int startDoc, int endDoc) {
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) {
final Bits docsWithField = FieldData.unwrapSingletonBits(values);
if (docsWithField == null || missingValue == 0) {
return singleton;
} else {
return new NumericDoubleValues() {
@Override
public double get(int docID) {
final double value = singleton.get(docID);
if (value == 0 && docsWithField.get(docID) == false) {
return missingValue;
}
return value;
}
};
}
} else {
return new NumericDoubleValues() {
@Override
public double get(int docID) {
return pick(values, missingValue, docID);
}
};
}
}
protected double pick(SortedNumericDoubleValues values, double missingValue, int doc) {
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(maxDoc), missingValue);
}
return new NumericDoubleValues() {
int lastSeenRootDoc = 0;
double lastEmittedValue = missingValue;
@Override
public double get(int rootDoc) {
assert rootDocs.get(rootDoc) : "can only sort root documents";
assert rootDoc >= lastSeenRootDoc : "can only evaluate current and upcoming root docs";
if (rootDoc == lastSeenRootDoc) {
return lastEmittedValue;
}
try {
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 lastEmittedValue;
} catch (IOException e) {
throw new RuntimeException(e);
}
}
};
}
protected double pick(SortedNumericDoubleValues values, double missingValue, DocIdSetIterator docItr, int startDoc, int endDoc) {
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) {
final Bits docsWithField = FieldData.unwrapSingletonBits(values);
if (docsWithField == null) {
return singleton;
} else {
return new BinaryDocValues() {
@Override
public BytesRef get(int docID) {
final BytesRef value = singleton.get(docID);
if (value.length == 0 && docsWithField.get(docID) == false) {
return missingValue;
}
return value;
}
};
}
} else {
return new BinaryDocValues() {
@Override
public BytesRef get(int docID) {
return pick(values, missingValue, docID);
}
};
}
}
protected BytesRef pick(SortedBinaryDocValues values, BytesRef missingValue, int doc) {
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(maxDoc), missingValue);
}
final BinaryDocValues selectedValues = select(values, null);
return new BinaryDocValues() {
final BytesRefBuilder builder = new BytesRefBuilder();
int lastSeenRootDoc = 0;
BytesRef lastEmittedValue = missingValue;
@Override
public BytesRef get(int rootDoc) {
assert rootDocs.get(rootDoc) : "can only sort root documents";
assert rootDoc >= lastSeenRootDoc : "can only evaluate current and upcoming root docs";
if (rootDoc == lastSeenRootDoc) {
return lastEmittedValue;
}
try {
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 lastEmittedValue;
} catch (IOException e) {
throw new RuntimeException(e);
}
}
};
}
protected BytesRef pick(BinaryDocValues values, BytesRefBuilder builder, DocIdSetIterator docItr, int startDoc, int endDoc) {
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 RandomAccessOrds 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 SortedDocValues() {
@Override
public int getOrd(int docID) {
return pick(values, docID);
}
@Override
public BytesRef lookupOrd(int ord) {
return values.lookupOrd(ord);
}
@Override
public int getValueCount() {
return (int)values.getValueCount();
}
};
}
}
protected int pick(RandomAccessOrds values, int doc) {
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 RandomAccessOrds 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 SortedDocValues() {
int lastSeenRootDoc = 0;
int lastEmittedOrd = -1;
@Override
public BytesRef lookupOrd(int ord) {
return selectedValues.lookupOrd(ord);
}
@Override
public int getValueCount() {
return selectedValues.getValueCount();
}
@Override
public int getOrd(int rootDoc) {
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;
}
try {
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;
return lastEmittedOrd = pick(selectedValues, innerDocs, firstNestedDoc, rootDoc);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
};
}
protected int pick(SortedDocValues values, DocIdSetIterator docItr, int startDoc, int endDoc) {
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() {
@Override
public double get(int docID) {
return pick(values, missingValue, docID);
}
};
}
protected double pick(UnsortedNumericDoubleValues values, final double missingValue, int doc) {
throw new IllegalArgumentException("Unsupported sort mode: " + this);
}
/**
* Interface allowing custom value generators to be used in MultiValueMode.
*/
public interface UnsortedNumericDoubleValues {
int count();
void setDocument(int docId);
double valueAt(int index);
}
@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