Clean up how pipeline aggs check for multi-bucket (backport of #54161) (#54379)

Pipeline aggregations like `stats_bucket`, `sum_bucket`, and
`percentiles_bucket` only operate on buckets that have multiple buckets.
This adds support for those aggregations to `geo_distance`, `ip_range`,
`auto_date_histogram`, and `rare_terms`.

This all happened because we used a marker interface to mark compatible
aggs, `MultiBucketAggregationBuilder` and it was fairly easy to forget
to implement the interface.

This replaces the marker interface with an abstract method in
`AggregationBuilder`, `bucketCardinality` which makes you return `NONE`,
`ONE`, or `MANY`. The `bucket` aggregations can check for `MANY`. At
this point `ONE` and `NONE` amount to about the same thing, but I
suspect that'll be a useful distinction when validating bucket sorts.

Closes #53215
This commit is contained in:
Nik Everett 2020-03-30 10:44:55 -04:00 committed by GitHub
parent 39b3010578
commit e58ad9fed3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
45 changed files with 547 additions and 124 deletions

View File

@ -86,6 +86,11 @@ public class StringStatsAggregationBuilder extends ValuesSourceAggregationBuilde
throw new UnsupportedOperationException();
}
@Override
public BucketCardinality bucketCardinality() {
return BucketCardinality.NONE;
}
@Override
protected ValuesSourceAggregatorFactory<Bytes> innerBuild(QueryShardContext queryShardContext, ValuesSourceConfig<Bytes> config,
AggregatorFactory parent, Builder subFactoriesBuilder) throws IOException {

View File

@ -94,6 +94,11 @@ public class TopMetricsAggregationBuilder extends AbstractAggregationBuilder<Top
throw new UnsupportedOperationException();
}
@Override
public BucketCardinality bucketCardinality() {
return BucketCardinality.NONE;
}
@Override
protected AggregatorFactory doBuild(QueryShardContext queryShardContext, AggregatorFactory parent, Builder subfactoriesBuilder)
throws IOException {

View File

@ -38,7 +38,7 @@ import java.io.IOException;
import java.util.Map;
public class MatrixStatsAggregationBuilder
extends ArrayValuesSourceAggregationBuilder.LeafOnly<ValuesSource.Numeric, MatrixStatsAggregationBuilder> {
extends ArrayValuesSourceAggregationBuilder.LeafOnly<ValuesSource.Numeric, MatrixStatsAggregationBuilder> {
public static final String NAME = "matrix_stats";
private MultiValueMode multiValueMode = MultiValueMode.AVG;

View File

@ -84,6 +84,11 @@ public abstract class ArrayValuesSourceAggregationBuilder<VS extends ValuesSourc
throw new AggregationInitializationException("Aggregator [" + name + "] of type [" +
getType() + "] cannot accept sub-aggregations");
}
@Override
public final BucketCardinality bucketCardinality() {
return BucketCardinality.NONE;
}
}
private final ValuesSourceType valuesSourceType;

View File

@ -94,11 +94,16 @@ public class ChildrenAggregationBuilder
out.writeString(childType);
}
@Override
public BucketCardinality bucketCardinality() {
return BucketCardinality.ONE;
}
@Override
protected ValuesSourceAggregatorFactory<WithOrdinals> innerBuild(QueryShardContext queryShardContext,
ValuesSourceConfig<WithOrdinals> config,
AggregatorFactory parent,
Builder subFactoriesBuilder) throws IOException {
ValuesSourceConfig<WithOrdinals> config,
AggregatorFactory parent,
Builder subFactoriesBuilder) throws IOException {
return new ChildrenAggregatorFactory(name, config, childFilter, parentFilter, queryShardContext, parent,
subFactoriesBuilder, metaData);
}

View File

@ -94,11 +94,16 @@ public class ParentAggregationBuilder
out.writeString(childType);
}
@Override
public BucketCardinality bucketCardinality() {
return BucketCardinality.ONE;
}
@Override
protected ValuesSourceAggregatorFactory<WithOrdinals> innerBuild(QueryShardContext queryShardContext,
ValuesSourceConfig<WithOrdinals> config,
AggregatorFactory parent,
Builder subFactoriesBuilder) throws IOException {
ValuesSourceConfig<WithOrdinals> config,
AggregatorFactory parent,
Builder subFactoriesBuilder) throws IOException {
return new ParentAggregatorFactory(name, config, childFilter, parentFilter, queryShardContext, parent,
subFactoriesBuilder, metaData);
}

View File

@ -360,3 +360,64 @@ setup:
- is_false: aggregations.str_terms.buckets.0.key_as_string
- match: { aggregations.str_terms.buckets.0.doc_count: 1 }
- match: { aggregations.str_terms.buckets.0.max_n.value: 3.0 }
---
"avg_bucket":
- skip:
version: " - 7.7.99"
reason: Fixed in 7.8.0
- do:
indices.create:
index: test
body:
settings:
number_of_replicas: 0
mappings:
properties:
str:
type: keyword
- do:
bulk:
index: test
refresh: true
body:
- '{"index": {}}'
- '{"str": "foo", "v": 1}'
- '{"index": {}}'
- '{"str": "foo", "v": 2}'
- '{"index": {}}'
- '{"str": "foo", "v": 3}'
- '{"index": {}}'
- '{"str": "bar", "v": 4}'
- '{"index": {}}'
- '{"str": "bar", "v": 5}'
- '{"index": {}}'
- '{"str": "baz", "v": 6}'
- do:
search:
index: test
body:
size: 0
aggs:
str_terms:
rare_terms:
field: str
max_doc_count: 2
aggs:
v:
sum:
field: v
str_terms_avg_v:
avg_bucket:
buckets_path: str_terms.v
- match: { hits.total.value: 6 }
- length: { aggregations.str_terms.buckets: 2 }
- match: { aggregations.str_terms.buckets.0.key: baz }
- match: { aggregations.str_terms.buckets.0.doc_count: 1 }
- match: { aggregations.str_terms.buckets.0.v.value: 6 }
- match: { aggregations.str_terms.buckets.1.key: bar }
- match: { aggregations.str_terms.buckets.1.doc_count: 2 }
- match: { aggregations.str_terms.buckets.1.v.value: 9 }
- match: { aggregations.str_terms_avg_v.value: 7.5 }

