From 82c678b5c72396c82ad81798f235cfd04e056a7b Mon Sep 17 00:00:00 2001 From: Luca Cavanna Date: Thu, 20 Apr 2017 21:31:34 +0200 Subject: [PATCH] Make Aggregations an abstract class rather than an interface (#24184) Some of the base methods that don't have to do with reduce phase and serialization can be moved to the base class which is no longer an interface. This will be reusable by the high level REST client further on the road. Also it simplify things as having an interface with a single implementor is not that helpful. --- .../search/aggregations/Aggregations.java | 65 ++++++++++- .../aggregations/InternalAggregations.java | 106 ++---------------- 2 files changed, 71 insertions(+), 100 deletions(-) diff --git a/core/src/main/java/org/elasticsearch/search/aggregations/Aggregations.java b/core/src/main/java/org/elasticsearch/search/aggregations/Aggregations.java index f7fe3e49f0a..ef84edfb729 100644 --- a/core/src/main/java/org/elasticsearch/search/aggregations/Aggregations.java +++ b/core/src/main/java/org/elasticsearch/search/aggregations/Aggregations.java @@ -18,31 +18,84 @@ */ package org.elasticsearch.search.aggregations; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.Objects; + +import static java.util.Collections.unmodifiableMap; /** - * Represents a set of computed addAggregation. + * Represents a set of {@link Aggregation}s */ -public interface Aggregations extends Iterable { +public abstract class Aggregations implements Iterable { + + protected List aggregations = Collections.emptyList(); + protected Map aggregationsAsMap; + + protected Aggregations() { + } + + protected Aggregations(List aggregations) { + this.aggregations = aggregations; + } + + /** + * Iterates over the {@link Aggregation}s. + */ + @Override + public final Iterator iterator() { + return aggregations.stream().map((p) -> (Aggregation) p).iterator(); + } /** * The list of {@link Aggregation}s. */ - List asList(); + public final List asList() { + return Collections.unmodifiableList(aggregations); + } /** * Returns the {@link Aggregation}s keyed by aggregation name. */ - Map asMap(); + public final Map asMap() { + return getAsMap(); + } /** * Returns the {@link Aggregation}s keyed by aggregation name. */ - Map getAsMap(); + public final Map getAsMap() { + if (aggregationsAsMap == null) { + Map newAggregationsAsMap = new HashMap<>(aggregations.size()); + for (Aggregation aggregation : aggregations) { + newAggregationsAsMap.put(aggregation.getName(), aggregation); + } + this.aggregationsAsMap = unmodifiableMap(newAggregationsAsMap); + } + return aggregationsAsMap; + } /** * Returns the aggregation that is associated with the specified name. */ - A get(String name); + @SuppressWarnings("unchecked") + public final A get(String name) { + return (A) asMap().get(name); + } + + @Override + public final boolean equals(Object obj) { + if (obj == null || getClass() != obj.getClass()) { + return false; + } + return aggregations.equals(((Aggregations) obj).aggregations); + } + + @Override + public final int hashCode() { + return Objects.hash(getClass(), aggregations); + } } diff --git a/core/src/main/java/org/elasticsearch/search/aggregations/InternalAggregations.java b/core/src/main/java/org/elasticsearch/search/aggregations/InternalAggregations.java index c835c47c148..64c9e4794c3 100644 --- a/core/src/main/java/org/elasticsearch/search/aggregations/InternalAggregations.java +++ b/core/src/main/java/org/elasticsearch/search/aggregations/InternalAggregations.java @@ -27,27 +27,18 @@ import org.elasticsearch.search.aggregations.InternalAggregation.ReduceContext; import java.io.IOException; import java.util.ArrayList; -import java.util.Collections; import java.util.HashMap; -import java.util.Iterator; import java.util.List; import java.util.Map; -import java.util.Objects; -import java.util.stream.Collectors; import static java.util.Collections.emptyMap; -import static java.util.Collections.unmodifiableMap; /** * An internal implementation of {@link Aggregations}. */ -public class InternalAggregations implements Aggregations, ToXContent, Streamable { +public final class InternalAggregations extends Aggregations implements ToXContent, Streamable { public static final InternalAggregations EMPTY = new InternalAggregations(); - private List aggregations = Collections.emptyList(); - - private Map aggregationsAsMap; - private InternalAggregations() { } @@ -55,55 +46,7 @@ public class InternalAggregations implements Aggregations, ToXContent, Streamabl * Constructs a new addAggregation. */ public InternalAggregations(List aggregations) { - this.aggregations = aggregations; - } - - /** - * Iterates over the {@link Aggregation}s. - */ - @Override - public Iterator iterator() { - return aggregations.stream().map((p) -> (Aggregation) p).iterator(); - } - - /** - * The list of {@link Aggregation}s. - */ - @Override - public List asList() { - return aggregations.stream().map((p) -> (Aggregation) p).collect(Collectors.toList()); - } - - /** - * Returns the {@link Aggregation}s keyed by map. - */ - @Override - public Map asMap() { - return getAsMap(); - } - - /** - * Returns the {@link Aggregation}s keyed by map. - */ - @Override - public Map getAsMap() { - if (aggregationsAsMap == null) { - Map newAggregationsAsMap = new HashMap<>(); - for (InternalAggregation aggregation : aggregations) { - newAggregationsAsMap.put(aggregation.getName(), aggregation); - } - this.aggregationsAsMap = unmodifiableMap(newAggregationsAsMap); - } - return aggregationsAsMap; - } - - /** - * @return the aggregation of the specified name. - */ - @SuppressWarnings("unchecked") - @Override - public A get(String name) { - return (A) asMap().get(name); + super(aggregations); } /** @@ -118,21 +61,16 @@ public class InternalAggregations implements Aggregations, ToXContent, Streamabl } // first we collect all aggregations of the same type and list them together - Map> aggByName = new HashMap<>(); for (InternalAggregations aggregations : aggregationsList) { - for (InternalAggregation aggregation : aggregations.aggregations) { - List aggs = aggByName.get(aggregation.getName()); - if (aggs == null) { - aggs = new ArrayList<>(aggregationsList.size()); - aggByName.put(aggregation.getName(), aggs); - } - aggs.add(aggregation); + for (Aggregation aggregation : aggregations.aggregations) { + List aggs = aggByName.computeIfAbsent( + aggregation.getName(), k -> new ArrayList<>(aggregationsList.size())); + aggs.add((InternalAggregation)aggregation); } } // now we can use the first aggregation of each list to handle the reduce of its list - List reducedAggregations = new ArrayList<>(); for (Map.Entry> entry : aggByName.entrySet()) { List aggregations = entry.getValue(); @@ -142,41 +80,33 @@ public class InternalAggregations implements Aggregations, ToXContent, Streamabl return new InternalAggregations(reducedAggregations); } - /** The fields required to write this addAggregation to xcontent */ - static class Fields { - public static final String AGGREGATIONS = "aggregations"; - } - @Override public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { if (aggregations.isEmpty()) { return builder; } - builder.startObject(Fields.AGGREGATIONS); + builder.startObject("aggregations"); toXContentInternal(builder, params); return builder.endObject(); } /** - * Directly write all the addAggregation without their bounding object. Used by sub-addAggregation (non top level addAggregation) + * Directly write all the aggregations without their bounding object. Used by sub-aggregations (non top level aggs) */ public XContentBuilder toXContentInternal(XContentBuilder builder, Params params) throws IOException { for (Aggregation aggregation : aggregations) { - ((InternalAggregation) aggregation).toXContent(builder, params); + ((InternalAggregation)aggregation).toXContent(builder, params); } return builder; } + public static InternalAggregations readAggregations(StreamInput in) throws IOException { InternalAggregations result = new InternalAggregations(); result.readFrom(in); return result; } - public static InternalAggregations readOptionalAggregations(StreamInput in) throws IOException { - return in.readOptionalStreamable(InternalAggregations::new); - } - @Override public void readFrom(StreamInput in) throws IOException { aggregations = in.readList(stream -> in.readNamedWriteable(InternalAggregation.class)); @@ -186,20 +116,8 @@ public class InternalAggregations implements Aggregations, ToXContent, Streamabl } @Override + @SuppressWarnings("unchecked") public void writeTo(StreamOutput out) throws IOException { - out.writeNamedWriteableList(aggregations); - } - - @Override - public boolean equals(Object obj) { - if (obj == null || getClass() != obj.getClass()) { - return false; - } - return aggregations.equals(((InternalAggregations) obj).aggregations); - } - - @Override - public int hashCode() { - return Objects.hash(getClass(), aggregations); + out.writeNamedWriteableList((List)aggregations); } }