Aggregations: Numeric metric aggregations are now formattable

You can now specify `format` in the request definition for most numeric metric aggregations. The exceptions are Percentile_Ranks, Cardinality and Value_Count as the response type of these can be different from the field type so the formatter won't work.

Closes #6812
This commit is contained in:
Colin Goodheart-Smithe 2014-12-22 15:05:29 +00:00
parent 04cb09f44c
commit 91e00c6c8e
48 changed files with 502 additions and 117 deletions

View File

@ -31,7 +31,7 @@ public abstract class InternalNumericMetricsAggregation extends InternalMetricsA
protected ValueFormatter valueFormatter;
public static abstract class SingleValue extends InternalNumericMetricsAggregation {
public static abstract class SingleValue extends InternalNumericMetricsAggregation implements NumericMetricsAggregation.SingleValue {
protected SingleValue() {}
@ -39,7 +39,13 @@ public abstract class InternalNumericMetricsAggregation extends InternalMetricsA
super(name, metaData);
}
public abstract double value();
public String getValueAsString() {
if (valueFormatter == null) {
return ValueFormatter.RAW.format(value());
} else {
return valueFormatter.format(value());
}
}
@Override
public Object getProperty(List<String> path) {
@ -54,7 +60,7 @@ public abstract class InternalNumericMetricsAggregation extends InternalMetricsA
}
public static abstract class MultiValue extends InternalNumericMetricsAggregation {
public static abstract class MultiValue extends InternalNumericMetricsAggregation implements NumericMetricsAggregation.MultiValue {
protected MultiValue() {}
@ -64,6 +70,14 @@ public abstract class InternalNumericMetricsAggregation extends InternalMetricsA
public abstract double value(String name);
public String valueAsString(String name) {
if (valueFormatter == null) {
return ValueFormatter.RAW.format(value(name));
} else {
return valueFormatter.format(value(name));
}
}
@Override
public Object getProperty(List<String> path) {
if (path.isEmpty()) {

View File

@ -0,0 +1,36 @@
/*
* 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.aggregations.metrics;
import org.elasticsearch.search.aggregations.Aggregation;
public interface NumericMetricsAggregation extends Aggregation {
public static interface SingleValue extends NumericMetricsAggregation {
double value();
String getValueAsString();
}
public static interface MultiValue extends NumericMetricsAggregation {
}
}

View File

@ -49,7 +49,7 @@ public abstract class NumericValuesSourceMetricsAggregatorParser<S extends Inter
@Override
public AggregatorFactory parse(String aggregationName, XContentParser parser, SearchContext context) throws IOException {
ValuesSourceParser<ValuesSource.Numeric> vsParser = ValuesSourceParser.numeric(aggregationName, aggType, context)
ValuesSourceParser<ValuesSource.Numeric> vsParser = ValuesSourceParser.numeric(aggregationName, aggType, context).formattable(true)
.build();
XContentParser.Token token;

View File

@ -20,6 +20,7 @@
package org.elasticsearch.search.aggregations.metrics;
import com.google.common.collect.Maps;
import org.elasticsearch.common.xcontent.XContentBuilder;
import java.io.IOException;
@ -33,6 +34,7 @@ public abstract class ValuesSourceMetricsAggregationBuilder<B extends ValuesSour
private String field;
private String script;
private String lang;
private String format;
private Map<String, Object> params;
protected ValuesSourceMetricsAggregationBuilder(String name, String type) {
@ -57,6 +59,12 @@ public abstract class ValuesSourceMetricsAggregationBuilder<B extends ValuesSour
return (B) this;
}
@SuppressWarnings("unchecked")
public B format(String format) {
this.format = format;
return (B) this;
}
@SuppressWarnings("unchecked")
public B params(Map<String, Object> params) {
if (this.params == null) {
@ -90,6 +98,10 @@ public abstract class ValuesSourceMetricsAggregationBuilder<B extends ValuesSour
builder.field("lang", lang);
}
if (format != null) {
builder.field("format", format);
}
if (this.params != null && !this.params.isEmpty()) {
builder.field("params").map(this.params);
}

View File

@ -18,12 +18,12 @@
*/
package org.elasticsearch.search.aggregations.metrics.avg;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.metrics.NumericMetricsAggregation;
/**
* An aggregation that computes the average of the values in the current bucket.
*/
public interface Avg extends Aggregation {
public interface Avg extends NumericMetricsAggregation.SingleValue {
/**
* The average value.

View File

@ -19,6 +19,7 @@
package org.elasticsearch.search.aggregations.metrics.avg;
import org.apache.lucene.index.LeafReaderContext;
import org.elasticsearch.common.inject.internal.Nullable;
import org.elasticsearch.common.lease.Releasables;
import org.elasticsearch.common.util.DoubleArray;
import org.elasticsearch.common.util.LongArray;
@ -30,6 +31,7 @@ import org.elasticsearch.search.aggregations.support.AggregationContext;
import org.elasticsearch.search.aggregations.support.ValuesSource;
import org.elasticsearch.search.aggregations.support.ValuesSourceAggregatorFactory;
import org.elasticsearch.search.aggregations.support.ValuesSourceConfig;
import org.elasticsearch.search.aggregations.support.format.ValueFormatter;
import java.io.IOException;
import java.util.Map;
@ -44,10 +46,13 @@ public class AvgAggregator extends NumericMetricsAggregator.SingleValue {
private LongArray counts;
private DoubleArray sums;
private ValueFormatter formatter;
public AvgAggregator(String name, long estimatedBucketsCount, ValuesSource.Numeric valuesSource, AggregationContext context, Aggregator parent, Map<String, Object> metaData) {
public AvgAggregator(String name, long estimatedBucketsCount, ValuesSource.Numeric valuesSource, @Nullable ValueFormatter formatter,
AggregationContext context, Aggregator parent, Map<String, Object> metaData) {
super(name, estimatedBucketsCount, context, parent, metaData);
this.valuesSource = valuesSource;
this.formatter = formatter;
if (valuesSource != null) {
final long initialSize = estimatedBucketsCount < 2 ? 1 : estimatedBucketsCount;
counts = bigArrays.newLongArray(initialSize, true);
@ -88,14 +93,14 @@ public class AvgAggregator extends NumericMetricsAggregator.SingleValue {
@Override
public InternalAggregation buildAggregation(long owningBucketOrdinal) {
if (valuesSource == null || owningBucketOrdinal >= counts.size()) {
return new InternalAvg(name, 0l, 0, getMetaData());
return new InternalAvg(name, 0l, 0, formatter, getMetaData());
}
return new InternalAvg(name, sums.get(owningBucketOrdinal), counts.get(owningBucketOrdinal), getMetaData());
return new InternalAvg(name, sums.get(owningBucketOrdinal), counts.get(owningBucketOrdinal), formatter, getMetaData());
}
@Override
public InternalAggregation buildEmptyAggregation() {
return new InternalAvg(name, 0.0, 0l, getMetaData());
return new InternalAvg(name, 0.0, 0l, formatter, getMetaData());
}
public static class Factory extends ValuesSourceAggregatorFactory.LeafOnly<ValuesSource.Numeric, Map<String, Object>> {
@ -106,12 +111,12 @@ public class AvgAggregator extends NumericMetricsAggregator.SingleValue {
@Override
protected Aggregator createUnmapped(AggregationContext aggregationContext, Aggregator parent, Map<String, Object> metaData) {
return new AvgAggregator(name, 0, null, aggregationContext, parent, metaData);
return new AvgAggregator(name, 0, null, config.formatter(), aggregationContext, parent, metaData);
}
@Override
protected Aggregator create(ValuesSource.Numeric valuesSource, long expectedBucketsCount, AggregationContext aggregationContext, Aggregator parent, Map<String, Object> metaData) {
return new AvgAggregator(name, expectedBucketsCount, valuesSource, aggregationContext, parent, metaData);
return new AvgAggregator(name, expectedBucketsCount, valuesSource, config.formatter(), aggregationContext, parent, metaData);
}
}

View File

@ -18,12 +18,14 @@
*/
package org.elasticsearch.search.aggregations.metrics.avg;
import org.elasticsearch.common.inject.internal.Nullable;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.search.aggregations.AggregationStreams;
import org.elasticsearch.search.aggregations.InternalAggregation;
import org.elasticsearch.search.aggregations.metrics.InternalNumericMetricsAggregation;
import org.elasticsearch.search.aggregations.support.format.ValueFormatter;
import org.elasticsearch.search.aggregations.support.format.ValueFormatterStreams;
import java.io.IOException;
@ -54,10 +56,11 @@ public class InternalAvg extends InternalNumericMetricsAggregation.SingleValue i
InternalAvg() {} // for serialization
public InternalAvg(String name, double sum, long count, Map<String, Object> metaData) {
public InternalAvg(String name, double sum, long count, @Nullable ValueFormatter formatter, Map<String, Object> metaData) {
super(name, metaData);
this.sum = sum;
this.count = count;
this.valueFormatter = formatter;
}
@Override
@ -82,7 +85,7 @@ public class InternalAvg extends InternalNumericMetricsAggregation.SingleValue i
count += ((InternalAvg) aggregation).count;
sum += ((InternalAvg) aggregation).sum;
}
return new InternalAvg(getName(), sum, count, getMetaData());
return new InternalAvg(getName(), sum, count, valueFormatter, getMetaData());
}
@Override

View File

@ -19,12 +19,12 @@
package org.elasticsearch.search.aggregations.metrics.cardinality;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.metrics.NumericMetricsAggregation;
/**
* An aggregation that computes approximate numbers of unique terms.
*/
public interface Cardinality extends Aggregation {
public interface Cardinality extends NumericMetricsAggregation.SingleValue {
/**
* The number of unique terms.

View File

@ -21,6 +21,7 @@ package org.elasticsearch.search.aggregations.metrics.cardinality;
import com.carrotsearch.hppc.hash.MurmurHash3;
import com.google.common.base.Preconditions;
import org.apache.lucene.index.LeafReaderContext;
import org.apache.lucene.index.RandomAccessOrds;
import org.apache.lucene.index.SortedNumericDocValues;
@ -42,6 +43,7 @@ import org.elasticsearch.search.aggregations.InternalAggregation;
import org.elasticsearch.search.aggregations.metrics.NumericMetricsAggregator;
import org.elasticsearch.search.aggregations.support.AggregationContext;
import org.elasticsearch.search.aggregations.support.ValuesSource;
import org.elasticsearch.search.aggregations.support.format.ValueFormatter;
import java.io.IOException;
import java.util.Map;
@ -60,14 +62,17 @@ public class CardinalityAggregator extends NumericMetricsAggregator.SingleValue
private HyperLogLogPlusPlus counts;
private Collector collector;
private ValueFormatter formatter;
public CardinalityAggregator(String name, long estimatedBucketsCount, ValuesSource valuesSource, boolean rehash,
int precision, AggregationContext context, Aggregator parent, Map<String, Object> metaData) {
int precision,
@Nullable ValueFormatter formatter, AggregationContext context, Aggregator parent, Map<String, Object> metaData) {
super(name, estimatedBucketsCount, context, parent, metaData);
this.valuesSource = valuesSource;
this.rehash = rehash;
this.precision = precision;
this.counts = valuesSource == null ? null : new HyperLogLogPlusPlus(precision, bigArrays, estimatedBucketsCount);
this.formatter = formatter;
}
@Override
@ -152,12 +157,12 @@ public class CardinalityAggregator extends NumericMetricsAggregator.SingleValue
// this Aggregator (and its HLL++ counters) is released.
HyperLogLogPlusPlus copy = new HyperLogLogPlusPlus(precision, BigArrays.NON_RECYCLING_INSTANCE, 1);
copy.merge(0, counts, owningBucketOrdinal);
return new InternalCardinality(name, copy, getMetaData());
return new InternalCardinality(name, copy, formatter, getMetaData());
}
@Override
public InternalAggregation buildEmptyAggregation() {
return new InternalCardinality(name, null, getMetaData());
return new InternalCardinality(name, null, formatter, getMetaData());
}
@Override

View File

@ -46,7 +46,8 @@ final class CardinalityAggregatorFactory extends ValuesSourceAggregatorFactory<V
@Override
protected Aggregator createUnmapped(AggregationContext context, Aggregator parent, Map<String, Object> metaData) {
return new CardinalityAggregator(name, parent == null ? 1 : parent.estimatedBucketCount(), null, true, precision(parent), context, parent, metaData);
return new CardinalityAggregator(name, parent == null ? 1 : parent.estimatedBucketCount(), null, true, precision(parent),
config.formatter(), context, parent, metaData);
}
@Override
@ -54,7 +55,8 @@ final class CardinalityAggregatorFactory extends ValuesSourceAggregatorFactory<V
if (!(valuesSource instanceof ValuesSource.Numeric) && !rehash) {
throw new AggregationExecutionException("Turning off rehashing for cardinality aggregation [" + name + "] on non-numeric values in not allowed");
}
return new CardinalityAggregator(name, parent == null ? 1 : parent.estimatedBucketCount(), valuesSource, rehash, precision(parent), context, parent, metaData);
return new CardinalityAggregator(name, parent == null ? 1 : parent.estimatedBucketCount(), valuesSource, rehash, precision(parent),
config.formatter(), context, parent, metaData);
}
/*

View File

@ -44,7 +44,7 @@ public class CardinalityParser implements Aggregator.Parser {
@Override
public AggregatorFactory parse(String name, XContentParser parser, SearchContext context) throws IOException {
ValuesSourceParser vsParser = ValuesSourceParser.any(name, InternalCardinality.TYPE, context).build();
ValuesSourceParser vsParser = ValuesSourceParser.any(name, InternalCardinality.TYPE, context).formattable(false).build();
long precisionThreshold = -1;
Boolean rehash = null;

View File

@ -19,6 +19,7 @@
package org.elasticsearch.search.aggregations.metrics.cardinality;
import org.elasticsearch.common.inject.internal.Nullable;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.common.util.BigArrays;
@ -26,6 +27,7 @@ import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.search.aggregations.AggregationStreams;
import org.elasticsearch.search.aggregations.InternalAggregation;
import org.elasticsearch.search.aggregations.metrics.InternalNumericMetricsAggregation;
import org.elasticsearch.search.aggregations.support.format.ValueFormatter;
import org.elasticsearch.search.aggregations.support.format.ValueFormatterStreams;
import java.io.IOException;
@ -51,9 +53,10 @@ public final class InternalCardinality extends InternalNumericMetricsAggregation
private HyperLogLogPlusPlus counts;
InternalCardinality(String name, HyperLogLogPlusPlus counts, Map<String, Object> metaData) {
InternalCardinality(String name, HyperLogLogPlusPlus counts, @Nullable ValueFormatter formatter, Map<String, Object> metaData) {
super(name, metaData);
this.counts = counts;
this.valueFormatter = formatter;
}
private InternalCardinality() {
@ -103,7 +106,8 @@ public final class InternalCardinality extends InternalNumericMetricsAggregation
final InternalCardinality cardinality = (InternalCardinality) aggregation;
if (cardinality.counts != null) {
if (reduced == null) {
reduced = new InternalCardinality(name, new HyperLogLogPlusPlus(cardinality.counts.precision(), BigArrays.NON_RECYCLING_INSTANCE, 1), getMetaData());
reduced = new InternalCardinality(name, new HyperLogLogPlusPlus(cardinality.counts.precision(),
BigArrays.NON_RECYCLING_INSTANCE, 1), this.valueFormatter, getMetaData());
}
reduced.merge(cardinality);
}

View File

@ -18,12 +18,14 @@
*/
package org.elasticsearch.search.aggregations.metrics.max;
import org.elasticsearch.common.inject.internal.Nullable;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.search.aggregations.AggregationStreams;
import org.elasticsearch.search.aggregations.InternalAggregation;
import org.elasticsearch.search.aggregations.metrics.InternalNumericMetricsAggregation;
import org.elasticsearch.search.aggregations.support.format.ValueFormatter;
import org.elasticsearch.search.aggregations.support.format.ValueFormatterStreams;
import java.io.IOException;
@ -53,8 +55,9 @@ public class InternalMax extends InternalNumericMetricsAggregation.SingleValue i
InternalMax() {} // for serialization
public InternalMax(String name, double max, Map<String, Object> metaData) {
public InternalMax(String name, double max, @Nullable ValueFormatter formatter, Map<String, Object> metaData) {
super(name, metaData);
this.valueFormatter = formatter;
this.max = max;
}
@ -78,7 +81,7 @@ public class InternalMax extends InternalNumericMetricsAggregation.SingleValue i
for (InternalAggregation aggregation : reduceContext.aggregations()) {
max = Math.max(max, ((InternalMax) aggregation).max);
}
return new InternalMax(name, max, getMetaData());
return new InternalMax(name, max, valueFormatter, getMetaData());
}
@Override

View File

@ -18,12 +18,12 @@
*/
package org.elasticsearch.search.aggregations.metrics.max;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.metrics.NumericMetricsAggregation;
/**
* An aggregation that computes the maximum of the values in the current bucket.
*/
public interface Max extends Aggregation {
public interface Max extends NumericMetricsAggregation.SingleValue {
/**
* The maximum.

View File

@ -19,6 +19,7 @@
package org.elasticsearch.search.aggregations.metrics.max;
import org.apache.lucene.index.LeafReaderContext;
import org.elasticsearch.common.inject.internal.Nullable;
import org.elasticsearch.common.lease.Releasables;
import org.elasticsearch.common.util.DoubleArray;
import org.elasticsearch.index.fielddata.NumericDoubleValues;
@ -31,6 +32,7 @@ import org.elasticsearch.search.aggregations.support.AggregationContext;
import org.elasticsearch.search.aggregations.support.ValuesSource;
import org.elasticsearch.search.aggregations.support.ValuesSourceAggregatorFactory;
import org.elasticsearch.search.aggregations.support.ValuesSourceConfig;
import org.elasticsearch.search.aggregations.support.format.ValueFormatter;
import java.io.IOException;
import java.util.Map;
@ -44,10 +46,13 @@ public class MaxAggregator extends NumericMetricsAggregator.SingleValue {
private NumericDoubleValues values;
private DoubleArray maxes;
private ValueFormatter formatter;
public MaxAggregator(String name, long estimatedBucketsCount, ValuesSource.Numeric valuesSource, AggregationContext context, Aggregator parent, Map<String, Object> metaData) {
public MaxAggregator(String name, long estimatedBucketsCount, ValuesSource.Numeric valuesSource, @Nullable ValueFormatter formatter,
AggregationContext context, Aggregator parent, Map<String, Object> metaData) {
super(name, estimatedBucketsCount, context, parent, metaData);
this.valuesSource = valuesSource;
this.formatter = formatter;
if (valuesSource != null) {
final long initialSize = estimatedBucketsCount < 2 ? 1 : estimatedBucketsCount;
maxes = bigArrays.newDoubleArray(initialSize, false);
@ -87,15 +92,15 @@ public class MaxAggregator extends NumericMetricsAggregator.SingleValue {
@Override
public InternalAggregation buildAggregation(long owningBucketOrdinal) {
if (valuesSource == null) {
return new InternalMax(name, Double.NEGATIVE_INFINITY, getMetaData());
return new InternalMax(name, Double.NEGATIVE_INFINITY, formatter, getMetaData());
}
assert owningBucketOrdinal < maxes.size();
return new InternalMax(name, maxes.get(owningBucketOrdinal), getMetaData());
return new InternalMax(name, maxes.get(owningBucketOrdinal), formatter, getMetaData());
}
@Override
public InternalAggregation buildEmptyAggregation() {
return new InternalMax(name, Double.NEGATIVE_INFINITY, getMetaData());
return new InternalMax(name, Double.NEGATIVE_INFINITY, formatter, getMetaData());
}
public static class Factory extends ValuesSourceAggregatorFactory.LeafOnly<ValuesSource.Numeric, Map<String, Object>> {
@ -106,12 +111,12 @@ public class MaxAggregator extends NumericMetricsAggregator.SingleValue {
@Override
protected Aggregator createUnmapped(AggregationContext aggregationContext, Aggregator parent, Map<String, Object> metaData) {
return new MaxAggregator(name, 0, null, aggregationContext, parent, metaData);
return new MaxAggregator(name, 0, null, config.formatter(), aggregationContext, parent, metaData);
}
@Override
protected Aggregator create(ValuesSource.Numeric valuesSource, long expectedBucketsCount, AggregationContext aggregationContext, Aggregator parent, Map<String, Object> metaData) {
return new MaxAggregator(name, expectedBucketsCount, valuesSource, aggregationContext, parent, metaData);
return new MaxAggregator(name, expectedBucketsCount, valuesSource, config.formatter(), aggregationContext, parent, metaData);
}
}

View File

@ -18,12 +18,14 @@
*/
package org.elasticsearch.search.aggregations.metrics.min;
import org.elasticsearch.common.inject.internal.Nullable;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.search.aggregations.AggregationStreams;
import org.elasticsearch.search.aggregations.InternalAggregation;
import org.elasticsearch.search.aggregations.metrics.InternalNumericMetricsAggregation;
import org.elasticsearch.search.aggregations.support.format.ValueFormatter;
import org.elasticsearch.search.aggregations.support.format.ValueFormatterStreams;
import java.io.IOException;
@ -54,9 +56,10 @@ public class InternalMin extends InternalNumericMetricsAggregation.SingleValue i
InternalMin() {} // for serialization
public InternalMin(String name, double min, Map<String, Object> metaData) {
public InternalMin(String name, double min, @Nullable ValueFormatter formatter, Map<String, Object> metaData) {
super(name, metaData);
this.min = min;
this.valueFormatter = formatter;
}
@Override
@ -79,7 +82,7 @@ public class InternalMin extends InternalNumericMetricsAggregation.SingleValue i
for (InternalAggregation aggregation : reduceContext.aggregations()) {
min = Math.min(min, ((InternalMin) aggregation).min);
}
return new InternalMin(getName(), min, getMetaData());
return new InternalMin(getName(), min, this.valueFormatter, getMetaData());
}
@Override

View File

@ -18,12 +18,12 @@
*/
package org.elasticsearch.search.aggregations.metrics.min;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.metrics.NumericMetricsAggregation;
/**
* An aggregation that computes the minimum of the values in the current bucket.
*/
public interface Min extends Aggregation {
public interface Min extends NumericMetricsAggregation.SingleValue {
/**
* The minimum.

View File

@ -19,6 +19,7 @@
package org.elasticsearch.search.aggregations.metrics.min;
import org.apache.lucene.index.LeafReaderContext;
import org.elasticsearch.common.inject.internal.Nullable;
import org.elasticsearch.common.lease.Releasables;
import org.elasticsearch.common.util.DoubleArray;
import org.elasticsearch.index.fielddata.NumericDoubleValues;
@ -31,6 +32,7 @@ import org.elasticsearch.search.aggregations.support.AggregationContext;
import org.elasticsearch.search.aggregations.support.ValuesSource;
import org.elasticsearch.search.aggregations.support.ValuesSourceAggregatorFactory;
import org.elasticsearch.search.aggregations.support.ValuesSourceConfig;
import org.elasticsearch.search.aggregations.support.format.ValueFormatter;
import java.io.IOException;
import java.util.Map;
@ -44,8 +46,10 @@ public class MinAggregator extends NumericMetricsAggregator.SingleValue {
private NumericDoubleValues values;
private DoubleArray mins;
private ValueFormatter formatter;
public MinAggregator(String name, long estimatedBucketsCount, ValuesSource.Numeric valuesSource, AggregationContext context, Aggregator parent, Map<String, Object> metaData) {
public MinAggregator(String name, long estimatedBucketsCount, ValuesSource.Numeric valuesSource, @Nullable ValueFormatter formatter,
AggregationContext context, Aggregator parent, Map<String, Object> metaData) {
super(name, estimatedBucketsCount, context, parent, metaData);
this.valuesSource = valuesSource;
if (valuesSource != null) {
@ -53,6 +57,7 @@ public class MinAggregator extends NumericMetricsAggregator.SingleValue {
mins = bigArrays.newDoubleArray(initialSize, false);
mins.fill(0, mins.size(), Double.POSITIVE_INFINITY);
}
this.formatter = formatter;
}
@Override
@ -87,15 +92,15 @@ public class MinAggregator extends NumericMetricsAggregator.SingleValue {
@Override
public InternalAggregation buildAggregation(long owningBucketOrdinal) {
if (valuesSource == null) {
return new InternalMin(name, Double.POSITIVE_INFINITY, getMetaData());
return new InternalMin(name, Double.POSITIVE_INFINITY, formatter, getMetaData());
}
assert owningBucketOrdinal < mins.size();
return new InternalMin(name, mins.get(owningBucketOrdinal), getMetaData());
return new InternalMin(name, mins.get(owningBucketOrdinal), formatter, getMetaData());
}
@Override
public InternalAggregation buildEmptyAggregation() {
return new InternalMin(name, Double.POSITIVE_INFINITY, getMetaData());
return new InternalMin(name, Double.POSITIVE_INFINITY, formatter, getMetaData());
}
public static class Factory extends ValuesSourceAggregatorFactory.LeafOnly<ValuesSource.Numeric, Map<String,Object>> {
@ -106,12 +111,12 @@ public class MinAggregator extends NumericMetricsAggregator.SingleValue {
@Override
protected Aggregator createUnmapped(AggregationContext aggregationContext, Aggregator parent, Map<String, Object> metaData) {
return new MinAggregator(name, 0, null, aggregationContext, parent, metaData);
return new MinAggregator(name, 0, null, config.formatter(), aggregationContext, parent, metaData);
}
@Override
protected Aggregator create(ValuesSource.Numeric valuesSource, long expectedBucketsCount, AggregationContext aggregationContext, Aggregator parent, Map<String, Object> metaData) {
return new MinAggregator(name, expectedBucketsCount, valuesSource, aggregationContext, parent, metaData);
return new MinAggregator(name, expectedBucketsCount, valuesSource, config.formatter(), aggregationContext, parent, metaData);
}
}

View File

@ -21,12 +21,14 @@ package org.elasticsearch.search.aggregations.metrics.percentiles;
import org.elasticsearch.ElasticsearchIllegalArgumentException;
import org.elasticsearch.Version;
import org.elasticsearch.common.inject.internal.Nullable;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.search.aggregations.InternalAggregation;
import org.elasticsearch.search.aggregations.metrics.InternalNumericMetricsAggregation;
import org.elasticsearch.search.aggregations.metrics.percentiles.tdigest.TDigestState;
import org.elasticsearch.search.aggregations.support.format.ValueFormatter;
import org.elasticsearch.search.aggregations.support.format.ValueFormatterStreams;
import java.io.IOException;
@ -41,11 +43,13 @@ abstract class AbstractInternalPercentiles extends InternalNumericMetricsAggrega
AbstractInternalPercentiles() {} // for serialization
public AbstractInternalPercentiles(String name, double[] keys, TDigestState state, boolean keyed, Map<String, Object> metaData) {
public AbstractInternalPercentiles(String name, double[] keys, TDigestState state, boolean keyed, @Nullable ValueFormatter formatter,
Map<String, Object> metaData) {
super(name, metaData);
this.keys = keys;
this.state = state;
this.keyed = keyed;
this.valueFormatter = formatter;
}
@Override

View File

@ -20,6 +20,7 @@
package org.elasticsearch.search.aggregations.metrics.percentiles;
import org.apache.lucene.index.LeafReaderContext;
import org.elasticsearch.common.inject.internal.Nullable;
import org.elasticsearch.common.lease.Releasables;
import org.elasticsearch.common.util.ArrayUtils;
import org.elasticsearch.common.util.ObjectArray;
@ -29,6 +30,7 @@ import org.elasticsearch.search.aggregations.metrics.NumericMetricsAggregator;
import org.elasticsearch.search.aggregations.metrics.percentiles.tdigest.TDigestState;
import org.elasticsearch.search.aggregations.support.AggregationContext;
import org.elasticsearch.search.aggregations.support.ValuesSource;
import org.elasticsearch.search.aggregations.support.format.ValueFormatter;
import java.io.IOException;
import java.util.Map;
@ -45,12 +47,15 @@ public abstract class AbstractPercentilesAggregator extends NumericMetricsAggreg
protected ObjectArray<TDigestState> states;
protected final double compression;
protected final boolean keyed;
protected ValueFormatter formatter;
public AbstractPercentilesAggregator(String name, long estimatedBucketsCount, ValuesSource.Numeric valuesSource, AggregationContext context,
Aggregator parent, double[] keys, double compression, boolean keyed, Map<String, Object> metaData) {
Aggregator parent, double[] keys, double compression, boolean keyed,
@Nullable ValueFormatter formatter, Map<String, Object> metaData) {
super(name, estimatedBucketsCount, context, parent, metaData);
this.valuesSource = valuesSource;
this.keyed = keyed;
this.formatter = formatter;
this.states = bigArrays.newObjectArray(estimatedBucketsCount);
this.keys = keys;
this.compression = compression;

View File

@ -20,6 +20,7 @@
package org.elasticsearch.search.aggregations.metrics.percentiles;
import com.carrotsearch.hppc.DoubleArrayList;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.search.SearchParseException;
import org.elasticsearch.search.aggregations.Aggregator;
@ -35,14 +36,17 @@ import java.util.Arrays;
public abstract class AbstractPercentilesParser implements Aggregator.Parser {
public AbstractPercentilesParser() {
super();
private boolean formattable;
public AbstractPercentilesParser(boolean formattable) {
this.formattable = formattable;
}
@Override
public AggregatorFactory parse(String aggregationName, XContentParser parser, SearchContext context) throws IOException {
ValuesSourceParser<ValuesSource.Numeric> vsParser = ValuesSourceParser.numeric(aggregationName, InternalPercentiles.TYPE, context).build();
ValuesSourceParser<ValuesSource.Numeric> vsParser = ValuesSourceParser.numeric(aggregationName, InternalPercentiles.TYPE, context)
.formattable(formattable).build();
double[] keys = null;
boolean keyed = true;

View File

@ -19,9 +19,12 @@
package org.elasticsearch.search.aggregations.metrics.percentiles;
import com.google.common.collect.UnmodifiableIterator;
import org.elasticsearch.common.inject.internal.Nullable;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.search.aggregations.AggregationStreams;
import org.elasticsearch.search.aggregations.metrics.percentiles.tdigest.TDigestState;
import org.elasticsearch.search.aggregations.support.format.ValueFormatter;
import java.io.IOException;
import java.util.Iterator;
@ -49,8 +52,9 @@ public class InternalPercentileRanks extends AbstractInternalPercentiles impleme
InternalPercentileRanks() {} // for serialization
public InternalPercentileRanks(String name, double[] cdfValues, TDigestState state, boolean keyed, Map<String, Object> metaData) {
super(name, cdfValues, state, keyed, metaData);
public InternalPercentileRanks(String name, double[] cdfValues, TDigestState state, boolean keyed, @Nullable ValueFormatter formatter,
Map<String, Object> metaData) {
super(name, cdfValues, state, keyed, formatter, metaData);
}
@Override
@ -63,13 +67,18 @@ public class InternalPercentileRanks extends AbstractInternalPercentiles impleme
return percentileRank(state, value);
}
@Override
public String percentAsString(double value) {
return valueAsString(String.valueOf(value));
}
@Override
public double value(double key) {
return percent(key);
}
protected AbstractInternalPercentiles createReduced(String name, double[] keys, TDigestState merged, boolean keyed, Map<String, Object> metaData) {
return new InternalPercentileRanks(name, keys, merged, keyed, metaData);
return new InternalPercentileRanks(name, keys, merged, keyed, valueFormatter, metaData);
}
@Override

View File

@ -19,9 +19,12 @@
package org.elasticsearch.search.aggregations.metrics.percentiles;
import com.google.common.collect.UnmodifiableIterator;
import org.elasticsearch.common.inject.internal.Nullable;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.search.aggregations.AggregationStreams;
import org.elasticsearch.search.aggregations.metrics.percentiles.tdigest.TDigestState;
import org.elasticsearch.search.aggregations.support.format.ValueFormatter;
import java.io.IOException;
import java.util.Iterator;
@ -49,8 +52,9 @@ public class InternalPercentiles extends AbstractInternalPercentiles implements
InternalPercentiles() {} // for serialization
public InternalPercentiles(String name, double[] percents, TDigestState state, boolean keyed, Map<String, Object> metaData) {
super(name, percents, state, keyed, metaData);
public InternalPercentiles(String name, double[] percents, TDigestState state, boolean keyed, @Nullable ValueFormatter formatter,
Map<String, Object> metaData) {
super(name, percents, state, keyed, formatter, metaData);
}
@Override
@ -63,13 +67,18 @@ public class InternalPercentiles extends AbstractInternalPercentiles implements
return state.quantile(percent / 100);
}
@Override
public String percentileAsString(double percent) {
return valueAsString(String.valueOf(percent));
}
@Override
public double value(double key) {
return percentile(key);
}
protected AbstractInternalPercentiles createReduced(String name, double[] keys, TDigestState merged, boolean keyed, Map<String, Object> metaData) {
return new InternalPercentiles(name, keys, merged, keyed, metaData);
return new InternalPercentiles(name, keys, merged, keyed, valueFormatter, metaData);
}
@Override

View File

@ -19,15 +19,20 @@
package org.elasticsearch.search.aggregations.metrics.percentiles;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.metrics.NumericMetricsAggregation;
/**
* An aggregation that computes approximate percentiles given values.
*/
public interface PercentileRanks extends Aggregation, Iterable<Percentile>{
public interface PercentileRanks extends NumericMetricsAggregation.MultiValue, Iterable<Percentile> {
/**
* Return the percentile for the given value.
*/
double percent(double value);
/**
* Return the percentile for the given value as a String.
*/
String percentAsString(double value);
}

View File

@ -18,11 +18,16 @@
*/
package org.elasticsearch.search.aggregations.metrics.percentiles;
import org.elasticsearch.common.inject.internal.Nullable;
import org.elasticsearch.search.aggregations.Aggregator;
import org.elasticsearch.search.aggregations.InternalAggregation;
import org.elasticsearch.search.aggregations.metrics.percentiles.tdigest.TDigestState;
import org.elasticsearch.search.aggregations.support.*;
import org.elasticsearch.search.aggregations.support.AggregationContext;
import org.elasticsearch.search.aggregations.support.ValuesSource;
import org.elasticsearch.search.aggregations.support.ValuesSource.Numeric;
import org.elasticsearch.search.aggregations.support.ValuesSourceAggregatorFactory;
import org.elasticsearch.search.aggregations.support.ValuesSourceConfig;
import org.elasticsearch.search.aggregations.support.format.ValueFormatter;
import java.util.Map;
@ -32,8 +37,9 @@ import java.util.Map;
public class PercentileRanksAggregator extends AbstractPercentilesAggregator {
public PercentileRanksAggregator(String name, long estimatedBucketsCount, Numeric valuesSource, AggregationContext context,
Aggregator parent, double[] percents, double compression, boolean keyed, Map<String, Object> metaData) {
super(name, estimatedBucketsCount, valuesSource, context, parent, percents, compression, keyed, metaData);
Aggregator parent, double[] percents, double compression, boolean keyed, @Nullable ValueFormatter formatter,
Map<String, Object> metaData) {
super(name, estimatedBucketsCount, valuesSource, context, parent, percents, compression, keyed, formatter, metaData);
}
@Override
@ -42,13 +48,13 @@ public class PercentileRanksAggregator extends AbstractPercentilesAggregator {
if (state == null) {
return buildEmptyAggregation();
} else {
return new InternalPercentileRanks(name, keys, state, keyed, getMetaData());
return new InternalPercentileRanks(name, keys, state, keyed, formatter, getMetaData());
}
}
@Override
public InternalAggregation buildEmptyAggregation() {
return new InternalPercentileRanks(name, keys, new TDigestState(compression), keyed, getMetaData());
return new InternalPercentileRanks(name, keys, new TDigestState(compression), keyed, formatter, getMetaData());
}
@Override
@ -77,12 +83,14 @@ public class PercentileRanksAggregator extends AbstractPercentilesAggregator {
@Override
protected Aggregator createUnmapped(AggregationContext aggregationContext, Aggregator parent, Map<String, Object> metaData) {
return new PercentileRanksAggregator(name, 0, null, aggregationContext, parent, values, compression, keyed, metaData);
return new PercentileRanksAggregator(name, 0, null, aggregationContext, parent, values, compression, keyed, config.formatter(),
metaData);
}
@Override
protected Aggregator create(ValuesSource.Numeric valuesSource, long expectedBucketsCount, AggregationContext aggregationContext, Aggregator parent, Map<String, Object> metaData) {
return new PercentileRanksAggregator(name, expectedBucketsCount, valuesSource, aggregationContext, parent, values, compression, keyed, metaData);
return new PercentileRanksAggregator(name, expectedBucketsCount, valuesSource, aggregationContext, parent, values, compression,
keyed, config.formatter(), metaData);
}
}
}

View File

@ -29,6 +29,10 @@ import org.elasticsearch.search.internal.SearchContext;
*/
public class PercentileRanksParser extends AbstractPercentilesParser {
public PercentileRanksParser() {
super(false);
}
@Override
public String type() {
return InternalPercentileRanks.TYPE.name();

View File

@ -18,16 +18,21 @@
*/
package org.elasticsearch.search.aggregations.metrics.percentiles;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.metrics.NumericMetricsAggregation;
/**
* An aggregation that computes approximate percentiles.
*/
public interface Percentiles extends Aggregation, Iterable<Percentile> {
public interface Percentiles extends NumericMetricsAggregation.MultiValue, Iterable<Percentile> {
/**
* Return the value associated with the provided percentile.
*/
double percentile(double percent);
/**
* Return the value associated with the provided percentile as a String.
*/
String percentileAsString(double percent);
}

View File

@ -18,11 +18,16 @@
*/
package org.elasticsearch.search.aggregations.metrics.percentiles;
import org.elasticsearch.common.inject.internal.Nullable;
import org.elasticsearch.search.aggregations.Aggregator;
import org.elasticsearch.search.aggregations.InternalAggregation;
import org.elasticsearch.search.aggregations.metrics.percentiles.tdigest.TDigestState;
import org.elasticsearch.search.aggregations.support.*;
import org.elasticsearch.search.aggregations.support.AggregationContext;
import org.elasticsearch.search.aggregations.support.ValuesSource;
import org.elasticsearch.search.aggregations.support.ValuesSource.Numeric;
import org.elasticsearch.search.aggregations.support.ValuesSourceAggregatorFactory;
import org.elasticsearch.search.aggregations.support.ValuesSourceConfig;
import org.elasticsearch.search.aggregations.support.format.ValueFormatter;
import java.util.Map;
@ -32,8 +37,9 @@ import java.util.Map;
public class PercentilesAggregator extends AbstractPercentilesAggregator {
public PercentilesAggregator(String name, long estimatedBucketsCount, Numeric valuesSource, AggregationContext context,
Aggregator parent, double[] percents, double compression, boolean keyed, Map<String, Object> metaData) {
super(name, estimatedBucketsCount, valuesSource, context, parent, percents, compression, keyed, metaData);
Aggregator parent, double[] percents, double compression, boolean keyed, @Nullable ValueFormatter formatter,
Map<String, Object> metaData) {
super(name, estimatedBucketsCount, valuesSource, context, parent, percents, compression, keyed, formatter, metaData);
}
@Override
@ -42,7 +48,7 @@ public class PercentilesAggregator extends AbstractPercentilesAggregator {
if (state == null) {
return buildEmptyAggregation();
} else {
return new InternalPercentiles(name, keys, state, keyed, getMetaData());
return new InternalPercentiles(name, keys, state, keyed, formatter, getMetaData());
}
}
@ -58,7 +64,7 @@ public class PercentilesAggregator extends AbstractPercentilesAggregator {
@Override
public InternalAggregation buildEmptyAggregation() {
return new InternalPercentiles(name, keys, new TDigestState(compression), keyed, getMetaData());
return new InternalPercentiles(name, keys, new TDigestState(compression), keyed, formatter, getMetaData());
}
public static class Factory extends ValuesSourceAggregatorFactory.LeafOnly<ValuesSource.Numeric, Map<String, Object>> {
@ -77,12 +83,14 @@ public class PercentilesAggregator extends AbstractPercentilesAggregator {
@Override
protected Aggregator createUnmapped(AggregationContext aggregationContext, Aggregator parent, Map<String, Object> metaData) {
return new PercentilesAggregator(name, 0, null, aggregationContext, parent, percents, compression, keyed, metaData);
return new PercentilesAggregator(name, 0, null, aggregationContext, parent, percents, compression, keyed, config.formatter(),
metaData);
}
@Override
protected Aggregator create(ValuesSource.Numeric valuesSource, long expectedBucketsCount, AggregationContext aggregationContext, Aggregator parent, Map<String, Object> metaData) {
return new PercentilesAggregator(name, expectedBucketsCount, valuesSource, aggregationContext, parent, percents, compression, keyed, metaData);
return new PercentilesAggregator(name, expectedBucketsCount, valuesSource, aggregationContext, parent, percents, compression,
keyed, config.formatter(), metaData);
}
}
}

View File

@ -28,6 +28,10 @@ import org.elasticsearch.search.internal.SearchContext;
*/
public class PercentilesParser extends AbstractPercentilesParser {
public PercentilesParser() {
super(true);
}
private final static double[] DEFAULT_PERCENTS = new double[] { 1, 5, 25, 50, 75, 95, 99 };
@Override

View File

@ -18,6 +18,7 @@
*/
package org.elasticsearch.search.aggregations.metrics.stats;
import org.elasticsearch.common.inject.internal.Nullable;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.common.xcontent.XContentBuilder;
@ -25,6 +26,7 @@ import org.elasticsearch.common.xcontent.XContentBuilderString;
import org.elasticsearch.search.aggregations.AggregationStreams;
import org.elasticsearch.search.aggregations.InternalAggregation;
import org.elasticsearch.search.aggregations.metrics.InternalNumericMetricsAggregation;
import org.elasticsearch.search.aggregations.support.format.ValueFormatter;
import org.elasticsearch.search.aggregations.support.format.ValueFormatterStreams;
import java.io.IOException;
@ -66,12 +68,14 @@ public class InternalStats extends InternalNumericMetricsAggregation.MultiValue
protected InternalStats() {} // for serialization
public InternalStats(String name, long count, double sum, double min, double max, Map<String, Object> metaData) {
public InternalStats(String name, long count, double sum, double min, double max, @Nullable ValueFormatter formatter,
Map<String, Object> metaData) {
super(name, metaData);
this.count = count;
this.sum = sum;
this.min = min;
this.max = max;
this.valueFormatter = formatter;
}
@Override
@ -99,6 +103,31 @@ public class InternalStats extends InternalNumericMetricsAggregation.MultiValue
return sum;
}
@Override
public String getCountAsString() {
return valueAsString(Metrics.count.name());
}
@Override
public String getMinAsString() {
return valueAsString(Metrics.min.name());
}
@Override
public String getMaxAsString() {
return valueAsString(Metrics.max.name());
}
@Override
public String getAvgAsString() {
return valueAsString(Metrics.avg.name());
}
@Override
public String getSumAsString() {
return valueAsString(Metrics.sum.name());
}
@Override
public Type type() {
return TYPE;
@ -131,7 +160,7 @@ public class InternalStats extends InternalNumericMetricsAggregation.MultiValue
max = Math.max(max, stats.getMax());
sum += stats.getSum();
}
return new InternalStats(name, count, sum, min, max, getMetaData());
return new InternalStats(name, count, sum, min, max, valueFormatter, getMetaData());
}
@Override

View File

@ -18,15 +18,15 @@
*/
package org.elasticsearch.search.aggregations.metrics.stats;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.metrics.NumericMetricsAggregation;
/**
* Statistics over a set of values (either aggregated over field data or scripts)
*/
public interface Stats extends Aggregation {
public interface Stats extends NumericMetricsAggregation.MultiValue {
/**
* @return The number of values that were aggregated
* @return The number of values that were aggregated.
*/
long getCount();
@ -50,4 +50,29 @@ public interface Stats extends Aggregation {
*/
double getSum();
/**
* @return The number of values that were aggregated as a String.
*/
String getCountAsString();
/**
* @return The minimum value of all aggregated values as a String.
*/
String getMinAsString();
/**
* @return The maximum value of all aggregated values as a String.
*/
String getMaxAsString();
/**
* @return The avg value over all aggregated values as a String.
*/
String getAvgAsString();
/**
* @return The sum of aggregated values as a String.
*/
String getSumAsString();
}

View File

@ -20,6 +20,7 @@ package org.elasticsearch.search.aggregations.metrics.stats;
import org.apache.lucene.index.LeafReaderContext;
import org.elasticsearch.ElasticsearchIllegalArgumentException;
import org.elasticsearch.common.inject.internal.Nullable;
import org.elasticsearch.common.lease.Releasables;
import org.elasticsearch.common.util.BigArrays;
import org.elasticsearch.common.util.DoubleArray;
@ -32,6 +33,7 @@ import org.elasticsearch.search.aggregations.support.AggregationContext;
import org.elasticsearch.search.aggregations.support.ValuesSource;
import org.elasticsearch.search.aggregations.support.ValuesSourceAggregatorFactory;
import org.elasticsearch.search.aggregations.support.ValuesSourceConfig;
import org.elasticsearch.search.aggregations.support.format.ValueFormatter;
import java.io.IOException;
import java.util.Map;
@ -48,8 +50,10 @@ public class StatsAggegator extends NumericMetricsAggregator.MultiValue {
private DoubleArray sums;
private DoubleArray mins;
private DoubleArray maxes;
private ValueFormatter formatter;
public StatsAggegator(String name, long estimatedBucketsCount, ValuesSource.Numeric valuesSource, AggregationContext context, Aggregator parent, Map<String, Object> metaData) {
public StatsAggegator(String name, long estimatedBucketsCount, ValuesSource.Numeric valuesSource, @Nullable ValueFormatter formatter,
AggregationContext context, Aggregator parent, Map<String, Object> metaData) {
super(name, estimatedBucketsCount, context, parent, metaData);
this.valuesSource = valuesSource;
if (valuesSource != null) {
@ -61,6 +65,7 @@ public class StatsAggegator extends NumericMetricsAggregator.MultiValue {
maxes = bigArrays.newDoubleArray(initialSize, false);
maxes.fill(0, maxes.size(), Double.NEGATIVE_INFINITY);
}
this.formatter = formatter;
}
@Override
@ -129,15 +134,16 @@ public class StatsAggegator extends NumericMetricsAggregator.MultiValue {
@Override
public InternalAggregation buildAggregation(long owningBucketOrdinal) {
if (valuesSource == null) {
return new InternalStats(name, 0, 0, Double.POSITIVE_INFINITY, Double.NEGATIVE_INFINITY, getMetaData());
return new InternalStats(name, 0, 0, Double.POSITIVE_INFINITY, Double.NEGATIVE_INFINITY, formatter, getMetaData());
}
assert owningBucketOrdinal < counts.size();
return new InternalStats(name, counts.get(owningBucketOrdinal), sums.get(owningBucketOrdinal), mins.get(owningBucketOrdinal), maxes.get(owningBucketOrdinal), getMetaData());
return new InternalStats(name, counts.get(owningBucketOrdinal), sums.get(owningBucketOrdinal), mins.get(owningBucketOrdinal),
maxes.get(owningBucketOrdinal), formatter, getMetaData());
}
@Override
public InternalAggregation buildEmptyAggregation() {
return new InternalStats(name, 0, 0, Double.POSITIVE_INFINITY, Double.NEGATIVE_INFINITY, getMetaData());
return new InternalStats(name, 0, 0, Double.POSITIVE_INFINITY, Double.NEGATIVE_INFINITY, formatter, getMetaData());
}
public static class Factory extends ValuesSourceAggregatorFactory.LeafOnly<ValuesSource.Numeric, Map<String, Object>> {
@ -148,12 +154,12 @@ public class StatsAggegator extends NumericMetricsAggregator.MultiValue {
@Override
protected Aggregator createUnmapped(AggregationContext aggregationContext, Aggregator parent, Map<String, Object> metaData) {
return new StatsAggegator(name, 0, null, aggregationContext, parent, metaData);
return new StatsAggegator(name, 0, null, config.formatter(), aggregationContext, parent, metaData);
}
@Override
protected Aggregator create(ValuesSource.Numeric valuesSource, long expectedBucketsCount, AggregationContext aggregationContext, Aggregator parent, Map<String, Object> metaData) {
return new StatsAggegator(name, expectedBucketsCount, valuesSource, aggregationContext, parent, metaData);
return new StatsAggegator(name, expectedBucketsCount, valuesSource, config.formatter(), aggregationContext, parent, metaData);
}
}

View File

@ -40,4 +40,19 @@ public interface ExtendedStats extends Stats {
*/
double getStdDeviation();
/**
* The sum of the squares of the collected values as a String.
*/
String getSumOfSquaresAsString();
/**
* The variance of the collected values as a String.
*/
String getVarianceAsString();
/**
* The standard deviation of the collected values as a String.
*/
String getStdDeviationAsString();
}

View File

@ -20,6 +20,7 @@ package org.elasticsearch.search.aggregations.metrics.stats.extended;
import org.apache.lucene.index.LeafReaderContext;
import org.elasticsearch.ElasticsearchIllegalArgumentException;
import org.elasticsearch.common.inject.internal.Nullable;
import org.elasticsearch.common.lease.Releasables;
import org.elasticsearch.common.util.BigArrays;
import org.elasticsearch.common.util.DoubleArray;
@ -32,6 +33,7 @@ import org.elasticsearch.search.aggregations.support.AggregationContext;
import org.elasticsearch.search.aggregations.support.ValuesSource;
import org.elasticsearch.search.aggregations.support.ValuesSourceAggregatorFactory;
import org.elasticsearch.search.aggregations.support.ValuesSourceConfig;
import org.elasticsearch.search.aggregations.support.format.ValueFormatter;
import java.io.IOException;
import java.util.Map;
@ -49,10 +51,13 @@ public class ExtendedStatsAggregator extends NumericMetricsAggregator.MultiValue
private DoubleArray mins;
private DoubleArray maxes;
private DoubleArray sumOfSqrs;
private ValueFormatter formatter;
public ExtendedStatsAggregator(String name, long estimatedBucketsCount, ValuesSource.Numeric valuesSource, AggregationContext context, Aggregator parent, Map<String, Object> metaData) {
public ExtendedStatsAggregator(String name, long estimatedBucketsCount, ValuesSource.Numeric valuesSource,
@Nullable ValueFormatter formatter, AggregationContext context, Aggregator parent, Map<String, Object> metaData) {
super(name, estimatedBucketsCount, context, parent, metaData);
this.valuesSource = valuesSource;
this.formatter = formatter;
if (valuesSource != null) {
final long initialSize = estimatedBucketsCount < 2 ? 1 : estimatedBucketsCount;
counts = bigArrays.newLongArray(initialSize, true);
@ -144,16 +149,16 @@ public class ExtendedStatsAggregator extends NumericMetricsAggregator.MultiValue
@Override
public InternalAggregation buildAggregation(long owningBucketOrdinal) {
if (valuesSource == null) {
return new InternalExtendedStats(name, 0, 0d, Double.POSITIVE_INFINITY, Double.NEGATIVE_INFINITY, 0d, getMetaData());
return new InternalExtendedStats(name, 0, 0d, Double.POSITIVE_INFINITY, Double.NEGATIVE_INFINITY, 0d, formatter, getMetaData());
}
assert owningBucketOrdinal < counts.size();
return new InternalExtendedStats(name, counts.get(owningBucketOrdinal), sums.get(owningBucketOrdinal), mins.get(owningBucketOrdinal),
maxes.get(owningBucketOrdinal), sumOfSqrs.get(owningBucketOrdinal), getMetaData());
return new InternalExtendedStats(name, counts.get(owningBucketOrdinal), sums.get(owningBucketOrdinal),
mins.get(owningBucketOrdinal), maxes.get(owningBucketOrdinal), sumOfSqrs.get(owningBucketOrdinal), formatter, getMetaData());
}
@Override
public InternalAggregation buildEmptyAggregation() {
return new InternalExtendedStats(name, 0, 0d, Double.POSITIVE_INFINITY, Double.NEGATIVE_INFINITY, 0d, getMetaData());
return new InternalExtendedStats(name, 0, 0d, Double.POSITIVE_INFINITY, Double.NEGATIVE_INFINITY, 0d, formatter, getMetaData());
}
@Override
@ -169,12 +174,13 @@ public class ExtendedStatsAggregator extends NumericMetricsAggregator.MultiValue
@Override
protected Aggregator createUnmapped(AggregationContext aggregationContext, Aggregator parent, Map<String, Object> metaData) {
return new ExtendedStatsAggregator(name, 0, null, aggregationContext, parent, metaData);
return new ExtendedStatsAggregator(name, 0, null, config.formatter(), aggregationContext, parent, metaData);
}
@Override
protected Aggregator create(ValuesSource.Numeric valuesSource, long expectedBucketsCount, AggregationContext aggregationContext, Aggregator parent, Map<String, Object> metaData) {
return new ExtendedStatsAggregator(name, expectedBucketsCount, valuesSource, aggregationContext, parent, metaData);
return new ExtendedStatsAggregator(name, expectedBucketsCount, valuesSource, config.formatter(), aggregationContext, parent,
metaData);
}
}
}

View File

@ -18,6 +18,7 @@
*/
package org.elasticsearch.search.aggregations.metrics.stats.extended;
import org.elasticsearch.common.inject.internal.Nullable;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.common.xcontent.XContentBuilder;
@ -25,6 +26,7 @@ import org.elasticsearch.common.xcontent.XContentBuilderString;
import org.elasticsearch.search.aggregations.AggregationStreams;
import org.elasticsearch.search.aggregations.InternalAggregation;
import org.elasticsearch.search.aggregations.metrics.stats.InternalStats;
import org.elasticsearch.search.aggregations.support.format.ValueFormatter;
import java.io.IOException;
import java.util.Map;
@ -62,8 +64,9 @@ public class InternalExtendedStats extends InternalStats implements ExtendedStat
InternalExtendedStats() {} // for serialization
public InternalExtendedStats(String name, long count, double sum, double min, double max, double sumOfSqrs, Map<String, Object> metaData) {
super(name, count, sum, min, max, metaData);
public InternalExtendedStats(String name, long count, double sum, double min, double max, double sumOfSqrs,
@Nullable ValueFormatter formatter, Map<String, Object> metaData) {
super(name, count, sum, min, max, formatter, metaData);
this.sumOfSqrs = sumOfSqrs;
}
@ -101,6 +104,21 @@ public class InternalExtendedStats extends InternalStats implements ExtendedStat
return Math.sqrt(getVariance());
}
@Override
public String getSumOfSquaresAsString() {
return valueAsString(Metrics.sum_of_squares.name());
}
@Override
public String getVarianceAsString() {
return valueAsString(Metrics.variance.name());
}
@Override
public String getStdDeviationAsString() {
return valueAsString(Metrics.std_deviation.name());
}
@Override
public InternalExtendedStats reduce(ReduceContext reduceContext) {
double sumOfSqrs = 0;
@ -109,7 +127,8 @@ public class InternalExtendedStats extends InternalStats implements ExtendedStat
sumOfSqrs += stats.getSumOfSquares();
}
final InternalStats stats = super.reduce(reduceContext);
return new InternalExtendedStats(name, stats.getCount(), stats.getSum(), stats.getMin(), stats.getMax(), sumOfSqrs, getMetaData());
return new InternalExtendedStats(name, stats.getCount(), stats.getSum(), stats.getMin(), stats.getMax(), sumOfSqrs, valueFormatter,
getMetaData());
}
@Override

View File

@ -18,12 +18,14 @@
*/
package org.elasticsearch.search.aggregations.metrics.sum;
import org.elasticsearch.common.inject.internal.Nullable;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.search.aggregations.AggregationStreams;
import org.elasticsearch.search.aggregations.InternalAggregation;
import org.elasticsearch.search.aggregations.metrics.InternalNumericMetricsAggregation;
import org.elasticsearch.search.aggregations.support.format.ValueFormatter;
import org.elasticsearch.search.aggregations.support.format.ValueFormatterStreams;
import java.io.IOException;
@ -53,9 +55,10 @@ public class InternalSum extends InternalNumericMetricsAggregation.SingleValue i
InternalSum() {} // for serialization
InternalSum(String name, double sum, Map<String, Object> metaData){
InternalSum(String name, double sum, @Nullable ValueFormatter formatter, Map<String, Object> metaData) {
super(name, metaData);
this.sum = sum;
this.valueFormatter = formatter;
}
@Override
@ -78,7 +81,7 @@ public class InternalSum extends InternalNumericMetricsAggregation.SingleValue i
for (InternalAggregation aggregation : reduceContext.aggregations()) {
sum += ((InternalSum) aggregation).sum;
}
return new InternalSum(name, sum, getMetaData());
return new InternalSum(name, sum, valueFormatter, getMetaData());
}
@Override

View File

@ -18,12 +18,12 @@
*/
package org.elasticsearch.search.aggregations.metrics.sum;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.metrics.NumericMetricsAggregation;
/**
* An aggregation that computes the sum of the values in the current bucket.
*/
public interface Sum extends Aggregation {
public interface Sum extends NumericMetricsAggregation.SingleValue {
/**
* The sum.

View File

@ -19,6 +19,7 @@
package org.elasticsearch.search.aggregations.metrics.sum;
import org.apache.lucene.index.LeafReaderContext;
import org.elasticsearch.common.inject.internal.Nullable;
import org.elasticsearch.common.lease.Releasables;
import org.elasticsearch.common.util.DoubleArray;
import org.elasticsearch.index.fielddata.SortedNumericDoubleValues;
@ -29,6 +30,7 @@ import org.elasticsearch.search.aggregations.support.AggregationContext;
import org.elasticsearch.search.aggregations.support.ValuesSource;
import org.elasticsearch.search.aggregations.support.ValuesSourceAggregatorFactory;
import org.elasticsearch.search.aggregations.support.ValuesSourceConfig;
import org.elasticsearch.search.aggregations.support.format.ValueFormatter;
import java.io.IOException;
import java.util.Map;
@ -42,10 +44,13 @@ public class SumAggregator extends NumericMetricsAggregator.SingleValue {
private SortedNumericDoubleValues values;
private DoubleArray sums;
private ValueFormatter formatter;
public SumAggregator(String name, long estimatedBucketsCount, ValuesSource.Numeric valuesSource, AggregationContext context, Aggregator parent, Map<String, Object> metaData) {
public SumAggregator(String name, long estimatedBucketsCount, ValuesSource.Numeric valuesSource, @Nullable ValueFormatter formatter,
AggregationContext context, Aggregator parent, Map<String, Object> metaData) {
super(name, estimatedBucketsCount, context, parent, metaData);
this.valuesSource = valuesSource;
this.formatter = formatter;
if (valuesSource != null) {
final long initialSize = estimatedBucketsCount < 2 ? 1 : estimatedBucketsCount;
sums = bigArrays.newDoubleArray(initialSize, true);
@ -82,14 +87,14 @@ public class SumAggregator extends NumericMetricsAggregator.SingleValue {
@Override
public InternalAggregation buildAggregation(long owningBucketOrdinal) {
if (valuesSource == null) {
return new InternalSum(name, 0, getMetaData());
return new InternalSum(name, 0, formatter, getMetaData());
}
return new InternalSum(name, sums.get(owningBucketOrdinal), getMetaData());
return new InternalSum(name, sums.get(owningBucketOrdinal), formatter, getMetaData());
}
@Override
public InternalAggregation buildEmptyAggregation() {
return new InternalSum(name, 0.0, getMetaData());
return new InternalSum(name, 0.0, formatter, getMetaData());
}
public static class Factory extends ValuesSourceAggregatorFactory.LeafOnly<ValuesSource.Numeric, Map<String, Object>> {
@ -100,12 +105,12 @@ public class SumAggregator extends NumericMetricsAggregator.SingleValue {
@Override
protected Aggregator createUnmapped(AggregationContext aggregationContext, Aggregator parent, Map<String, Object> metaData) {
return new SumAggregator(name, 0, null, aggregationContext, parent, metaData);
return new SumAggregator(name, 0, null, config.formatter(), aggregationContext, parent, metaData);
}
@Override
protected Aggregator create(ValuesSource.Numeric valuesSource, long expectedBucketsCount, AggregationContext aggregationContext, Aggregator parent, Map<String, Object> metaData) {
return new SumAggregator(name, expectedBucketsCount, valuesSource, aggregationContext, parent, metaData);
return new SumAggregator(name, expectedBucketsCount, valuesSource, config.formatter(), aggregationContext, parent, metaData);
}
}

View File

@ -18,12 +18,14 @@
*/
package org.elasticsearch.search.aggregations.metrics.valuecount;
import org.elasticsearch.common.inject.internal.Nullable;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.search.aggregations.AggregationStreams;
import org.elasticsearch.search.aggregations.InternalAggregation;
import org.elasticsearch.search.aggregations.metrics.InternalNumericMetricsAggregation;
import org.elasticsearch.search.aggregations.support.format.ValueFormatter;
import java.io.IOException;
import java.util.Map;
@ -52,9 +54,10 @@ public class InternalValueCount extends InternalNumericMetricsAggregation.Single
InternalValueCount() {} // for serialization
public InternalValueCount(String name, long value, Map<String, Object> metaData) {
public InternalValueCount(String name, long value, @Nullable ValueFormatter formatter, Map<String, Object> metaData) {
super(name, metaData);
this.value = value;
this.valueFormatter = formatter;
}
@Override
@ -78,7 +81,7 @@ public class InternalValueCount extends InternalNumericMetricsAggregation.Single
for (InternalAggregation aggregation : reduceContext.aggregations()) {
valueCount += ((InternalValueCount) aggregation).value;
}
return new InternalValueCount(name, valueCount, getMetaData());
return new InternalValueCount(name, valueCount, valueFormatter, getMetaData());
}
@Override
@ -93,7 +96,11 @@ public class InternalValueCount extends InternalNumericMetricsAggregation.Single
@Override
public XContentBuilder doXContentBody(XContentBuilder builder, Params params) throws IOException {
return builder.field(CommonFields.VALUE, value);
builder.field(CommonFields.VALUE, value);
if (valueFormatter != null) {
builder.field(CommonFields.VALUE_AS_STRING, valueFormatter.format(value));
}
return builder;
}
@Override

View File

@ -18,13 +18,13 @@
*/
package org.elasticsearch.search.aggregations.metrics.valuecount;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.metrics.NumericMetricsAggregation;
/**
* An get that holds the number of <strong>values</strong> that the current document set has for a specific
* field.
*/
public interface ValueCount extends Aggregation {
public interface ValueCount extends NumericMetricsAggregation.SingleValue {
/**
* @return The count

View File

@ -19,6 +19,7 @@
package org.elasticsearch.search.aggregations.metrics.valuecount;
import org.apache.lucene.index.LeafReaderContext;
import org.elasticsearch.common.inject.internal.Nullable;
import org.elasticsearch.common.lease.Releasables;
import org.elasticsearch.common.util.LongArray;
import org.elasticsearch.index.fielddata.SortedBinaryDocValues;
@ -29,6 +30,7 @@ import org.elasticsearch.search.aggregations.support.AggregationContext;
import org.elasticsearch.search.aggregations.support.ValuesSource;
import org.elasticsearch.search.aggregations.support.ValuesSourceAggregatorFactory;
import org.elasticsearch.search.aggregations.support.ValuesSourceConfig;
import org.elasticsearch.search.aggregations.support.format.ValueFormatter;
import java.io.IOException;
import java.util.Map;
@ -46,10 +48,13 @@ public class ValueCountAggregator extends NumericMetricsAggregator.SingleValue {
// a count per bucket
LongArray counts;
private ValueFormatter formatter;
public ValueCountAggregator(String name, long expectedBucketsCount, ValuesSource valuesSource, AggregationContext aggregationContext, Aggregator parent, Map<String, Object> metaData) {
public ValueCountAggregator(String name, long expectedBucketsCount, ValuesSource valuesSource, @Nullable ValueFormatter formatter,
AggregationContext aggregationContext, Aggregator parent, Map<String, Object> metaData) {
super(name, 0, aggregationContext, parent, metaData);
this.valuesSource = valuesSource;
this.formatter = formatter;
if (valuesSource != null) {
// expectedBucketsCount == 0 means it's a top level bucket
final long initialSize = expectedBucketsCount < 2 ? 1 : expectedBucketsCount;
@ -82,15 +87,15 @@ public class ValueCountAggregator extends NumericMetricsAggregator.SingleValue {
@Override
public InternalAggregation buildAggregation(long owningBucketOrdinal) {
if (valuesSource == null) {
return new InternalValueCount(name, 0, getMetaData());
return new InternalValueCount(name, 0, formatter, getMetaData());
}
assert owningBucketOrdinal < counts.size();
return new InternalValueCount(name, counts.get(owningBucketOrdinal), getMetaData());
return new InternalValueCount(name, counts.get(owningBucketOrdinal), formatter, getMetaData());
}
@Override
public InternalAggregation buildEmptyAggregation() {
return new InternalValueCount(name, 0l, getMetaData());
return new InternalValueCount(name, 0l, formatter, getMetaData());
}
@Override
@ -106,12 +111,13 @@ public class ValueCountAggregator extends NumericMetricsAggregator.SingleValue {
@Override
protected Aggregator createUnmapped(AggregationContext aggregationContext, Aggregator parent, Map<String, Object> metaData) {
return new ValueCountAggregator(name, 0, null, aggregationContext, parent, metaData);
return new ValueCountAggregator(name, 0, null, config.formatter(), aggregationContext, parent, metaData);
}
@Override
protected Aggregator create(VS valuesSource, long expectedBucketsCount, AggregationContext aggregationContext, Aggregator parent, Map<String, Object> metaData) {
return new ValueCountAggregator(name, expectedBucketsCount, valuesSource, aggregationContext, parent, metaData);
return new ValueCountAggregator(name, expectedBucketsCount, valuesSource, config.formatter(), aggregationContext, parent,
metaData);
}
}

View File

@ -22,7 +22,6 @@ import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.search.aggregations.bucket.global.Global;
import org.elasticsearch.search.aggregations.bucket.histogram.Histogram;
import org.elasticsearch.search.aggregations.metrics.avg.Avg;
import org.elasticsearch.test.junit.annotations.TestLogging;
import org.junit.Test;
import static org.elasticsearch.index.query.QueryBuilders.matchAllQuery;
@ -158,6 +157,18 @@ public class AvgTests extends AbstractNumericTests {
assertThat(avg.getValue(), equalTo((double) (2+3+4+5+6+7+8+9+10+11) / 10));
}
public void testSingleValuedField_WithFormatter() throws Exception {
SearchResponse searchResponse = client().prepareSearch("idx").setQuery(matchAllQuery())
.addAggregation(avg("avg").format("#").field("value")).execute().actionGet();
assertThat(searchResponse.getHits().getTotalHits(), equalTo(10l));
Avg avg = searchResponse.getAggregations().get("avg");
assertThat(avg, notNullValue());
assertThat(avg.getName(), equalTo("avg"));
assertThat(avg.getValue(), equalTo((double) (1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10) / 10));
assertThat(avg.getValueAsString(), equalTo("6"));
}
@Test
public void testMultiValuedField() throws Exception {

View File

@ -123,6 +123,33 @@ public class ExtendedStatsTests extends AbstractNumericTests {
assertThat(stats.getStdDeviation(), equalTo(stdDev(1, 2, 3, 4, 5, 6, 7, 8 ,9, 10)));
}
public void testSingleValuedField_WithFormatter() throws Exception {
SearchResponse searchResponse = client().prepareSearch("idx").setQuery(matchAllQuery())
.addAggregation(extendedStats("stats").format("0000.0").field("value")).execute().actionGet();
assertThat(searchResponse.getHits().getTotalHits(), equalTo(10l));
ExtendedStats stats = searchResponse.getAggregations().get("stats");
assertThat(stats, notNullValue());
assertThat(stats.getName(), equalTo("stats"));
assertThat(stats.getAvg(), equalTo((double) (1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10) / 10));
assertThat(stats.getAvgAsString(), equalTo("0005.5"));
assertThat(stats.getMin(), equalTo(1.0));
assertThat(stats.getMinAsString(), equalTo("0001.0"));
assertThat(stats.getMax(), equalTo(10.0));
assertThat(stats.getMaxAsString(), equalTo("0010.0"));
assertThat(stats.getSum(), equalTo((double) 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10));
assertThat(stats.getSumAsString(), equalTo("0055.0"));
assertThat(stats.getCount(), equalTo(10l));
assertThat(stats.getCountAsString(), equalTo("0010.0"));
assertThat(stats.getSumOfSquares(), equalTo((double) 1 + 4 + 9 + 16 + 25 + 36 + 49 + 64 + 81 + 100));
assertThat(stats.getSumOfSquaresAsString(), equalTo("0385.0"));
assertThat(stats.getVariance(), equalTo(variance(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)));
assertThat(stats.getVarianceAsString(), equalTo("0008.2"));
assertThat(stats.getStdDeviation(), equalTo(stdDev(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)));
assertThat(stats.getStdDeviationAsString(), equalTo("0002.9"));
}
@Test
public void testSingleValuedField_getProperty() throws Exception {

View File

@ -86,6 +86,20 @@ public class MaxTests extends AbstractNumericTests {
assertThat(max.getValue(), equalTo(10.0));
}
@Test
public void testSingleValuedField_WithFormatter() throws Exception {
SearchResponse searchResponse = client().prepareSearch("idx").setQuery(matchAllQuery())
.addAggregation(max("max").format("0000.0").field("value")).execute().actionGet();
assertThat(searchResponse.getHits().getTotalHits(), equalTo(10l));
Max max = searchResponse.getAggregations().get("max");
assertThat(max, notNullValue());
assertThat(max.getName(), equalTo("max"));
assertThat(max.getValue(), equalTo(10.0));
assertThat(max.getValueAsString(), equalTo("0010.0"));
}
@Test
public void testSingleValuedField_getProperty() throws Exception {

View File

@ -86,6 +86,20 @@ public class MinTests extends AbstractNumericTests {
assertThat(min.getValue(), equalTo(1.0));
}
@Test
public void testSingleValuedField_WithFormatter() throws Exception {
SearchResponse searchResponse = client().prepareSearch("idx").setQuery(matchAllQuery())
.addAggregation(min("min").format("0000.0").field("value")).execute().actionGet();
assertThat(searchResponse.getHits().getTotalHits(), equalTo(10l));
Min min = searchResponse.getAggregations().get("min");
assertThat(min, notNullValue());
assertThat(min.getName(), equalTo("min"));
assertThat(min.getValue(), equalTo(1.0));
assertThat(min.getValueAsString(), equalTo("0001.0"));
}
@Test
public void testSingleValuedField_getProperty() throws Exception {

View File

@ -19,6 +19,7 @@
package org.elasticsearch.search.aggregations.metrics;
import com.google.common.collect.Lists;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.common.logging.Loggers;
import org.elasticsearch.search.aggregations.bucket.global.Global;

View File

@ -23,7 +23,6 @@ import org.elasticsearch.action.search.ShardSearchFailure;
import org.elasticsearch.search.aggregations.bucket.global.Global;
import org.elasticsearch.search.aggregations.bucket.histogram.Histogram;
import org.elasticsearch.search.aggregations.metrics.stats.Stats;
import org.elasticsearch.test.junit.annotations.TestLogging;
import org.junit.Test;
import static org.elasticsearch.index.query.QueryBuilders.matchAllQuery;
@ -108,6 +107,28 @@ public class StatsTests extends AbstractNumericTests {
assertThat(stats.getCount(), equalTo(10l));
}
public void testSingleValuedField_WithFormatter() throws Exception {
SearchResponse searchResponse = client().prepareSearch("idx").setQuery(matchAllQuery())
.addAggregation(stats("stats").format("0000.0").field("value")).execute().actionGet();
assertThat(searchResponse.getHits().getTotalHits(), equalTo(10l));
Stats stats = searchResponse.getAggregations().get("stats");
assertThat(stats, notNullValue());
assertThat(stats.getName(), equalTo("stats"));
assertThat(stats.getAvg(), equalTo((double) (1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10) / 10));
assertThat(stats.getAvgAsString(), equalTo("0005.5"));
assertThat(stats.getMin(), equalTo(1.0));
assertThat(stats.getMinAsString(), equalTo("0001.0"));
assertThat(stats.getMax(), equalTo(10.0));
assertThat(stats.getMaxAsString(), equalTo("0010.0"));
assertThat(stats.getSum(), equalTo((double) 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10));
assertThat(stats.getSumAsString(), equalTo("0055.0"));
assertThat(stats.getCount(), equalTo(10l));
assertThat(stats.getCountAsString(), equalTo("0010.0"));
}
@Test
public void testSingleValuedField_getProperty() throws Exception {

View File

@ -86,6 +86,20 @@ public class SumTests extends AbstractNumericTests {
assertThat(sum.getValue(), equalTo((double) 1+2+3+4+5+6+7+8+9+10));
}
@Test
public void testSingleValuedField_WithFormatter() throws Exception {
SearchResponse searchResponse = client().prepareSearch("idx").setQuery(matchAllQuery())
.addAggregation(sum("sum").format("0000.0").field("value")).execute().actionGet();
assertThat(searchResponse.getHits().getTotalHits(), equalTo(10l));
Sum sum = searchResponse.getAggregations().get("sum");
assertThat(sum, notNullValue());
assertThat(sum.getName(), equalTo("sum"));
assertThat(sum.getValue(), equalTo((double) 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10));
assertThat(sum.getValueAsString(), equalTo("0055.0"));
}
@Test
public void testSingleValuedField_getProperty() throws Exception {