View File

@ -0,0 +1,76 @@
setup:
- do:
indices.create:
index: test
body:
settings:
number_of_replicas: 0
mappings:
properties:
date:
type: date
- do:
bulk:
refresh: true
index: test
body:
- '{"index": {}}'
- '{"date": "2020-03-01", "v": 1}'
- '{"index": {}}'
- '{"date": "2020-03-02", "v": 2}'
- '{"index": {}}'
- '{"date": "2020-03-08", "v": 3}'
- '{"index": {}}'
- '{"date": "2020-03-09", "v": 4}'
---
"basic":
- skip:
version: " - 7.7.99"
reason: Tracked in https://github.com/elastic/elasticsearch/issues/54382
- do:
search:
body:
size: 0
aggs:
histo:
auto_date_histogram:
field: date
buckets: 2
- match: { hits.total.value: 4 }
- length: { aggregations.histo.buckets: 2 }
- match: { aggregations.histo.buckets.0.key_as_string: "2020-03-01T00:00:00.000Z" }
- match: { aggregations.histo.buckets.0.doc_count: 2 }
- match: { aggregations.histo.buckets.1.key_as_string: "2020-03-08T00:00:00.000Z" }
- match: { aggregations.histo.buckets.1.doc_count: 2 }
---
"avg_bucket":
- skip:
version: " - 7.7.99"
reason: Fixed in 7.8.0
- do:
search:
body:
size: 0
aggs:
histo:
auto_date_histogram:
field: date
buckets: 2
aggs:
v:
sum:
field: v
histo_avg_v:
avg_bucket:
buckets_path: histo.v
- match: { hits.total.value: 4 }
- length: { aggregations.histo.buckets: 2 }
- match: { aggregations.histo.buckets.0.key_as_string: "2020-03-01T00:00:00.000Z" }
- match: { aggregations.histo.buckets.0.doc_count: 2 }
- match: { aggregations.histo.buckets.0.v.value: 3 }
- match: { aggregations.histo.buckets.1.key_as_string: "2020-03-08T00:00:00.000Z" }
- match: { aggregations.histo.buckets.1.doc_count: 2 }
- match: { aggregations.histo.buckets.1.v.value: 7 }
- match: { aggregations.histo_avg_v.value: 5 }

View File

@ -0,0 +1,85 @@
setup:
- do:
indices.create:
index: test
body:
mappings:
properties:
location:
type: geo_point
- do:
bulk:
index: test
refresh: true
body:
- '{"index": {}}'
- '{"location": {"lat" : 40.7128, "lon" : -74.0060}, "name": "New York", "population": 8623000}'
- '{"index": {}}'
- '{"location": {"lat" : 34.0522, "lon" : -118.2437}, "name": "Los Angeles", "population": 4000000}'
- '{"index": {}}'
- '{"location": {"lat" : 41.8781, "lon" : -87.6298}, "name": "Chicago", "population": 2716000}'
---
"basic":
- do:
search:
rest_total_hits_as_int: true
body:
size: 0
aggs:
distance:
geo_distance:
field: location
origin: "35.7796, -78.6382"
ranges:
- to: 1000000
- from: 1000000
to: 5000000
- from: 5000000
- match: { hits.total: 3 }
- length: { aggregations.distance.buckets: 3 }
- match: { aggregations.distance.buckets.0.key: "*-1000000.0" }
- match: { aggregations.distance.buckets.0.doc_count: 1 }
- match: { aggregations.distance.buckets.1.key: "1000000.0-5000000.0" }
- match: { aggregations.distance.buckets.1.doc_count: 2 }
- match: { aggregations.distance.buckets.2.key: "5000000.0-*" }
- match: { aggregations.distance.buckets.2.doc_count: 0 }
---
"avg_bucket":
- skip:
version: " - 7.7.99"
reason: Fixed in 7.8.0
- do:
search:
body:
size: 0
aggs:
distance:
geo_distance:
field: location
origin: "35.7796, -78.6382"
ranges:
- to: 1000000
- from: 1000000
to: 5000000
- from: 5000000
aggs:
total_population:
sum:
field: population
avg_total_population:
avg_bucket:
buckets_path: distance.total_population
- match: { hits.total.value: 3 }
- length: { aggregations.distance.buckets: 3 }
- match: { aggregations.distance.buckets.0.key: "*-1000000.0" }
- match: { aggregations.distance.buckets.0.doc_count: 1 }
- match: { aggregations.distance.buckets.0.total_population.value: 8623000.0 }
- match: { aggregations.distance.buckets.1.key: "1000000.0-5000000.0" }
- match: { aggregations.distance.buckets.1.doc_count: 2 }
- match: { aggregations.distance.buckets.1.total_population.value: 6716000.0 }
- match: { aggregations.distance.buckets.2.key: "5000000.0-*" }
- match: { aggregations.distance.buckets.2.doc_count: 0 }
- match: { aggregations.distance.buckets.2.total_population.value: 0 }
- match: { aggregations.avg_total_population.value: 7669500.0 }

View File

