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.
This commit is contained in:
parent
077a6c3ee7
commit
82c678b5c7
|
@ -18,31 +18,84 @@
|
||||||
*/
|
*/
|
||||||
package org.elasticsearch.search.aggregations;
|
package org.elasticsearch.search.aggregations;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
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<Aggregation> {
|
public abstract class Aggregations implements Iterable<Aggregation> {
|
||||||
|
|
||||||
|
protected List<? extends Aggregation> aggregations = Collections.emptyList();
|
||||||
|
protected Map<String, Aggregation> aggregationsAsMap;
|
||||||
|
|
||||||
|
protected Aggregations() {
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Aggregations(List<? extends Aggregation> aggregations) {
|
||||||
|
this.aggregations = aggregations;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Iterates over the {@link Aggregation}s.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public final Iterator<Aggregation> iterator() {
|
||||||
|
return aggregations.stream().map((p) -> (Aggregation) p).iterator();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The list of {@link Aggregation}s.
|
* The list of {@link Aggregation}s.
|
||||||
*/
|
*/
|
||||||
List<Aggregation> asList();
|
public final List<Aggregation> asList() {
|
||||||
|
return Collections.unmodifiableList(aggregations);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the {@link Aggregation}s keyed by aggregation name.
|
* Returns the {@link Aggregation}s keyed by aggregation name.
|
||||||
*/
|
*/
|
||||||
Map<String, Aggregation> asMap();
|
public final Map<String, Aggregation> asMap() {
|
||||||
|
return getAsMap();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the {@link Aggregation}s keyed by aggregation name.
|
* Returns the {@link Aggregation}s keyed by aggregation name.
|
||||||
*/
|
*/
|
||||||
Map<String, Aggregation> getAsMap();
|
public final Map<String, Aggregation> getAsMap() {
|
||||||
|
if (aggregationsAsMap == null) {
|
||||||
|
Map<String, Aggregation> 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.
|
* Returns the aggregation that is associated with the specified name.
|
||||||
*/
|
*/
|
||||||
<A extends Aggregation> A get(String name);
|
@SuppressWarnings("unchecked")
|
||||||
|
public final <A extends Aggregation> 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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,27 +27,18 @@ import org.elasticsearch.search.aggregations.InternalAggregation.ReduceContext;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
import static java.util.Collections.emptyMap;
|
import static java.util.Collections.emptyMap;
|
||||||
import static java.util.Collections.unmodifiableMap;
|
|
||||||
/**
|
/**
|
||||||
* An internal implementation of {@link Aggregations}.
|
* 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();
|
public static final InternalAggregations EMPTY = new InternalAggregations();
|
||||||
|
|
||||||
private List<InternalAggregation> aggregations = Collections.emptyList();
|
|
||||||
|
|
||||||
private Map<String, Aggregation> aggregationsAsMap;
|
|
||||||
|
|
||||||
private InternalAggregations() {
|
private InternalAggregations() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -55,55 +46,7 @@ public class InternalAggregations implements Aggregations, ToXContent, Streamabl
|
||||||
* Constructs a new addAggregation.
|
* Constructs a new addAggregation.
|
||||||
*/
|
*/
|
||||||
public InternalAggregations(List<InternalAggregation> aggregations) {
|
public InternalAggregations(List<InternalAggregation> aggregations) {
|
||||||
this.aggregations = aggregations;
|
super(aggregations);
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Iterates over the {@link Aggregation}s.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public Iterator<Aggregation> iterator() {
|
|
||||||
return aggregations.stream().map((p) -> (Aggregation) p).iterator();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The list of {@link Aggregation}s.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public List<Aggregation> asList() {
|
|
||||||
return aggregations.stream().map((p) -> (Aggregation) p).collect(Collectors.toList());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the {@link Aggregation}s keyed by map.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public Map<String, Aggregation> asMap() {
|
|
||||||
return getAsMap();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the {@link Aggregation}s keyed by map.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public Map<String, Aggregation> getAsMap() {
|
|
||||||
if (aggregationsAsMap == null) {
|
|
||||||
Map<String, InternalAggregation> 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 extends Aggregation> A get(String name) {
|
|
||||||
return (A) asMap().get(name);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -118,21 +61,16 @@ public class InternalAggregations implements Aggregations, ToXContent, Streamabl
|
||||||
}
|
}
|
||||||
|
|
||||||
// first we collect all aggregations of the same type and list them together
|
// first we collect all aggregations of the same type and list them together
|
||||||
|
|
||||||
Map<String, List<InternalAggregation>> aggByName = new HashMap<>();
|
Map<String, List<InternalAggregation>> aggByName = new HashMap<>();
|
||||||
for (InternalAggregations aggregations : aggregationsList) {
|
for (InternalAggregations aggregations : aggregationsList) {
|
||||||
for (InternalAggregation aggregation : aggregations.aggregations) {
|
for (Aggregation aggregation : aggregations.aggregations) {
|
||||||
List<InternalAggregation> aggs = aggByName.get(aggregation.getName());
|
List<InternalAggregation> aggs = aggByName.computeIfAbsent(
|
||||||
if (aggs == null) {
|
aggregation.getName(), k -> new ArrayList<>(aggregationsList.size()));
|
||||||
aggs = new ArrayList<>(aggregationsList.size());
|
aggs.add((InternalAggregation)aggregation);
|
||||||
aggByName.put(aggregation.getName(), aggs);
|
|
||||||
}
|
|
||||||
aggs.add(aggregation);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// now we can use the first aggregation of each list to handle the reduce of its list
|
// now we can use the first aggregation of each list to handle the reduce of its list
|
||||||
|
|
||||||
List<InternalAggregation> reducedAggregations = new ArrayList<>();
|
List<InternalAggregation> reducedAggregations = new ArrayList<>();
|
||||||
for (Map.Entry<String, List<InternalAggregation>> entry : aggByName.entrySet()) {
|
for (Map.Entry<String, List<InternalAggregation>> entry : aggByName.entrySet()) {
|
||||||
List<InternalAggregation> aggregations = entry.getValue();
|
List<InternalAggregation> aggregations = entry.getValue();
|
||||||
|
@ -142,23 +80,18 @@ public class InternalAggregations implements Aggregations, ToXContent, Streamabl
|
||||||
return new InternalAggregations(reducedAggregations);
|
return new InternalAggregations(reducedAggregations);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** The fields required to write this addAggregation to xcontent */
|
|
||||||
static class Fields {
|
|
||||||
public static final String AGGREGATIONS = "aggregations";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
|
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
|
||||||
if (aggregations.isEmpty()) {
|
if (aggregations.isEmpty()) {
|
||||||
return builder;
|
return builder;
|
||||||
}
|
}
|
||||||
builder.startObject(Fields.AGGREGATIONS);
|
builder.startObject("aggregations");
|
||||||
toXContentInternal(builder, params);
|
toXContentInternal(builder, params);
|
||||||
return builder.endObject();
|
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 {
|
public XContentBuilder toXContentInternal(XContentBuilder builder, Params params) throws IOException {
|
||||||
for (Aggregation aggregation : aggregations) {
|
for (Aggregation aggregation : aggregations) {
|
||||||
|
@ -167,16 +100,13 @@ public class InternalAggregations implements Aggregations, ToXContent, Streamabl
|
||||||
return builder;
|
return builder;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static InternalAggregations readAggregations(StreamInput in) throws IOException {
|
public static InternalAggregations readAggregations(StreamInput in) throws IOException {
|
||||||
InternalAggregations result = new InternalAggregations();
|
InternalAggregations result = new InternalAggregations();
|
||||||
result.readFrom(in);
|
result.readFrom(in);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static InternalAggregations readOptionalAggregations(StreamInput in) throws IOException {
|
|
||||||
return in.readOptionalStreamable(InternalAggregations::new);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void readFrom(StreamInput in) throws IOException {
|
public void readFrom(StreamInput in) throws IOException {
|
||||||
aggregations = in.readList(stream -> in.readNamedWriteable(InternalAggregation.class));
|
aggregations = in.readList(stream -> in.readNamedWriteable(InternalAggregation.class));
|
||||||
|
@ -186,20 +116,8 @@ public class InternalAggregations implements Aggregations, ToXContent, Streamabl
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
public void writeTo(StreamOutput out) throws IOException {
|
public void writeTo(StreamOutput out) throws IOException {
|
||||||
out.writeNamedWriteableList(aggregations);
|
out.writeNamedWriteableList((List<InternalAggregation>)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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue