|
|
@@ -19,6 +19,7 @@ import org.elasticsearch.common.util.BigArrays;
|
|
|
import org.elasticsearch.common.util.BitArray;
|
|
|
import org.elasticsearch.common.util.DoubleArray;
|
|
|
import org.elasticsearch.common.util.LongArray;
|
|
|
+import org.elasticsearch.common.util.ObjectArray;
|
|
|
import org.elasticsearch.index.fielddata.NumericDoubleValues;
|
|
|
import org.elasticsearch.search.DocValueFormat;
|
|
|
import org.elasticsearch.search.MultiValueMode;
|
|
|
@@ -33,8 +34,8 @@ import org.elasticsearch.search.aggregations.support.ValuesSourceRegistry;
|
|
|
import org.elasticsearch.search.sort.BucketedSort;
|
|
|
import org.elasticsearch.search.sort.SortBuilder;
|
|
|
import org.elasticsearch.search.sort.SortValue;
|
|
|
-import org.elasticsearch.xpack.core.common.search.aggregations.MissingHelper;
|
|
|
import org.elasticsearch.xpack.analytics.topmetrics.InternalTopMetrics.MetricValue;
|
|
|
+import org.elasticsearch.xpack.core.common.search.aggregations.MissingHelper;
|
|
|
|
|
|
import java.io.IOException;
|
|
|
import java.util.ArrayList;
|
|
|
@@ -398,20 +399,32 @@ class TopMetricsAggregator extends NumericMetricsAggregator.MultiValue {
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * Loads metrics for whole numbers.
|
|
|
+ * Loads metrics fields with segment ordinals.
|
|
|
*/
|
|
|
- static class GlobalOrdsValues extends CollectingMetricValues {
|
|
|
+ static class SegmentOrdsValues extends CollectingMetricValues {
|
|
|
private final ValuesSource.Bytes.WithOrdinals valuesSource;
|
|
|
- private SortedSetDocValues globalOrds;
|
|
|
- private LongArray values;
|
|
|
+ /**
|
|
|
+ * Reference to the segment's doc values so we can convert the
|
|
|
+ * {@link #segmentOrds} into strings on the way out.
|
|
|
+ */
|
|
|
+ private ObjectArray<SortedSetDocValues> segmentResolve;
|
|
|
+ /**
|
|
|
+ * Terms ordinal in the segment.
|
|
|
+ */
|
|
|
+ private LongArray segmentOrds;
|
|
|
|
|
|
- GlobalOrdsValues(int size, BigArrays bigArrays, String name, ValuesSourceConfig config) {
|
|
|
+ SegmentOrdsValues(int size, BigArrays bigArrays, String name, ValuesSourceConfig config) {
|
|
|
super(bigArrays, name, config);
|
|
|
- if (false == config.hasGlobalOrdinals()) {
|
|
|
- throw new IllegalArgumentException("top_metrics can only collect bytes that have global ordinals");
|
|
|
+ try {
|
|
|
+ valuesSource = (ValuesSource.Bytes.WithOrdinals) config.getValuesSource();
|
|
|
+ } catch (ClassCastException e) {
|
|
|
+ throw new IllegalArgumentException(
|
|
|
+ "top_metrics can only collect bytes that have segment ordinals but " + config.getDescription() + " does not",
|
|
|
+ e
|
|
|
+ );
|
|
|
}
|
|
|
- this.valuesSource = (ValuesSource.Bytes.WithOrdinals) config.getValuesSource();
|
|
|
- values = bigArrays.newLongArray(size, false);
|
|
|
+ segmentResolve = bigArrays.newObjectArray(size);
|
|
|
+ segmentOrds = bigArrays.newLongArray(size, false);
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
@@ -421,43 +434,48 @@ class TopMetricsAggregator extends NumericMetricsAggregator.MultiValue {
|
|
|
|
|
|
@Override
|
|
|
public MetricValue metricValue(long index) throws IOException {
|
|
|
- if (globalOrds == null) {
|
|
|
- // We didn't collect a single segment.
|
|
|
- return null;
|
|
|
- }
|
|
|
- long ord = values.get(index);
|
|
|
+ long ord = segmentOrds.get(index);
|
|
|
if (ord == -1) {
|
|
|
return null;
|
|
|
}
|
|
|
- return new MetricValue(config.format(), SortValue.from(BytesRef.deepCopyOf(globalOrds.lookupOrd(ord))));
|
|
|
+ SortedSetDocValues resolve = segmentResolve.get(index);
|
|
|
+ return new MetricValue(config.format(), SortValue.from(BytesRef.deepCopyOf(resolve.lookupOrd(ord))));
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
public void swap(long lhs, long rhs) {
|
|
|
- long tmp = values.get(lhs);
|
|
|
- values.set(lhs, values.get(rhs));
|
|
|
- values.set(rhs, tmp);
|
|
|
+ SortedSetDocValues tempSegmentResolve = segmentResolve.get(lhs);
|
|
|
+ segmentResolve.set(lhs, segmentResolve.get(rhs));
|
|
|
+ segmentResolve.set(rhs, tempSegmentResolve);
|
|
|
+ long tmpSegmentOrd = segmentOrds.get(lhs);
|
|
|
+ segmentOrds.set(lhs, segmentOrds.get(rhs));
|
|
|
+ segmentOrds.set(rhs, tmpSegmentOrd);
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
public Loader loader(LeafReaderContext ctx) throws IOException {
|
|
|
- globalOrds = valuesSource.globalOrdinalsValues(ctx);
|
|
|
+ SortedSetDocValues segmentOrdValues = valuesSource.ordinalsValues(ctx);
|
|
|
// For now just return the value that sorts first.
|
|
|
return (index, doc) -> {
|
|
|
- if (false == globalOrds.advanceExact(doc)) {
|
|
|
- values.set(index, -1);
|
|
|
- return;
|
|
|
+ if (index >= segmentResolve.size()) {
|
|
|
+ segmentResolve = bigArrays.grow(segmentResolve, index + 1);
|
|
|
}
|
|
|
- if (index >= values.size()) {
|
|
|
- values = bigArrays.grow(values, index + 1);
|
|
|
+ if (index >= segmentOrds.size()) {
|
|
|
+ segmentOrds = bigArrays.grow(segmentOrds, index + 1);
|
|
|
}
|
|
|
- values.set(index, globalOrds.nextOrd());
|
|
|
+ if (false == segmentOrdValues.advanceExact(doc)) {
|
|
|
+ segmentResolve.set(index, null);
|
|
|
+ segmentOrds.set(index, -1);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ segmentResolve.set(index, segmentOrdValues);
|
|
|
+ segmentOrds.set(index, segmentOrdValues.nextOrd());
|
|
|
};
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
public void close() {
|
|
|
- Releasables.close(values);
|
|
|
+ Releasables.close(segmentResolve, segmentOrds);
|
|
|
}
|
|
|
}
|
|
|
|