@ -224,6 +224,58 @@ setup:
- match: { aggregations.ip_range.buckets.1.key: "192.168.0.0-192.169.0.0" }
- match: { aggregations.ip_range.buckets.2.key: "192.169.0.0-*" }
---
"IP Range avg_bucket":
- skip:
version: " - 7.7.99"
reason: Fixed in 7.8.0
- do:
bulk:
refresh: true
index: test
body:
- '{"index": {}}'
- '{"ip": "::1", "v": 1}'
- '{"index": {}}'
- '{"ip": "192.168.0.1", "v": 2}'
- '{"index": {}}'
- '{"ip": "192.168.0.7", "v": 3}'
- do:
search:
index: test
body:
size: 0
aggs:
range:
ip_range:
field: ip
ranges:
- to: 192.168.0.0
- from: 192.168.0.0
to: 192.169.0.0
- from: 192.169.0.0
aggs:
v:
sum:
field: v
range_avg_v:
avg_bucket:
buckets_path: range.v
- match: { hits.total.value: 3 }
- length: { aggregations.range.buckets: 3 }
- match: { aggregations.range.buckets.0.key: "*-192.168.0.0" }
- match: { aggregations.range.buckets.0.doc_count: 1 }
- match: { aggregations.range.buckets.0.v.value: 1 }
- match: { aggregations.range.buckets.1.key: "192.168.0.0-192.169.0.0" }
- match: { aggregations.range.buckets.1.doc_count: 2 }
- match: { aggregations.range.buckets.1.v.value: 5 }
- match: { aggregations.range.buckets.2.key: "192.169.0.0-*" }
- match: { aggregations.range.buckets.2.doc_count: 0 }
- match: { aggregations.range.buckets.2.v.value: 0 }
- match: { aggregations.range_avg_v.value: 3 }
---
"Date range":
- do:

View File

