Implementation of GapPolicy for derivative

This commit is contained in:
Colin Goodheart-Smithe 2015-03-02 14:53:05 +00:00
parent bcaf22eac3
commit 7c046d28bf
5 changed files with 193 additions and 115 deletions

View File

@ -93,7 +93,7 @@ public class InternalSimpleValue extends InternalNumericMetricsAggregation.Singl
@Override
public XContentBuilder doXContentBody(XContentBuilder builder, Params params) throws IOException {
boolean hasValue = !Double.isInfinite(value);
boolean hasValue = !(Double.isInfinite(value) || Double.isNaN(value));
builder.field(CommonFields.VALUE, hasValue ? value : null);
if (hasValue && valueFormatter != null) {
builder.field(CommonFields.VALUE_AS_STRING, valueFormatter.format(value));

View File

@ -21,12 +21,14 @@ package org.elasticsearch.search.aggregations.reducers.derivative;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.search.aggregations.reducers.ReducerBuilder;
import org.elasticsearch.search.aggregations.reducers.derivative.DerivativeReducer.GapPolicy;
import java.io.IOException;
public class DerivativeBuilder extends ReducerBuilder<DerivativeBuilder> {
private String format;
private GapPolicy gapPolicy;
public DerivativeBuilder(String name) {
super(name, DerivativeReducer.TYPE.name());
@ -37,11 +39,19 @@ public class DerivativeBuilder extends ReducerBuilder<DerivativeBuilder> {
return this;
}
public DerivativeBuilder gapPolicy(GapPolicy gapPolicy) {
this.gapPolicy = gapPolicy;
return this;
}
@Override
protected XContentBuilder internalXContent(XContentBuilder builder, Params params) throws IOException {
if (format != null) {
builder.field(DerivativeParser.FORMAT.getPreferredName(), format);
}
if (gapPolicy != null) {
builder.field(DerivativeParser.GAP_POLICY.getPreferredName(), gapPolicy.getName());
}
return builder;
}

View File

@ -24,6 +24,7 @@ import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.search.SearchParseException;
import org.elasticsearch.search.aggregations.reducers.Reducer;
import org.elasticsearch.search.aggregations.reducers.ReducerFactory;
import org.elasticsearch.search.aggregations.reducers.derivative.DerivativeReducer.GapPolicy;
import org.elasticsearch.search.aggregations.support.format.ValueFormat;
import org.elasticsearch.search.aggregations.support.format.ValueFormatter;
import org.elasticsearch.search.internal.SearchContext;
@ -33,7 +34,9 @@ import java.util.ArrayList;
import java.util.List;
public class DerivativeParser implements Reducer.Parser {
public static final ParseField FORMAT = new ParseField("format");
public static final ParseField GAP_POLICY = new ParseField("gap_policy");
@Override
public String type() {
@ -46,6 +49,7 @@ public class DerivativeParser implements Reducer.Parser {
String currentFieldName = null;
String[] bucketsPaths = null;
String format = null;
GapPolicy gapPolicy = GapPolicy.IGNORE;
while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
if (token == XContentParser.Token.FIELD_NAME) {
@ -55,6 +59,8 @@ public class DerivativeParser implements Reducer.Parser {
format = parser.text();
} else if (BUCKETS_PATH.match(currentFieldName)) {
bucketsPaths = new String[] { parser.text() };
} else if (GAP_POLICY.match(currentFieldName)) {
gapPolicy = GapPolicy.parse(context, parser.text());
} else {
throw new SearchParseException(context, "Unknown key for a " + token + " in [" + reducerName + "]: ["
+ currentFieldName + "].");
@ -86,7 +92,7 @@ public class DerivativeParser implements Reducer.Parser {
formatter = ValueFormat.Patternable.Number.format(format).formatter();
}
return new DerivativeReducer.Factory(reducerName, bucketsPaths, formatter);
return new DerivativeReducer.Factory(reducerName, bucketsPaths, formatter, gapPolicy);
}
}

View File

@ -24,8 +24,10 @@ import com.google.common.collect.Lists;
import org.elasticsearch.ElasticsearchIllegalStateException;
import org.elasticsearch.common.Nullable;
import org.elasticsearch.common.ParseField;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.search.SearchParseException;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.AggregationExecutionException;
import org.elasticsearch.search.aggregations.Aggregator;
@ -44,9 +46,11 @@ import org.elasticsearch.search.aggregations.support.AggregationContext;
import org.elasticsearch.search.aggregations.support.AggregationPath;
import org.elasticsearch.search.aggregations.support.format.ValueFormatter;
import org.elasticsearch.search.aggregations.support.format.ValueFormatterStreams;
import org.elasticsearch.search.internal.SearchContext;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
@ -75,13 +79,16 @@ public class DerivativeReducer extends Reducer {
};
private ValueFormatter formatter;
private GapPolicy gapPolicy;
public DerivativeReducer() {
}
public DerivativeReducer(String name, String[] bucketsPaths, @Nullable ValueFormatter formatter, Map<String, Object> metadata) {
public DerivativeReducer(String name, String[] bucketsPaths, @Nullable ValueFormatter formatter, GapPolicy gapPolicy,
Map<String, Object> metadata) {
super(name, bucketsPaths, metadata);
this.formatter = formatter;
this.gapPolicy = gapPolicy;
}
@Override
@ -100,9 +107,6 @@ public class DerivativeReducer extends Reducer {
for (InternalHistogram.Bucket bucket : buckets) {
Double thisBucketValue = resolveBucketValue(histo, bucket);
if (lastBucketValue != null) {
if (thisBucketValue == null) {
throw new ElasticsearchIllegalStateException("FOUND GAP IN DATA"); // NOCOMMIT deal with gaps in data
}
double diff = thisBucketValue - lastBucketValue;
List<InternalAggregation> aggs = new ArrayList<>(Lists.transform(bucket.getAggregations().asList(), FUNCTION));
@ -122,14 +126,31 @@ public class DerivativeReducer extends Reducer {
try {
Object propertyValue = bucket.getProperty(histo.getName(), AggregationPath.parse(bucketsPaths()[0])
.getPathElementsAsStringList());
if (propertyValue == null) {
throw new AggregationExecutionException(DerivativeParser.BUCKETS_PATH.getPreferredName()
+ " must reference either a number value or a single value numeric metric aggregation");
} else {
double value;
if (propertyValue instanceof Number) {
return ((Number) propertyValue).doubleValue();
value = ((Number) propertyValue).doubleValue();
} else if (propertyValue instanceof InternalNumericMetricsAggregation.SingleValue) {
return ((InternalNumericMetricsAggregation.SingleValue) propertyValue).value();
value = ((InternalNumericMetricsAggregation.SingleValue) propertyValue).value();
} else {
throw new AggregationExecutionException(DerivativeParser.BUCKETS_PATH.getPreferredName()
+ " must reference either a number value or a single value numeric metric aggregation");
}
if (Double.isInfinite(value) || Double.isNaN(value)) {
switch (gapPolicy) {
case INSERT_ZEROS:
return 0.0;
case IGNORE:
default:
return Double.NaN;
}
} else {
return value;
}
}
} catch (InvalidAggregationPathException e) {
return null;
}
@ -138,27 +159,83 @@ public class DerivativeReducer extends Reducer {
@Override
public void doReadFrom(StreamInput in) throws IOException {
formatter = ValueFormatterStreams.readOptional(in);
gapPolicy = GapPolicy.readFrom(in);
}
@Override
public void doWriteTo(StreamOutput out) throws IOException {
ValueFormatterStreams.writeOptional(formatter, out);
gapPolicy.writeTo(out);
}
public static class Factory extends ReducerFactory {
private final ValueFormatter formatter;
private GapPolicy gapPolicy;
public Factory(String name, String[] bucketsPaths, @Nullable ValueFormatter formatter) {
public Factory(String name, String[] bucketsPaths, @Nullable ValueFormatter formatter, GapPolicy gapPolicy) {
super(name, TYPE.name(), bucketsPaths);
this.formatter = formatter;
this.gapPolicy = gapPolicy;
}
@Override
protected Reducer createInternal(AggregationContext context, Aggregator parent, boolean collectsFromSingleBucket,
Map<String, Object> metaData) throws IOException {
return new DerivativeReducer(name, bucketsPaths, formatter, metaData);
return new DerivativeReducer(name, bucketsPaths, formatter, gapPolicy, metaData);
}
}
public static enum GapPolicy {
INSERT_ZEROS((byte) 0, "insert_zeros"), IGNORE((byte) 1, "ignore");
public static GapPolicy parse(SearchContext context, String text) {
GapPolicy result = null;
for (GapPolicy policy : values()) {
if (policy.parseField.match(text)) {
if (result == null) {
result = policy;
} else {
throw new ElasticsearchIllegalStateException("Text can be parsed to 2 different gap policies: text=[" + text
+ "], " + "policies=" + Arrays.asList(result, policy));
}
}
}
if (result == null) {
final List<String> validNames = new ArrayList<>();
for (GapPolicy policy : values()) {
validNames.add(policy.getName());
}
throw new SearchParseException(context, "Invalid gap policy: [" + text + "], accepted values: " + validNames);
}
return result;
}
private final byte id;
private final ParseField parseField;
private GapPolicy(byte id, String name) {
this.id = id;
this.parseField = new ParseField(name);
}
public void writeTo(StreamOutput out) throws IOException {
out.writeByte(id);
}
public static GapPolicy readFrom(StreamInput in) throws IOException {
byte id = in.readByte();
for (GapPolicy gapPolicy : values()) {
if (id == gapPolicy.id) {
return gapPolicy;
}
}
throw new IllegalStateException("Unknown GapPolicy with id [" + id + "]");
}
public String getName() {
return parseField.getPreferredName();
}
}
}

View File

@ -19,13 +19,13 @@
package org.elasticsearch.search.aggregations.reducers;
import org.apache.lucene.util.LuceneTestCase.AwaitsFix;
import org.elasticsearch.action.index.IndexRequestBuilder;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.search.aggregations.bucket.histogram.Histogram;
import org.elasticsearch.search.aggregations.bucket.histogram.Histogram.Bucket;
import org.elasticsearch.search.aggregations.bucket.histogram.InternalHistogram;
import org.elasticsearch.search.aggregations.metrics.sum.Sum;
import org.elasticsearch.search.aggregations.reducers.derivative.DerivativeReducer.GapPolicy;
import org.elasticsearch.search.aggregations.support.AggregationPath;
import org.elasticsearch.test.ElasticsearchIntegrationTest;
import org.hamcrest.Matchers;
@ -388,15 +388,14 @@ public class DerivativeTests extends ElasticsearchIntegrationTest {
}
}
@AwaitsFix(bugUrl = "waiting for derivative to gaps")
@Test
public void singleValuedFieldWithGaps() throws Exception {
SearchResponse searchResponse = client()
.prepareSearch("empty_bucket_idx")
.setQuery(matchAllQuery())
.addAggregation(
histogram("histo").field(SINGLE_VALUED_FIELD_NAME).interval(interval)
.subAggregation(derivative("deriv").setBucketsPaths("_count"))) // NOCOMMITadd ignore gapPolicy
histogram("histo").field(SINGLE_VALUED_FIELD_NAME).interval(1).minDocCount(0)
.subAggregation(derivative("deriv").setBucketsPaths("_count")))
.execute().actionGet();
assertThat(searchResponse.getHits().getTotalHits(), equalTo(14l));
@ -405,91 +404,30 @@ public class DerivativeTests extends ElasticsearchIntegrationTest {
assertThat(deriv, Matchers.notNullValue());
assertThat(deriv.getName(), equalTo("histo"));
List<Histogram.Bucket> buckets = (List<Bucket>) deriv.getBuckets();
assertThat(buckets.size(), equalTo(5));
assertThat(buckets.size(), equalTo(12));
Histogram.Bucket bucket = buckets.get(0);
assertThat(bucket, notNullValue());
assertThat(((Number) bucket.getKey()).longValue(), equalTo(0l));
assertThat(bucket.getDocCount(), equalTo(0l));
assertThat(bucket.getDocCount(), equalTo(1l));
SimpleValue docCountDeriv = bucket.getAggregations().get("deriv");
assertThat(docCountDeriv, notNullValue());
assertThat(docCountDeriv.value(), equalTo(0d));
assertThat(docCountDeriv, nullValue());
bucket = buckets.get(1);
assertThat(bucket, notNullValue());
assertThat(((Number) bucket.getKey()).longValue(), equalTo(1l));
assertThat(bucket.getDocCount(), equalTo(0l));
docCountDeriv = bucket.getAggregations().get("deriv");
assertThat(docCountDeriv, notNullValue());
assertThat(docCountDeriv.value(), equalTo(1d));
bucket = buckets.get(2);
assertThat(bucket, notNullValue());
assertThat(((Number) bucket.getKey()).longValue(), equalTo(4l));
assertThat(bucket.getDocCount(), equalTo(0l));
assertThat(bucket.getDocCount(), equalTo(1l));
docCountDeriv = bucket.getAggregations().get("deriv");
assertThat(docCountDeriv, notNullValue());
assertThat(docCountDeriv.value(), equalTo(0d));
bucket = buckets.get(3);
assertThat(bucket, notNullValue());
assertThat(((Number) bucket.getKey()).longValue(), equalTo(9l));
assertThat(bucket.getDocCount(), equalTo(0l));
docCountDeriv = bucket.getAggregations().get("deriv");
assertThat(docCountDeriv, notNullValue());
assertThat(docCountDeriv.value(), equalTo(-1d));
bucket = buckets.get(4);
assertThat(bucket, notNullValue());
assertThat(((Number) bucket.getKey()).longValue(), equalTo(10l));
assertThat(bucket.getDocCount(), equalTo(0l));
docCountDeriv = bucket.getAggregations().get("deriv");
assertThat(docCountDeriv, notNullValue());
assertThat(docCountDeriv.value(), equalTo(-1d));
}
@AwaitsFix(bugUrl = "waiting for derivative to support insert_zeros gap policy")
@Test
public void singleValuedFieldWithGaps_insertZeros() throws Exception {
SearchResponse searchResponse = client()
.prepareSearch("empty_bucket_idx")
.setQuery(matchAllQuery())
.addAggregation(
histogram("histo").field(SINGLE_VALUED_FIELD_NAME).interval(interval)
.subAggregation(derivative("deriv").setBucketsPaths("_count"))) // NOCOMMIT add insert_zeros gapPolicy
.execute().actionGet();
assertThat(searchResponse.getHits().getTotalHits(), equalTo(14l));
InternalHistogram deriv = searchResponse.getAggregations().get("histo");
assertThat(deriv, Matchers.notNullValue());
assertThat(deriv.getName(), equalTo("histo"));
List<Histogram.Bucket> buckets = (List<Bucket>) deriv.getBuckets();
assertThat(buckets.size(), equalTo(11));
Histogram.Bucket bucket = buckets.get(0);
assertThat(bucket, notNullValue());
assertThat(((Number) bucket.getKey()).longValue(), equalTo(0l));
assertThat(bucket.getDocCount(), equalTo(0l));
SimpleValue docCountDeriv = bucket.getAggregations().get("deriv");
assertThat(docCountDeriv, notNullValue());
assertThat(docCountDeriv.value(), equalTo(0d));
bucket = buckets.get(1);
assertThat(bucket, notNullValue());
assertThat(((Number) bucket.getKey()).longValue(), equalTo(1l));
assertThat(bucket.getDocCount(), equalTo(0l));
docCountDeriv = bucket.getAggregations().get("deriv");
assertThat(docCountDeriv, notNullValue());
assertThat(docCountDeriv.value(), equalTo(1d));
bucket = buckets.get(2);
assertThat(bucket, notNullValue());
assertThat(((Number) bucket.getKey()).longValue(), equalTo(2l));
assertThat(bucket.getDocCount(), equalTo(0l));
assertThat(bucket.getDocCount(), equalTo(2l));
docCountDeriv = bucket.getAggregations().get("deriv");
assertThat(docCountDeriv, notNullValue());
assertThat(docCountDeriv.value(), equalTo(-2d));
assertThat(docCountDeriv.value(), equalTo(1d));
bucket = buckets.get(3);
assertThat(bucket, notNullValue());
@ -497,23 +435,23 @@ public class DerivativeTests extends ElasticsearchIntegrationTest {
assertThat(bucket.getDocCount(), equalTo(0l));
docCountDeriv = bucket.getAggregations().get("deriv");
assertThat(docCountDeriv, notNullValue());
assertThat(docCountDeriv.value(), equalTo(2d));
assertThat(docCountDeriv.value(), equalTo(-2d));
bucket = buckets.get(4);
assertThat(bucket, notNullValue());
assertThat(((Number) bucket.getKey()).longValue(), equalTo(4l));
assertThat(bucket.getDocCount(), equalTo(0l));
assertThat(bucket.getDocCount(), equalTo(2l));
docCountDeriv = bucket.getAggregations().get("deriv");
assertThat(docCountDeriv, notNullValue());
assertThat(docCountDeriv.value(), equalTo(0d));
assertThat(docCountDeriv.value(), equalTo(2d));
bucket = buckets.get(5);
assertThat(bucket, notNullValue());
assertThat(((Number) bucket.getKey()).longValue(), equalTo(5l));
assertThat(bucket.getDocCount(), equalTo(0l));
assertThat(bucket.getDocCount(), equalTo(2l));
docCountDeriv = bucket.getAggregations().get("deriv");
assertThat(docCountDeriv, notNullValue());
assertThat(docCountDeriv.value(), equalTo(-2d));
assertThat(docCountDeriv.value(), equalTo(0d));
bucket = buckets.get(6);
assertThat(bucket, notNullValue());
@ -521,7 +459,7 @@ public class DerivativeTests extends ElasticsearchIntegrationTest {
assertThat(bucket.getDocCount(), equalTo(0l));
docCountDeriv = bucket.getAggregations().get("deriv");
assertThat(docCountDeriv, notNullValue());
assertThat(docCountDeriv.value(), equalTo(0d));
assertThat(docCountDeriv.value(), equalTo(-2d));
bucket = buckets.get(7);
assertThat(bucket, notNullValue());
@ -537,95 +475,142 @@ public class DerivativeTests extends ElasticsearchIntegrationTest {
assertThat(bucket.getDocCount(), equalTo(0l));
docCountDeriv = bucket.getAggregations().get("deriv");
assertThat(docCountDeriv, notNullValue());
assertThat(docCountDeriv.value(), equalTo(3d));
assertThat(docCountDeriv.value(), equalTo(0d));
bucket = buckets.get(9);
assertThat(bucket, notNullValue());
assertThat(((Number) bucket.getKey()).longValue(), equalTo(9l));
assertThat(bucket.getDocCount(), equalTo(0l));
assertThat(bucket.getDocCount(), equalTo(3l));
docCountDeriv = bucket.getAggregations().get("deriv");
assertThat(docCountDeriv, notNullValue());
assertThat(docCountDeriv.value(), equalTo(-1d));
assertThat(docCountDeriv.value(), equalTo(3d));
bucket = buckets.get(10);
assertThat(bucket, notNullValue());
assertThat(((Number) bucket.getKey()).longValue(), equalTo(10l));
assertThat(bucket.getDocCount(), equalTo(0l));
assertThat(bucket.getDocCount(), equalTo(2l));
docCountDeriv = bucket.getAggregations().get("deriv");
assertThat(docCountDeriv, notNullValue());
assertThat(docCountDeriv.value(), equalTo(-1d));
bucket = buckets.get(11);
assertThat(bucket, notNullValue());
assertThat(((Number) bucket.getKey()).longValue(), equalTo(11l));
assertThat(bucket.getDocCount(), equalTo(1l));
docCountDeriv = bucket.getAggregations().get("deriv");
assertThat(docCountDeriv, notNullValue());
assertThat(docCountDeriv.value(), equalTo(-1d));
}
@AwaitsFix(bugUrl = "waiting for derivative to support interpolate gapPolicy")
@Test
public void singleValuedFieldWithGaps_interpolate() throws Exception {
public void singleValuedFieldWithGaps_insertZeros() throws Exception {
SearchResponse searchResponse = client()
.prepareSearch("empty_bucket_idx")
.setQuery(matchAllQuery())
.addAggregation(
histogram("histo").field(SINGLE_VALUED_FIELD_NAME).interval(interval)
.subAggregation(derivative("deriv").setBucketsPaths("_count"))).execute().actionGet(); // NOCOMMIT add interpolate gapPolicy
histogram("histo").field(SINGLE_VALUED_FIELD_NAME).interval(1).minDocCount(0)
.subAggregation(derivative("deriv").setBucketsPaths("_count").gapPolicy(GapPolicy.INSERT_ZEROS)))
.execute().actionGet();
assertThat(searchResponse.getHits().getTotalHits(), equalTo(14l));
InternalHistogram deriv = searchResponse.getAggregations().get("deriv");
InternalHistogram deriv = searchResponse.getAggregations().get("histo");
assertThat(deriv, Matchers.notNullValue());
assertThat(deriv.getName(), equalTo("histo"));
List<Histogram.Bucket> buckets = (List<Bucket>) deriv.getBuckets();
assertThat(buckets.size(), equalTo(7));
assertThat(buckets.size(), equalTo(12));
Histogram.Bucket bucket = buckets.get(0);
assertThat(bucket, notNullValue());
assertThat(((Number) bucket.getKey()).longValue(), equalTo(0l));
assertThat(bucket.getDocCount(), equalTo(0l));
assertThat(bucket.getDocCount(), equalTo(1l));
SimpleValue docCountDeriv = bucket.getAggregations().get("deriv");
assertThat(docCountDeriv, notNullValue());
assertThat(docCountDeriv.value(), equalTo(0d));
assertThat(docCountDeriv, nullValue());
bucket = buckets.get(1);
assertThat(bucket, notNullValue());
assertThat(((Number) bucket.getKey()).longValue(), equalTo(1l));
assertThat(bucket.getDocCount(), equalTo(0l));
assertThat(bucket.getDocCount(), equalTo(1l));
docCountDeriv = bucket.getAggregations().get("deriv");
assertThat(docCountDeriv, notNullValue());
assertThat(docCountDeriv.value(), equalTo(1d));
assertThat(docCountDeriv.value(), equalTo(0d));
bucket = buckets.get(2);
assertThat(bucket, notNullValue());
assertThat(((Number) bucket.getKey()).longValue(), equalTo(2l));
assertThat(bucket.getDocCount(), equalTo(0l));
assertThat(bucket.getDocCount(), equalTo(2l));
docCountDeriv = bucket.getAggregations().get("deriv");
assertThat(docCountDeriv, notNullValue());
assertThat(docCountDeriv.value(), equalTo(0d));
assertThat(docCountDeriv.value(), equalTo(1d));
bucket = buckets.get(3);
assertThat(bucket, notNullValue());
assertThat(((Number) bucket.getKey()).longValue(), equalTo(3l));
assertThat(bucket.getDocCount(), equalTo(0l));
docCountDeriv = bucket.getAggregations().get("deriv");
assertThat(docCountDeriv, notNullValue());
assertThat(docCountDeriv.value(), equalTo(-2d));
bucket = buckets.get(4);
assertThat(bucket, notNullValue());
assertThat(((Number) bucket.getKey()).longValue(), equalTo(4l));
assertThat(bucket.getDocCount(), equalTo(2l));
docCountDeriv = bucket.getAggregations().get("deriv");
assertThat(docCountDeriv, notNullValue());
assertThat(docCountDeriv.value(), equalTo(2d));
bucket = buckets.get(5);
assertThat(bucket, notNullValue());
assertThat(((Number) bucket.getKey()).longValue(), equalTo(5l));
assertThat(bucket.getDocCount(), equalTo(2l));
docCountDeriv = bucket.getAggregations().get("deriv");
assertThat(docCountDeriv, notNullValue());
assertThat(docCountDeriv.value(), equalTo(0d));
bucket = buckets.get(6);
assertThat(bucket, notNullValue());
assertThat(((Number) bucket.getKey()).longValue(), equalTo(6l));
assertThat(bucket.getDocCount(), equalTo(0l));
docCountDeriv = bucket.getAggregations().get("deriv");
assertThat(docCountDeriv, notNullValue());
assertThat(docCountDeriv.value(), equalTo(-2d));
bucket = buckets.get(7);
assertThat(bucket, notNullValue());
assertThat(((Number) bucket.getKey()).longValue(), equalTo(7l));
assertThat(bucket.getDocCount(), equalTo(0l));
docCountDeriv = bucket.getAggregations().get("deriv");
assertThat(docCountDeriv, notNullValue());
assertThat(docCountDeriv.value(), equalTo(0d));
bucket = buckets.get(4);
bucket = buckets.get(8);
assertThat(bucket, notNullValue());
assertThat(((Number) bucket.getKey()).longValue(), equalTo(5l));
assertThat(((Number) bucket.getKey()).longValue(), equalTo(8l));
assertThat(bucket.getDocCount(), equalTo(0l));
docCountDeriv = bucket.getAggregations().get("deriv");
assertThat(docCountDeriv, notNullValue());
assertThat(docCountDeriv.value(), equalTo(0.25d));
assertThat(docCountDeriv.value(), equalTo(0d));
bucket = buckets.get(5);
bucket = buckets.get(9);
assertThat(bucket, notNullValue());
assertThat(((Number) bucket.getKey()).longValue(), equalTo(9l));
assertThat(bucket.getDocCount(), equalTo(0l));
assertThat(bucket.getDocCount(), equalTo(3l));
docCountDeriv = bucket.getAggregations().get("deriv");
assertThat(docCountDeriv, notNullValue());
assertThat(docCountDeriv.value(), equalTo(-1d));
assertThat(docCountDeriv.value(), equalTo(3d));
bucket = buckets.get(6);
bucket = buckets.get(10);
assertThat(bucket, notNullValue());
assertThat(((Number) bucket.getKey()).longValue(), equalTo(10l));
assertThat(bucket.getDocCount(), equalTo(0l));
assertThat(bucket.getDocCount(), equalTo(2l));
docCountDeriv = bucket.getAggregations().get("deriv");
assertThat(docCountDeriv, notNullValue());
assertThat(docCountDeriv.value(), equalTo(-1d));
bucket = buckets.get(11);
assertThat(bucket, notNullValue());
assertThat(((Number) bucket.getKey()).longValue(), equalTo(11l));
assertThat(bucket.getDocCount(), equalTo(1l));
docCountDeriv = bucket.getAggregations().get("deriv");
assertThat(docCountDeriv, notNullValue());
assertThat(docCountDeriv.value(), equalTo(-1d));