Add _bucket_count option to buckets_path

This change adds a new special path to the buckets_path syntax
`_bucket_count`. This new option will return the number of buckets for a
multi-bucket aggregation, which can then be used in pipeline
aggregations.

Closes #19553
This commit is contained in:
Colin Goodheart-Smithe 2016-07-25 10:19:15 +01:00
parent c7c0faa54d
commit 2c12c3e628
8 changed files with 64 additions and 19 deletions

View File

@ -43,7 +43,7 @@ public abstract class InternalMultiBucketAggregation<A extends InternalMultiBuck
/**
* Create a new copy of this {@link Aggregation} with the same settings as
* this {@link Aggregation} and contains the provided buckets.
*
*
* @param buckets
* the buckets to use in the new {@link Aggregation}
* @return the new {@link Aggregation}
@ -53,7 +53,7 @@ public abstract class InternalMultiBucketAggregation<A extends InternalMultiBuck
/**
* Create a new {@link InternalBucket} using the provided prototype bucket
* and aggregations.
*
*
* @param aggregations
* the aggregations for the new bucket
* @param prototype
@ -66,6 +66,8 @@ public abstract class InternalMultiBucketAggregation<A extends InternalMultiBuck
public Object getProperty(List<String> path) {
if (path.isEmpty()) {
return this;
} else if (path.get(0).equals("_bucket_count")) {
return getBuckets().size();
} else {
List<? extends Bucket> buckets = getBuckets();
Object[] propertyArray = new Object[buckets.size()];

View File

@ -380,6 +380,7 @@ public class DateHistogramIT extends ESIntegTestCase {
assertThat(histo.getName(), equalTo("histo"));
List<? extends Bucket> buckets = histo.getBuckets();
assertThat(buckets.size(), equalTo(3));
assertThat(histo.getProperty("_bucket_count"), equalTo(3));
Object[] propertiesKeys = (Object[]) histo.getProperty("_key");
Object[] propertiesDocCounts = (Object[]) histo.getProperty("_count");
Object[] propertiesCounts = (Object[]) histo.getProperty("sum.value");
@ -600,7 +601,7 @@ public class DateHistogramIT extends ESIntegTestCase {
assertThat(histo.getBuckets().size(), equalTo(4));
// TODO: use diamond once JI-9019884 is fixed
List<Histogram.Bucket> buckets = new ArrayList<Histogram.Bucket>(histo.getBuckets());
List<Histogram.Bucket> buckets = new ArrayList<>(histo.getBuckets());
Histogram.Bucket bucket = buckets.get(0);
assertThat(bucket, notNullValue());

View File

@ -137,7 +137,7 @@ public class DateRangeIT extends ESIntegTestCase {
assertThat(range.getBuckets().size(), equalTo(3));
// TODO: use diamond once JI-9019884 is fixed
List<Range.Bucket> buckets = new ArrayList<Range.Bucket>(range.getBuckets());
List<Range.Bucket> buckets = new ArrayList<>(range.getBuckets());
Range.Bucket bucket = buckets.get(0);
assertThat((String) bucket.getKey(), equalTo("a long time ago"));
@ -421,6 +421,7 @@ public class DateRangeIT extends ESIntegTestCase {
assertThat(range.getName(), equalTo("range"));
List<? extends Bucket> buckets = range.getBuckets();
assertThat(buckets.size(), equalTo(3));
assertThat(range.getProperty("_bucket_count"), equalTo(3));
Object[] propertiesKeys = (Object[]) range.getProperty("_key");
Object[] propertiesDocCounts = (Object[]) range.getProperty("_count");
Object[] propertiesCounts = (Object[]) range.getProperty("sum.value");
@ -855,7 +856,7 @@ public class DateRangeIT extends ESIntegTestCase {
Range dateRange = bucket.getAggregations().get("date_range");
// TODO: use diamond once JI-9019884 is fixed
List<Range.Bucket> buckets = new ArrayList<Range.Bucket>(dateRange.getBuckets());
List<Range.Bucket> buckets = new ArrayList<>(dateRange.getBuckets());
assertThat(dateRange, Matchers.notNullValue());
assertThat(dateRange.getName(), equalTo("date_range"));
assertThat(buckets.size(), is(1));

View File

@ -426,6 +426,7 @@ public class DoubleTermsIT extends AbstractTermsTestCase {
assertThat(terms, notNullValue());
assertThat(terms.getName(), equalTo("terms"));
assertThat(terms.getBuckets().size(), equalTo(5));
assertThat(terms.getProperty("_bucket_count"), equalTo(5));
Object[] propertiesKeys = (Object[]) terms.getProperty("_key");
Object[] propertiesDocCounts = (Object[]) terms.getProperty("_count");
Object[] propertiesCounts = (Object[]) terms.getProperty("sum.value");

View File

@ -172,6 +172,7 @@ public class FiltersIT extends ESIntegTestCase {
assertThat(filters.getName(), equalTo("tags"));
assertThat(filters.getBuckets().size(), equalTo(2));
assertThat(filters.getProperty("_bucket_count"), equalTo(2));
Object[] propertiesKeys = (Object[]) filters.getProperty("_key");
Object[] propertiesDocCounts = (Object[]) filters.getProperty("_count");
Object[] propertiesCounts = (Object[]) filters.getProperty("avg_value.value");
@ -426,6 +427,7 @@ public class FiltersIT extends ESIntegTestCase {
assertThat(filters.getName(), equalTo("tags"));
assertThat(filters.getBuckets().size(), equalTo(3));
assertThat(filters.getProperty("_bucket_count"), equalTo(3));
Object[] propertiesKeys = (Object[]) filters.getProperty("_key");
Object[] propertiesDocCounts = (Object[]) filters.getProperty("_count");
Object[] propertiesCounts = (Object[]) filters.getProperty("avg_value.value");

View File

@ -349,6 +349,7 @@ public class GeoDistanceIT extends ESIntegTestCase {
assertThat(geoDist.getName(), equalTo("amsterdam_rings"));
List<? extends Bucket> buckets = geoDist.getBuckets();
assertThat(geoDist.getBuckets().size(), equalTo(3));
assertThat(geoDist.getProperty("_bucket_count"), equalTo(3));
Object[] propertiesKeys = (Object[]) geoDist.getProperty("_key");
Object[] propertiesDocCounts = (Object[]) geoDist.getProperty("_count");
Object[] propertiesCities = (Object[]) geoDist.getProperty("cities");
@ -429,7 +430,7 @@ public class GeoDistanceIT extends ESIntegTestCase {
Range geoDistance = bucket.getAggregations().get("geo_dist");
// TODO: use diamond once JI-9019884 is fixed
List<Range.Bucket> buckets = new ArrayList<Range.Bucket>(geoDistance.getBuckets());
List<Range.Bucket> buckets = new ArrayList<>(geoDistance.getBuckets());
assertThat(geoDistance, Matchers.notNullValue());
assertThat(geoDistance.getName(), equalTo("geo_dist"));
assertThat(buckets.size(), is(1));

View File

@ -26,7 +26,6 @@ import org.elasticsearch.plugins.Plugin;
import org.elasticsearch.script.MockScriptPlugin;
import org.elasticsearch.script.Script;
import org.elasticsearch.script.ScriptService.ScriptType;
import org.elasticsearch.search.aggregations.AggregationTestScriptsPlugin;
import org.elasticsearch.search.aggregations.bucket.filter.Filter;
import org.elasticsearch.search.aggregations.bucket.histogram.ExtendedBounds;
import org.elasticsearch.search.aggregations.bucket.histogram.Histogram;
@ -253,7 +252,7 @@ public class HistogramIT extends ESIntegTestCase {
assertThat(histo.getBuckets().size(), equalTo(numValueBuckets));
// TODO: use diamond once JI-9019884 is fixed
List<Histogram.Bucket> buckets = new ArrayList<Histogram.Bucket>(histo.getBuckets());
List<Histogram.Bucket> buckets = new ArrayList<>(histo.getBuckets());
for (int i = 0; i < numValueBuckets; ++i) {
Histogram.Bucket bucket = buckets.get(i);
assertThat(bucket, notNullValue());
@ -276,7 +275,7 @@ public class HistogramIT extends ESIntegTestCase {
assertThat(histo.getBuckets().size(), equalTo(numValueBuckets));
// TODO: use diamond once JI-9019884 is fixed
List<Histogram.Bucket> buckets = new ArrayList<Histogram.Bucket>(histo.getBuckets());
List<Histogram.Bucket> buckets = new ArrayList<>(histo.getBuckets());
for (int i = 0; i < numValueBuckets; ++i) {
Histogram.Bucket bucket = buckets.get(numValueBuckets - i - 1);
assertThat(bucket, notNullValue());
@ -300,7 +299,7 @@ public class HistogramIT extends ESIntegTestCase {
LongHashSet buckets = new LongHashSet();
// TODO: use diamond once JI-9019884 is fixed
List<Histogram.Bucket> histoBuckets = new ArrayList<Histogram.Bucket>(histo.getBuckets());
List<Histogram.Bucket> histoBuckets = new ArrayList<>(histo.getBuckets());
long previousCount = Long.MIN_VALUE;
for (int i = 0; i < numValueBuckets; ++i) {
Histogram.Bucket bucket = histoBuckets.get(i);
@ -329,7 +328,7 @@ public class HistogramIT extends ESIntegTestCase {
LongHashSet buckets = new LongHashSet();
// TODO: use diamond once JI-9019884 is fixed
List<Histogram.Bucket> histoBuckets = new ArrayList<Histogram.Bucket>(histo.getBuckets());
List<Histogram.Bucket> histoBuckets = new ArrayList<>(histo.getBuckets());
long previousCount = Long.MAX_VALUE;
for (int i = 0; i < numValueBuckets; ++i) {
Histogram.Bucket bucket = histoBuckets.get(i);
@ -356,12 +355,13 @@ public class HistogramIT extends ESIntegTestCase {
assertThat(histo, notNullValue());
assertThat(histo.getName(), equalTo("histo"));
assertThat(histo.getBuckets().size(), equalTo(numValueBuckets));
assertThat(histo.getProperty("_bucket_count"), equalTo(numValueBuckets));
Object[] propertiesKeys = (Object[]) histo.getProperty("_key");
Object[] propertiesDocCounts = (Object[]) histo.getProperty("_count");
Object[] propertiesCounts = (Object[]) histo.getProperty("sum.value");
// TODO: use diamond once JI-9019884 is fixed
List<Histogram.Bucket> buckets = new ArrayList<Histogram.Bucket>(histo.getBuckets());
List<Histogram.Bucket> buckets = new ArrayList<>(histo.getBuckets());
for (int i = 0; i < numValueBuckets; ++i) {
Histogram.Bucket bucket = buckets.get(i);
assertThat(bucket, notNullValue());
@ -404,7 +404,7 @@ public class HistogramIT extends ESIntegTestCase {
LongHashSet visited = new LongHashSet();
double previousSum = Double.NEGATIVE_INFINITY;
// TODO: use diamond once JI-9019884 is fixed
List<Histogram.Bucket> buckets = new ArrayList<Histogram.Bucket>(histo.getBuckets());
List<Histogram.Bucket> buckets = new ArrayList<>(histo.getBuckets());
for (int i = 0; i < numValueBuckets; ++i) {
Histogram.Bucket bucket = buckets.get(i);
assertThat(bucket, notNullValue());
@ -448,7 +448,7 @@ public class HistogramIT extends ESIntegTestCase {
LongHashSet visited = new LongHashSet();
double previousSum = Double.POSITIVE_INFINITY;
// TODO: use diamond once JI-9019884 is fixed
List<Histogram.Bucket> buckets = new ArrayList<Histogram.Bucket>(histo.getBuckets());
List<Histogram.Bucket> buckets = new ArrayList<>(histo.getBuckets());
for (int i = 0; i < numValueBuckets; ++i) {
Histogram.Bucket bucket = buckets.get(i);
assertThat(bucket, notNullValue());
@ -492,7 +492,7 @@ public class HistogramIT extends ESIntegTestCase {
LongHashSet visited = new LongHashSet();
double previousSum = Double.POSITIVE_INFINITY;
// TODO: use diamond once JI-9019884 is fixed
List<Histogram.Bucket> buckets = new ArrayList<Histogram.Bucket>(histo.getBuckets());
List<Histogram.Bucket> buckets = new ArrayList<>(histo.getBuckets());
for (int i = 0; i < numValueBuckets; ++i) {
Histogram.Bucket bucket = buckets.get(i);
assertThat(bucket, notNullValue());
@ -538,7 +538,7 @@ public class HistogramIT extends ESIntegTestCase {
LongHashSet visited = new LongHashSet();
double prevMax = asc ? Double.NEGATIVE_INFINITY : Double.POSITIVE_INFINITY;
// TODO: use diamond once JI-9019884 is fixed
List<Histogram.Bucket> buckets = new ArrayList<Histogram.Bucket>(histo.getBuckets());
List<Histogram.Bucket> buckets = new ArrayList<>(histo.getBuckets());
for (int i = 0; i < numValueBuckets; ++i) {
Histogram.Bucket bucket = buckets.get(i);
assertThat(bucket, notNullValue());
@ -625,7 +625,7 @@ public class HistogramIT extends ESIntegTestCase {
assertThat(histo.getBuckets().size(), equalTo(numValuesBuckets));
// TODO: use diamond once JI-9019884 is fixed
List<Histogram.Bucket> buckets = new ArrayList<Histogram.Bucket>(histo.getBuckets());
List<Histogram.Bucket> buckets = new ArrayList<>(histo.getBuckets());
for (int i = 0; i < numValuesBuckets; ++i) {
Histogram.Bucket bucket = buckets.get(numValuesBuckets - i - 1);
assertThat(bucket, notNullValue());

View File

@ -107,8 +107,7 @@ a metric embedded inside a sibling aggregation:
=== Special Paths
Instead of pathing to a metric, `buckets_path` can use a special `"_count"` path. This instructs
the pipeline aggregation to use the document count as it's input. For example, a moving average can be calculated on the document
count of each bucket, instead of a specific metric:
the pipeline aggregation to use the document count as it's input. For example, a moving average can be calculated on the document count of each bucket, instead of a specific metric:
[source,js]
--------------------------------------------------
@ -128,6 +127,44 @@ count of each bucket, instead of a specific metric:
--------------------------------------------------
<1> By using `_count` instead of a metric name, we can calculate the moving average of document counts in the histogram
The `buckets_path` can also use `"_bucket_count"` and path to a multi-bucket aggregation to use the number of buckets
returned by that aggregation in the pipeline aggregation instead of a metric. for example a `bucket_selector` can be
used here to filter out buckets which contain no buckets for an inner terms aggregation:
[source,js]
--------------------------------------------------
{
"size": 0,
"aggs": {
"histo": {
"date_histogram": {
"field": "date",
"interval": "day"
},
"aggs": {
"categories": {
"terms": {
"field": "category"
}
},
"min_bucket_selector": {
"bucket_selector": {
"buckets_path": {
"count": "categories._bucket_count"
},
"script": {
"inline": "count != 0"
}
}
}
}
}
}
}
--------------------------------------------------
<1> By using `_bucket_count` instead of a metric name, we can filter out `histo` buckets where they contain no buckets
for the `categories` aggregation
[[dots-in-agg-names]]
[float]
=== Dealing with dots in agg names