@ -154,6 +154,19 @@ public abstract class AggregationBuilder
return factoriesBuilder.buildPipelineTree();
}
/**
* Rough measure of how many buckets this aggregation can return. Just
* "zero", "one", and "many".
*/
public enum BucketCardinality {
NONE, ONE, MANY;
}
/**
* Do aggregations built by this builder contain buckets? If so, do they
* contain *always* contain a single bucket?
*/
public abstract BucketCardinality bucketCardinality();
/** Common xcontent fields shared among aggregator builders */
public static final class CommonFields extends ParseField.CommonFields {
public static final ParseField VALUE_TYPE = new ParseField("value_type");

View File

@ -1,30 +0,0 @@
/*
* 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.bucket;
import org.elasticsearch.search.aggregations.AggregationBuilder;
/**
* Marker interface to indicate that the {@link AggregationBuilder} is for a
* multi-bucket aggregation.
*/
public interface MultiBucketAggregationBuilder {
}

View File

@ -33,7 +33,6 @@ import org.elasticsearch.search.aggregations.AbstractAggregationBuilder;
import org.elasticsearch.search.aggregations.AggregationBuilder;
import org.elasticsearch.search.aggregations.AggregatorFactories.Builder;
import org.elasticsearch.search.aggregations.AggregatorFactory;
import org.elasticsearch.search.aggregations.bucket.MultiBucketAggregationBuilder;
import org.elasticsearch.search.aggregations.bucket.adjacency.AdjacencyMatrixAggregator.KeyedFilter;
import java.io.IOException;
@ -46,8 +45,7 @@ import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
public class AdjacencyMatrixAggregationBuilder extends AbstractAggregationBuilder<AdjacencyMatrixAggregationBuilder>
implements MultiBucketAggregationBuilder {
public class AdjacencyMatrixAggregationBuilder extends AbstractAggregationBuilder<AdjacencyMatrixAggregationBuilder> {
public static final String NAME = "adjacency_matrix";
private static final String DEFAULT_SEPARATOR = "&";
@ -215,6 +213,11 @@ public class AdjacencyMatrixAggregationBuilder extends AbstractAggregationBuilde
subFactoriesBuilder, metaData);
}
@Override
public BucketCardinality bucketCardinality() {
return BucketCardinality.MANY;
}
@Override
protected XContentBuilder internalXContent(XContentBuilder builder, Params params) throws IOException {
builder.startObject();

View File

@ -147,6 +147,16 @@ public class CompositeAggregationBuilder extends AbstractAggregationBuilder<Comp
return size;
}
@Override
public BucketCardinality bucketCardinality() {
/*
* Cardinality *does* have buckets so MULTI might be appropriate here.
* But the buckets can't be used with the composite agg so we're
* going to pretend that it doesn't have buckets.
*/
return BucketCardinality.NONE;
}
/**
* Returns null if the provided factory and his parents are compatible with
* this aggregator or the instance of the parent's factory that is incompatible with

View File

@ -83,6 +83,11 @@ public class FilterAggregationBuilder extends AbstractAggregationBuilder<FilterA
out.writeNamedWriteable(filter);
}
@Override
public BucketCardinality bucketCardinality() {
return BucketCardinality.ONE;
}
@Override
protected AggregationBuilder doRewrite(QueryRewriteContext queryShardContext) throws IOException {
QueryBuilder result = Rewriteable.rewrite(filter, queryShardContext);

View File

@ -33,7 +33,6 @@ import org.elasticsearch.search.aggregations.AbstractAggregationBuilder;
import org.elasticsearch.search.aggregations.AggregationBuilder;
import org.elasticsearch.search.aggregations.AggregatorFactories.Builder;
import org.elasticsearch.search.aggregations.AggregatorFactory;
import org.elasticsearch.search.aggregations.bucket.MultiBucketAggregationBuilder;
import org.elasticsearch.search.aggregations.bucket.filter.FiltersAggregator.KeyedFilter;
import java.io.IOException;
@ -47,8 +46,7 @@ import java.util.Objects;
import static org.elasticsearch.index.query.AbstractQueryBuilder.parseInnerQueryBuilder;
public class FiltersAggregationBuilder extends AbstractAggregationBuilder<FiltersAggregationBuilder>
implements MultiBucketAggregationBuilder {
public class FiltersAggregationBuilder extends AbstractAggregationBuilder<FiltersAggregationBuilder> {
public static final String NAME = "filters";
private static final ParseField FILTERS_FIELD = new ParseField("filters");
@ -198,6 +196,11 @@ public class FiltersAggregationBuilder extends AbstractAggregationBuilder<Filter
return otherBucketKey;
}
@Override
public BucketCardinality bucketCardinality() {
return BucketCardinality.MANY;
}
@Override
protected AggregationBuilder doRewrite(QueryRewriteContext queryShardContext) throws IOException {
List<KeyedFilter> rewrittenFilters = new ArrayList<>(filters.size());

View File

@ -19,11 +19,6 @@
package org.elasticsearch.search.aggregations.bucket.geogrid;
import java.io.IOException;
import java.util.Map;
import java.util.Objects;
import java.util.function.Function;
import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.Version;
import org.elasticsearch.common.ParseField;
@ -38,7 +33,6 @@ import org.elasticsearch.index.query.QueryShardContext;
import org.elasticsearch.search.aggregations.AggregatorFactories.Builder;
import org.elasticsearch.search.aggregations.AggregatorFactory;
import org.elasticsearch.search.aggregations.bucket.BucketUtils;
import org.elasticsearch.search.aggregations.bucket.MultiBucketAggregationBuilder;
import org.elasticsearch.search.aggregations.support.CoreValuesSourceType;
import org.elasticsearch.search.aggregations.support.ValueType;
import org.elasticsearch.search.aggregations.support.ValuesSource;
@ -47,8 +41,12 @@ import org.elasticsearch.search.aggregations.support.ValuesSourceAggregatorFacto
import org.elasticsearch.search.aggregations.support.ValuesSourceConfig;
import org.elasticsearch.search.aggregations.support.ValuesSourceParserHelper;
public abstract class GeoGridAggregationBuilder extends ValuesSourceAggregationBuilder<ValuesSource.GeoPoint, GeoGridAggregationBuilder>
implements MultiBucketAggregationBuilder {
import java.io.IOException;
import java.util.Map;
import java.util.Objects;
import java.util.function.Function;
public abstract class GeoGridAggregationBuilder extends ValuesSourceAggregationBuilder<ValuesSource.GeoPoint, GeoGridAggregationBuilder> {
/* recognized field names in JSON */
static final ParseField FIELD_PRECISION = new ParseField("precision");
static final ParseField FIELD_SIZE = new ParseField("size");
@ -171,11 +169,15 @@ public abstract class GeoGridAggregationBuilder extends ValuesSourceAggregationB
return geoBoundingBox;
}
@Override
public final BucketCardinality bucketCardinality() {
return BucketCardinality.MANY;
}
@Override
protected ValuesSourceAggregatorFactory<ValuesSource.GeoPoint> innerBuild(QueryShardContext queryShardContext,
ValuesSourceConfig<ValuesSource.GeoPoint> config,
AggregatorFactory parent, Builder subFactoriesBuilder)
throws IOException {
ValuesSourceConfig<ValuesSource.GeoPoint> config,
AggregatorFactory parent, Builder subFactoriesBuilder) throws IOException {
int shardSize = this.shardSize;
int requiredSize = this.requiredSize;

View File

@ -19,9 +19,6 @@
package org.elasticsearch.search.aggregations.bucket.geogrid;
import java.io.IOException;
import java.util.Map;
import org.elasticsearch.common.geo.GeoBoundingBox;
import org.elasticsearch.common.geo.GeoUtils;
import org.elasticsearch.common.io.stream.StreamInput;
@ -34,6 +31,9 @@ import org.elasticsearch.search.aggregations.support.ValuesSource;
import org.elasticsearch.search.aggregations.support.ValuesSourceAggregatorFactory;
import org.elasticsearch.search.aggregations.support.ValuesSourceConfig;
import java.io.IOException;
import java.util.Map;
public class GeoHashGridAggregationBuilder extends GeoGridAggregationBuilder {
public static final String NAME = "geohash_grid";
public static final int DEFAULT_PRECISION = 5;

View File

@ -65,6 +65,11 @@ public class GlobalAggregationBuilder extends AbstractAggregationBuilder<GlobalA
// Nothing to write
}
@Override
public BucketCardinality bucketCardinality() {
return BucketCardinality.ONE;
}
@Override
protected AggregatorFactory doBuild(QueryShardContext queryShardContext, AggregatorFactory parent, Builder subFactoriesBuilder)
throws IOException {

View File

@ -178,9 +178,14 @@ public class AutoDateHistogramAggregationBuilder
return numBuckets;
}
@Override
public BucketCardinality bucketCardinality() {
return BucketCardinality.MANY;
}
@Override
protected ValuesSourceAggregatorFactory<Numeric> innerBuild(QueryShardContext queryShardContext, ValuesSourceConfig<Numeric> config,
AggregatorFactory parent, Builder subFactoriesBuilder) throws IOException {
AggregatorFactory parent, Builder subFactoriesBuilder) throws IOException {
RoundingInfo[] roundings = buildRoundings(timeZone(), getMinimumIntervalExpression());
int maxRoundingInterval = Arrays.stream(roundings,0, roundings.length-1)
.map(rounding -> rounding.innerIntervals)

View File

@ -43,7 +43,6 @@ import org.elasticsearch.search.aggregations.AggregatorFactory;
import org.elasticsearch.search.aggregations.BucketOrder;
import org.elasticsearch.search.aggregations.InternalOrder;
import org.elasticsearch.search.aggregations.InternalOrder.CompoundOrder;
import org.elasticsearch.search.aggregations.bucket.MultiBucketAggregationBuilder;
import org.elasticsearch.search.aggregations.support.CoreValuesSourceType;
import org.elasticsearch.search.aggregations.support.ValueType;
import org.elasticsearch.search.aggregations.support.ValuesSource;
@ -69,8 +68,7 @@ import static java.util.Collections.unmodifiableMap;
* A builder for histograms on date fields.
*/
public class DateHistogramAggregationBuilder extends ValuesSourceAggregationBuilder<ValuesSource, DateHistogramAggregationBuilder>
implements MultiBucketAggregationBuilder, DateIntervalConsumer {
implements DateIntervalConsumer {
public static final String NAME = "date_histogram";
public static final Map<String, Rounding.DateTimeUnit> DATE_FIELD_UNITS;
@ -376,6 +374,11 @@ public class DateHistogramAggregationBuilder extends ValuesSourceAggregationBuil
return this;
}
@Override
public BucketCardinality bucketCardinality() {
return BucketCardinality.MANY;
}
@Override
protected XContentBuilder doXContentBody(XContentBuilder builder, Params params) throws IOException {

View File

@ -19,11 +19,6 @@
package org.elasticsearch.search.aggregations.bucket.histogram;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import org.elasticsearch.common.ParseField;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput;
@ -37,7 +32,6 @@ import org.elasticsearch.search.aggregations.AggregatorFactory;
import org.elasticsearch.search.aggregations.BucketOrder;
import org.elasticsearch.search.aggregations.InternalOrder;
import org.elasticsearch.search.aggregations.InternalOrder.CompoundOrder;
import org.elasticsearch.search.aggregations.bucket.MultiBucketAggregationBuilder;
import org.elasticsearch.search.aggregations.support.CoreValuesSourceType;
import org.elasticsearch.search.aggregations.support.ValueType;
import org.elasticsearch.search.aggregations.support.ValuesSource;
@ -47,12 +41,16 @@ import org.elasticsearch.search.aggregations.support.ValuesSourceConfig;
import org.elasticsearch.search.aggregations.support.ValuesSourceParserHelper;
import org.elasticsearch.search.aggregations.support.ValuesSourceType;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.Objects;
/**
* A builder for histograms on numeric fields. This builder can operate on either base numeric fields, or numeric range fields. IP range
* fields are unsupported, and will throw at the factory layer.
*/
public class HistogramAggregationBuilder extends ValuesSourceAggregationBuilder<ValuesSource, HistogramAggregationBuilder>
implements MultiBucketAggregationBuilder {
public class HistogramAggregationBuilder extends ValuesSourceAggregationBuilder<ValuesSource, HistogramAggregationBuilder> {
public static final String NAME = "histogram";
private static final ObjectParser<double[], Void> EXTENDED_BOUNDS_PARSER = new ObjectParser<>(
@ -263,6 +261,11 @@ public class HistogramAggregationBuilder extends ValuesSourceAggregationBuilder<
return this;
}
@Override
public BucketCardinality bucketCardinality() {
return BucketCardinality.MANY;
}
@Override
protected XContentBuilder doXContentBody(XContentBuilder builder, Params params) throws IOException {

View File

@ -78,11 +78,16 @@ public class MissingAggregationBuilder extends ValuesSourceAggregationBuilder<Va
return true;
}
@Override
public BucketCardinality bucketCardinality() {
return BucketCardinality.ONE;
}
@Override
protected ValuesSourceAggregatorFactory<ValuesSource> innerBuild(QueryShardContext queryShardContext,
ValuesSourceConfig<ValuesSource> config,
AggregatorFactory parent,
Builder subFactoriesBuilder) throws IOException {
ValuesSourceConfig<ValuesSource> config,
AggregatorFactory parent,
Builder subFactoriesBuilder) throws IOException {
return new MissingAggregatorFactory(name, config, queryShardContext, parent, subFactoriesBuilder, metaData);
}

View File

@ -86,6 +86,11 @@ public class NestedAggregationBuilder extends AbstractAggregationBuilder<NestedA
return path;
}
@Override
public BucketCardinality bucketCardinality() {
return BucketCardinality.ONE;
}
@Override
protected AggregatorFactory doBuild(QueryShardContext queryShardContext,
AggregatorFactory parent,

View File

@ -90,6 +90,11 @@ public class ReverseNestedAggregationBuilder extends AbstractAggregationBuilder<
return path;
}
@Override
public BucketCardinality bucketCardinality() {
return BucketCardinality.ONE;
}
@Override
protected AggregatorFactory doBuild(QueryShardContext queryShardContext, AggregatorFactory parent, Builder subFactoriesBuilder)
throws IOException {

View File

@ -25,7 +25,6 @@ import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.common.io.stream.Writeable;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.search.aggregations.AggregatorFactories;
import org.elasticsearch.search.aggregations.bucket.MultiBucketAggregationBuilder;
import org.elasticsearch.search.aggregations.bucket.range.RangeAggregator.Range;
import org.elasticsearch.search.aggregations.support.ValuesSource;
import org.elasticsearch.search.aggregations.support.ValuesSourceAggregationBuilder;
@ -38,8 +37,7 @@ import java.util.Objects;
import java.util.function.Function;
public abstract class AbstractRangeBuilder<AB extends AbstractRangeBuilder<AB, R>, R extends Range>
extends ValuesSourceAggregationBuilder<ValuesSource.Numeric, AB> implements MultiBucketAggregationBuilder {
extends ValuesSourceAggregationBuilder<ValuesSource.Numeric, AB> {
protected final InternalRange.Factory<?, ?> rangeFactory;
protected List<R> ranges = new ArrayList<>();
protected boolean keyed = false;
@ -132,6 +130,11 @@ public abstract class AbstractRangeBuilder<AB extends AbstractRangeBuilder<AB, R
return keyed;
}
@Override
public BucketCardinality bucketCardinality() {
return BucketCardinality.MANY;
}
@Override
protected XContentBuilder doXContentBody(XContentBuilder builder, Params params) throws IOException {
builder.field(RangeAggregator.RANGES_FIELD.getPreferredName(), ranges);

View File

@ -410,11 +410,16 @@ public class GeoDistanceAggregationBuilder extends ValuesSourceAggregationBuilde
return keyed;
}
@Override
public BucketCardinality bucketCardinality() {
return BucketCardinality.MANY;
}
@Override
protected ValuesSourceAggregatorFactory<ValuesSource.GeoPoint> innerBuild(QueryShardContext queryShardContext,
ValuesSourceConfig<ValuesSource.GeoPoint> config,
AggregatorFactory parent,
Builder subFactoriesBuilder) throws IOException {
ValuesSourceConfig<ValuesSource.GeoPoint> config,
AggregatorFactory parent,
Builder subFactoriesBuilder) throws IOException {
Range[] ranges = this.ranges.toArray(new Range[this.range().size()]);
if (ranges.length == 0) {
throw new IllegalArgumentException("No [ranges] specified for the [" + this.getName() + "] aggregation");

View File

@ -18,15 +18,6 @@
*/
package org.elasticsearch.search.aggregations.bucket.range;
import java.io.IOException;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import org.apache.lucene.document.InetAddressPoint;
import org.apache.lucene.util.BytesRef;
import org.elasticsearch.common.ParseField;
@ -53,6 +44,15 @@ import org.elasticsearch.search.aggregations.support.ValuesSourceAggregatorFacto
import org.elasticsearch.search.aggregations.support.ValuesSourceConfig;
import org.elasticsearch.search.aggregations.support.ValuesSourceParserHelper;
import java.io.IOException;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
public final class IpRangeAggregationBuilder
extends ValuesSourceAggregationBuilder<ValuesSource.Bytes, IpRangeAggregationBuilder> {
@ -359,11 +359,15 @@ public final class IpRangeAggregationBuilder
return new BytesRef(bytes);
}
@Override
public BucketCardinality bucketCardinality() {
return BucketCardinality.MANY;
}
@Override
protected ValuesSourceAggregatorFactory<ValuesSource.Bytes> innerBuild(
QueryShardContext queryShardContext, ValuesSourceConfig<ValuesSource.Bytes> config,
AggregatorFactory parent, Builder subFactoriesBuilder)
throws IOException {
QueryShardContext queryShardContext, ValuesSourceConfig<ValuesSource.Bytes> config,
AggregatorFactory parent, Builder subFactoriesBuilder) throws IOException {
List<BinaryRangeAggregator.Range> ranges = new ArrayList<>();
if(this.ranges.size() == 0){
throw new IllegalArgumentException("No [ranges] specified for the [" + this.getName() + "] aggregation");

View File

@ -142,11 +142,16 @@ public class DiversifiedAggregationBuilder extends ValuesSourceAggregationBuilde
return executionHint;
}
@Override
public BucketCardinality bucketCardinality() {
return BucketCardinality.ONE;
}
@Override
protected ValuesSourceAggregatorFactory<ValuesSource> innerBuild(QueryShardContext queryShardContext,
ValuesSourceConfig<ValuesSource> config,
AggregatorFactory parent,
Builder subFactoriesBuilder) throws IOException {
ValuesSourceConfig<ValuesSource> config,
AggregatorFactory parent,
Builder subFactoriesBuilder) throws IOException {
return new DiversifiedAggregatorFactory(name, config, shardSize, maxDocsPerValue, executionHint, queryShardContext, parent,
subFactoriesBuilder, metaData);
}

View File

@ -83,6 +83,11 @@ public class SamplerAggregationBuilder extends AbstractAggregationBuilder<Sample
return shardSize;
}
@Override
public BucketCardinality bucketCardinality() {
return BucketCardinality.ONE;
}
@Override
protected SamplerAggregatorFactory doBuild(QueryShardContext queryShardContext, AggregatorFactory parent, Builder subFactoriesBuilder)
throws IOException {

View File

@ -31,7 +31,6 @@ import org.elasticsearch.index.query.QueryShardContext;
import org.elasticsearch.search.aggregations.AggregationBuilder;
import org.elasticsearch.search.aggregations.AggregatorFactories.Builder;
import org.elasticsearch.search.aggregations.AggregatorFactory;
import org.elasticsearch.search.aggregations.bucket.MultiBucketAggregationBuilder;
import org.elasticsearch.search.aggregations.bucket.significant.heuristics.JLHScore;
import org.elasticsearch.search.aggregations.bucket.significant.heuristics.SignificanceHeuristic;
import org.elasticsearch.search.aggregations.bucket.terms.IncludeExclude;
@ -52,8 +51,7 @@ import java.util.Objects;
import static org.elasticsearch.index.query.AbstractQueryBuilder.parseInnerQueryBuilder;
public class SignificantTermsAggregationBuilder extends ValuesSourceAggregationBuilder<ValuesSource, SignificantTermsAggregationBuilder>
implements MultiBucketAggregationBuilder {
public class SignificantTermsAggregationBuilder extends ValuesSourceAggregationBuilder<ValuesSource, SignificantTermsAggregationBuilder> {
public static final String NAME = "significant_terms";
static final ParseField BACKGROUND_FILTER = new ParseField("background_filter");
@ -282,11 +280,16 @@ public class SignificantTermsAggregationBuilder extends ValuesSourceAggregationB
return significanceHeuristic;
}
@Override
public BucketCardinality bucketCardinality() {
return BucketCardinality.MANY;
}
@Override
protected ValuesSourceAggregatorFactory<ValuesSource> innerBuild(QueryShardContext queryShardContext,
ValuesSourceConfig<ValuesSource> config,
AggregatorFactory parent,
Builder subFactoriesBuilder) throws IOException {
ValuesSourceConfig<ValuesSource> config,
AggregatorFactory parent,
Builder subFactoriesBuilder) throws IOException {
SignificanceHeuristic executionHeuristic = this.significanceHeuristic.rewrite(queryShardContext);
return new SignificantTermsAggregatorFactory(name, config, includeExclude, executionHint, filterBuilder,
bucketCountThresholds, executionHeuristic, queryShardContext, parent, subFactoriesBuilder, metaData);

View File

@ -321,6 +321,11 @@ public class SignificantTextAggregationBuilder extends AbstractAggregationBuilde
out.writeOptionalStringArray(sourceFieldNames);
}
@Override
public BucketCardinality bucketCardinality() {
return BucketCardinality.MANY;
}
@Override
protected AggregatorFactory doBuild(QueryShardContext queryShardContext, AggregatorFactory parent,
Builder subFactoriesBuilder) throws IOException {

View File

@ -156,11 +156,16 @@ public class RareTermsAggregationBuilder extends ValuesSourceAggregationBuilder<
this.precision = precision;
}
@Override
public BucketCardinality bucketCardinality() {
return BucketCardinality.MANY;
}
@Override
protected ValuesSourceAggregatorFactory<ValuesSource> innerBuild(QueryShardContext queryShardContext,
ValuesSourceConfig<ValuesSource> config,
AggregatorFactory parent,
Builder subFactoriesBuilder) throws IOException {
ValuesSourceConfig<ValuesSource> config,
AggregatorFactory parent,
Builder subFactoriesBuilder) throws IOException {
return new RareTermsAggregatorFactory(name, config, includeExclude,
queryShardContext, parent, subFactoriesBuilder, metaData, maxDocCount, precision);
}

View File

@ -34,7 +34,6 @@ import org.elasticsearch.search.aggregations.AggregatorFactory;
import org.elasticsearch.search.aggregations.BucketOrder;
import org.elasticsearch.search.aggregations.InternalOrder;
import org.elasticsearch.search.aggregations.InternalOrder.CompoundOrder;
import org.elasticsearch.search.aggregations.bucket.MultiBucketAggregationBuilder;
import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregator.BucketCountThresholds;
import org.elasticsearch.search.aggregations.support.CoreValuesSourceType;
import org.elasticsearch.search.aggregations.support.ValueType;
@ -49,8 +48,7 @@ import java.util.List;
import java.util.Map;
import java.util.Objects;
public class TermsAggregationBuilder extends ValuesSourceAggregationBuilder<ValuesSource, TermsAggregationBuilder>
implements MultiBucketAggregationBuilder {
public class TermsAggregationBuilder extends ValuesSourceAggregationBuilder<ValuesSource, TermsAggregationBuilder> {
public static final String NAME = "terms";
public static final ParseField EXECUTION_HINT_FIELD_NAME = new ParseField("execution_hint");
@ -329,11 +327,16 @@ public class TermsAggregationBuilder extends ValuesSourceAggregationBuilder<Valu
return this;
}
@Override
public BucketCardinality bucketCardinality() {
return BucketCardinality.MANY;
}
@Override
protected ValuesSourceAggregatorFactory<ValuesSource> innerBuild(QueryShardContext queryShardContext,
ValuesSourceConfig<ValuesSource> config,
AggregatorFactory parent,
Builder subFactoriesBuilder) throws IOException {
ValuesSourceConfig<ValuesSource> config,
AggregatorFactory parent,
Builder subFactoriesBuilder) throws IOException {
return new TermsAggregatorFactory(name, config, order, includeExclude, executionHint, collectMode,
bucketCountThresholds, showTermDocCountError, queryShardContext, parent, subFactoriesBuilder, metaData);
}

View File

@ -19,10 +19,6 @@
package org.elasticsearch.search.aggregations.metrics;
import java.io.IOException;
import java.util.Map;
import java.util.Objects;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.common.xcontent.ObjectParser;
@ -38,6 +34,10 @@ import org.elasticsearch.search.aggregations.support.ValuesSourceAggregationBuil
import org.elasticsearch.search.aggregations.support.ValuesSourceConfig;
import org.elasticsearch.search.aggregations.support.ValuesSourceParserHelper;
import java.io.IOException;
import java.util.Map;
import java.util.Objects;
public class GeoBoundsAggregationBuilder extends ValuesSourceAggregationBuilder<ValuesSource.GeoPoint, GeoBoundsAggregationBuilder> {
public static final String NAME = "geo_bounds";
@ -92,6 +92,11 @@ public class GeoBoundsAggregationBuilder extends ValuesSourceAggregationBuilder<
return wrapLongitude;
}
@Override
public BucketCardinality bucketCardinality() {
return BucketCardinality.NONE;
}
@Override
protected GeoBoundsAggregatorFactory innerBuild(QueryShardContext queryShardContext, ValuesSourceConfig<ValuesSource.GeoPoint> config,
AggregatorFactory parent, Builder subFactoriesBuilder) throws IOException {

View File

@ -206,6 +206,11 @@ public class ScriptedMetricAggregationBuilder extends AbstractAggregationBuilder
return params;
}
@Override
public BucketCardinality bucketCardinality() {
return BucketCardinality.NONE;
}
@Override
protected ScriptedMetricAggregatorFactory doBuild(QueryShardContext queryShardContext, AggregatorFactory parent,
Builder subfactoriesBuilder) throws IOException {

View File

@ -575,6 +575,11 @@ public class TopHitsAggregationBuilder extends AbstractAggregationBuilder<TopHit
+ getType() + "] cannot accept sub-aggregations");
}
@Override
public BucketCardinality bucketCardinality() {
return BucketCardinality.NONE;
}
@Override
protected TopHitsAggregatorFactory doBuild(QueryShardContext queryShardContext, AggregatorFactory parent, Builder subfactoriesBuilder)
throws IOException {

View File

@ -92,12 +92,17 @@ public class WeightedAvgAggregationBuilder extends MultiValuesSourceAggregationB
// Do nothing, no extra state to write to stream
}
@Override
public BucketCardinality bucketCardinality() {
return BucketCardinality.NONE;
}
@Override
protected MultiValuesSourceAggregatorFactory<Numeric> innerBuild(QueryShardContext queryShardContext,
Map<String, ValuesSourceConfig<Numeric>> configs,
DocValueFormat format,
AggregatorFactory parent,
Builder subFactoriesBuilder) throws IOException {
Map<String, ValuesSourceConfig<Numeric>> configs,
DocValueFormat format,
AggregatorFactory parent,
Builder subFactoriesBuilder) throws IOException {
return new WeightedAvgAggregatorFactory(name, configs, format, queryShardContext, parent, subFactoriesBuilder, metaData);
}

View File

@ -24,7 +24,6 @@ import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.search.DocValueFormat;
import org.elasticsearch.search.aggregations.AggregationBuilder;
import org.elasticsearch.search.aggregations.bucket.MultiBucketAggregationBuilder;
import org.elasticsearch.search.aggregations.pipeline.BucketHelpers.GapPolicy;
import java.io.IOException;
@ -121,7 +120,7 @@ public abstract class BucketMetricsPipelineAggregationBuilder<AF extends BucketM
context.addBucketPathValidationError("aggregation does not exist for aggregation [" + name + "]: " + bucketsPaths[0]);
return;
}
if ((aggBuilder.get() instanceof MultiBucketAggregationBuilder) == false) {
if (aggBuilder.get().bucketCardinality() != AggregationBuilder.BucketCardinality.MANY) {
context.addValidationError("The first aggregation in " + PipelineAggregator.Parser.BUCKETS_PATH.getPreferredName()
+ " must be a multi-bucket aggregation for aggregation [" + name + "] found :"
+ aggBuilder.get().getClass().getName() + " for buckets path: " + bucketsPaths[0]);

View File

@ -73,6 +73,11 @@ public abstract class ValuesSourceAggregationBuilder<VS extends ValuesSource, AB
throw new AggregationInitializationException("Aggregator [" + name + "] of type ["
+ getType() + "] cannot accept sub-aggregations");
}
@Override
public final BucketCardinality bucketCardinality() {
return BucketCardinality.NONE;
}
}
private final ValuesSourceType valuesSourceType;

View File

@ -396,11 +396,16 @@ public class SearchModuleTests extends ESTestCase {
protected void innerWriteTo(StreamOutput out) throws IOException {
}
@Override
public BucketCardinality bucketCardinality() {
return BucketCardinality.NONE;
}
@Override
protected ValuesSourceAggregatorFactory<ValuesSource> innerBuild(QueryShardContext queryShardContext,
ValuesSourceConfig<ValuesSource> config,
AggregatorFactory parent,
Builder subFactoriesBuilder) throws IOException {
ValuesSourceConfig<ValuesSource> config,
AggregatorFactory parent,
Builder subFactoriesBuilder) throws IOException {
return null;
}

View File

@ -65,6 +65,11 @@ public class StringStatsAggregationBuilder extends ValuesSourceAggregationBuilde
out.writeBoolean(showDistribution);
}
@Override
public BucketCardinality bucketCardinality() {
return BucketCardinality.NONE;
}
@Override
protected StringStatsAggregatorFactory innerBuild(QueryShardContext queryShardContext,
ValuesSourceConfig<ValuesSource.Bytes> config,

View File

@ -113,6 +113,11 @@ public class TopMetricsAggregationBuilder extends AbstractAggregationBuilder<Top
return new TopMetricsAggregationBuilder(this, factoriesBuilder, metaData);
}
@Override
public BucketCardinality bucketCardinality() {
return BucketCardinality.NONE;
}
@Override
protected AggregatorFactory doBuild(QueryShardContext queryShardContext, AggregatorFactory parent, Builder subFactoriesBuilder)
throws IOException {

View File

@ -99,4 +99,9 @@ public class CancellingAggregationBuilder extends AbstractAggregationBuilder<Can
}
};
}
@Override
public BucketCardinality bucketCardinality() {
return BucketCardinality.NONE;
}
}

View File

@ -64,11 +64,16 @@ public class MockDeprecatedAggregationBuilder extends ValuesSourceAggregationBui
protected void innerWriteTo(StreamOutput out) throws IOException {
}
@Override
public BucketCardinality bucketCardinality() {
return BucketCardinality.NONE;
}
@Override
protected ValuesSourceAggregatorFactory<ValuesSource> innerBuild(QueryShardContext queryShardContext,
ValuesSourceConfig<ValuesSource> config,
AggregatorFactory parent,
Builder subFactoriesBuilder) throws IOException {
ValuesSourceConfig<ValuesSource> config,
AggregatorFactory parent,
Builder subFactoriesBuilder) throws IOException {
return null;
}