|
@@ -22,7 +22,7 @@ package org.elasticsearch.search.aggregations.bucket.composite;
|
|
|
import org.elasticsearch.common.ParseField;
|
|
|
import org.elasticsearch.common.io.stream.StreamInput;
|
|
|
import org.elasticsearch.common.io.stream.StreamOutput;
|
|
|
-import org.elasticsearch.common.xcontent.ObjectParser;
|
|
|
+import org.elasticsearch.common.xcontent.ConstructingObjectParser;
|
|
|
import org.elasticsearch.common.xcontent.XContentBuilder;
|
|
|
import org.elasticsearch.common.xcontent.XContentParser;
|
|
|
import org.elasticsearch.search.aggregations.AbstractAggregationBuilder;
|
|
@@ -34,9 +34,12 @@ import org.elasticsearch.search.internal.SearchContext;
|
|
|
|
|
|
import java.io.IOException;
|
|
|
import java.util.ArrayList;
|
|
|
+import java.util.HashSet;
|
|
|
import java.util.List;
|
|
|
import java.util.Map;
|
|
|
import java.util.Objects;
|
|
|
+import java.util.Set;
|
|
|
+import java.util.function.Function;
|
|
|
|
|
|
public class CompositeAggregationBuilder extends AbstractAggregationBuilder<CompositeAggregationBuilder> {
|
|
|
public static final String NAME = "composite";
|
|
@@ -45,29 +48,36 @@ public class CompositeAggregationBuilder extends AbstractAggregationBuilder<Comp
|
|
|
public static final ParseField SIZE_FIELD_NAME = new ParseField("size");
|
|
|
public static final ParseField SOURCES_FIELD_NAME = new ParseField("sources");
|
|
|
|
|
|
- private static final ObjectParser<CompositeAggregationBuilder, Void> PARSER;
|
|
|
- static {
|
|
|
- PARSER = new ObjectParser<>(NAME);
|
|
|
- PARSER.declareInt(CompositeAggregationBuilder::size, SIZE_FIELD_NAME);
|
|
|
- PARSER.declareObject(CompositeAggregationBuilder::aggregateAfter, (parser, context) -> parser.map(), AFTER_FIELD_NAME);
|
|
|
- PARSER.declareObjectArray(CompositeAggregationBuilder::setSources,
|
|
|
+ private static final Function<String, ConstructingObjectParser<CompositeAggregationBuilder, Void>> PARSER = name -> {
|
|
|
+ @SuppressWarnings("unchecked")
|
|
|
+ ConstructingObjectParser<CompositeAggregationBuilder, Void> parser = new ConstructingObjectParser<>(NAME, a -> {
|
|
|
+ CompositeAggregationBuilder builder = new CompositeAggregationBuilder(name, (List<CompositeValuesSourceBuilder<?>>)a[0]);
|
|
|
+ if (a[1] != null) {
|
|
|
+ builder.size((Integer)a[1]);
|
|
|
+ }
|
|
|
+ if (a[2] != null) {
|
|
|
+ builder.aggregateAfter((Map<String, Object>)a[2]);
|
|
|
+ }
|
|
|
+ return builder;
|
|
|
+ });
|
|
|
+ parser.declareObjectArray(ConstructingObjectParser.constructorArg(),
|
|
|
(p, c) -> CompositeValuesSourceParserHelper.fromXContent(p), SOURCES_FIELD_NAME);
|
|
|
- }
|
|
|
+ parser.declareInt(ConstructingObjectParser.optionalConstructorArg(), SIZE_FIELD_NAME);
|
|
|
+ parser.declareObject(ConstructingObjectParser.optionalConstructorArg(), (p, context) -> p.map(), AFTER_FIELD_NAME);
|
|
|
+ return parser;
|
|
|
+ };
|
|
|
+
|
|
|
public static CompositeAggregationBuilder parse(String aggregationName, XContentParser parser) throws IOException {
|
|
|
- return PARSER.parse(parser, new CompositeAggregationBuilder(aggregationName), null);
|
|
|
+ return PARSER.apply(aggregationName).parse(parser, null);
|
|
|
}
|
|
|
|
|
|
private List<CompositeValuesSourceBuilder<?>> sources;
|
|
|
private Map<String, Object> after;
|
|
|
private int size = 10;
|
|
|
|
|
|
- private CompositeAggregationBuilder(String name) {
|
|
|
- this(name, null);
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
public CompositeAggregationBuilder(String name, List<CompositeValuesSourceBuilder<?>> sources) {
|
|
|
super(name);
|
|
|
+ validateSources(sources);
|
|
|
this.sources = sources;
|
|
|
}
|
|
|
|
|
@@ -116,11 +126,6 @@ public class CompositeAggregationBuilder extends AbstractAggregationBuilder<Comp
|
|
|
return NAME;
|
|
|
}
|
|
|
|
|
|
- private CompositeAggregationBuilder setSources(List<CompositeValuesSourceBuilder<?>> sources) {
|
|
|
- this.sources = sources;
|
|
|
- return this;
|
|
|
- }
|
|
|
-
|
|
|
/**
|
|
|
* Gets the list of {@link CompositeValuesSourceBuilder} for this aggregation.
|
|
|
*/
|
|
@@ -167,6 +172,28 @@ public class CompositeAggregationBuilder extends AbstractAggregationBuilder<Comp
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ private static void validateSources(List<CompositeValuesSourceBuilder<?>> sources) {
|
|
|
+ if (sources == null || sources.isEmpty()) {
|
|
|
+ throw new IllegalArgumentException("Composite [" + SOURCES_FIELD_NAME.getPreferredName() + "] cannot be null or empty");
|
|
|
+ }
|
|
|
+
|
|
|
+ Set<String> names = new HashSet<>();
|
|
|
+ Set<String> duplicates = new HashSet<>();
|
|
|
+ sources.forEach(source -> {
|
|
|
+ if (source == null) {
|
|
|
+ throw new IllegalArgumentException("Composite source cannot be null");
|
|
|
+ }
|
|
|
+ boolean unique = names.add(source.name());
|
|
|
+ if (unique == false) {
|
|
|
+ duplicates.add(source.name());
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ if (duplicates.size() > 0) {
|
|
|
+ throw new IllegalArgumentException("Composite source names must be unique, found duplicates: " + duplicates);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
@Override
|
|
|
protected AggregatorFactory<?> doBuild(SearchContext context, AggregatorFactory<?> parent,
|
|
|
AggregatorFactories.Builder subfactoriesBuilder) throws IOException {
|