Skip to content

Commit f9aaf8d

Browse files
committed
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.
1 parent feecbc8 commit f9aaf8d

File tree

2 files changed

+72
-84
lines changed

2 files changed

+72
-84
lines changed

core/src/main/java/org/elasticsearch/search/aggregations/Aggregations.java

Lines changed: 59 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,31 +18,84 @@
1818
*/
1919
package org.elasticsearch.search.aggregations;
2020

21+
import java.util.Collections;
22+
import java.util.HashMap;
23+
import java.util.Iterator;
2124
import java.util.List;
2225
import java.util.Map;
26+
import java.util.Objects;
27+
28+
import static java.util.Collections.unmodifiableMap;
2329

2430
/**
25-
* Represents a set of computed addAggregation.
31+
* Represents a set of {@link Aggregation}s
2632
*/
27-
public interface Aggregations extends Iterable<Aggregation> {
33+
public abstract class Aggregations implements Iterable<Aggregation> {
34+
35+
protected List<? extends Aggregation> aggregations = Collections.emptyList();
36+
protected Map<String, Aggregation> aggregationsAsMap;
37+
38+
protected Aggregations() {
39+
}
40+
41+
protected Aggregations(List<? extends Aggregation> aggregations) {
42+
this.aggregations = aggregations;
43+
}
44+
45+
/**
46+
* Iterates over the {@link Aggregation}s.
47+
*/
48+
@Override
49+
public final Iterator<Aggregation> iterator() {
50+
return aggregations.stream().map((p) -> (Aggregation) p).iterator();
51+
}
2852

2953
/**
3054
* The list of {@link Aggregation}s.
3155
*/
32-
List<Aggregation> asList();
56+
public final List<Aggregation> asList() {
57+
return Collections.unmodifiableList(aggregations);
58+
}
3359

3460
/**
3561
* Returns the {@link Aggregation}s keyed by aggregation name.
3662
*/
37-
Map<String, Aggregation> asMap();
63+
public final Map<String, Aggregation> asMap() {
64+
return getAsMap();
65+
}
3866

3967
/**
4068
* Returns the {@link Aggregation}s keyed by aggregation name.
4169
*/
42-
Map<String, Aggregation> getAsMap();
70+
public final Map<String, Aggregation> getAsMap() {
71+
if (aggregationsAsMap == null) {
72+
Map<String, Aggregation> newAggregationsAsMap = new HashMap<>(aggregations.size());
73+
for (Aggregation aggregation : aggregations) {
74+
newAggregationsAsMap.put(aggregation.getName(), aggregation);
75+
}
76+
this.aggregationsAsMap = unmodifiableMap(newAggregationsAsMap);
77+
}
78+
return aggregationsAsMap;
79+
}
4380

4481
/**
4582
* Returns the aggregation that is associated with the specified name.
4683
*/
47-
<A extends Aggregation> A get(String name);
84+
@SuppressWarnings("unchecked")
85+
public final <A extends Aggregation> A get(String name) {
86+
return (A) asMap().get(name);
87+
}
88+
89+
@Override
90+
public final boolean equals(Object obj) {
91+
if (obj == null || getClass() != obj.getClass()) {
92+
return false;
93+
}
94+
return aggregations.equals(((Aggregations) obj).aggregations);
95+
}
96+
97+
@Override
98+
public final int hashCode() {
99+
return Objects.hash(getClass(), aggregations);
100+
}
48101
}

core/src/main/java/org/elasticsearch/search/aggregations/InternalAggregations.java

Lines changed: 13 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -29,80 +29,24 @@
2929
import java.util.ArrayList;
3030
import java.util.Collections;
3131
import java.util.HashMap;
32-
import java.util.Iterator;
3332
import java.util.List;
3433
import java.util.Map;
35-
import java.util.stream.Collectors;
3634

37-
import static java.util.Collections.emptyMap;
38-
import static java.util.Collections.unmodifiableMap;
3935
/**
4036
* An internal implementation of {@link Aggregations}.
4137
*/
42-
public class InternalAggregations implements Aggregations, ToXContent, Streamable {
38+
public final class InternalAggregations extends Aggregations implements ToXContent, Streamable {
4339

4440
public static final InternalAggregations EMPTY = new InternalAggregations();
4541

46-
private List<InternalAggregation> aggregations = Collections.emptyList();
47-
48-
private Map<String, Aggregation> aggregationsAsMap;
49-
5042
private InternalAggregations() {
5143
}
5244

5345
/**
5446
* Constructs a new addAggregation.
5547
*/
5648
public InternalAggregations(List<InternalAggregation> aggregations) {
57-
this.aggregations = aggregations;
58-
}
59-
60-
/**
61-
* Iterates over the {@link Aggregation}s.
62-
*/
63-
@Override
64-
public Iterator<Aggregation> iterator() {
65-
return aggregations.stream().map((p) -> (Aggregation) p).iterator();
66-
}
67-
68-
/**
69-
* The list of {@link Aggregation}s.
70-
*/
71-
@Override
72-
public List<Aggregation> asList() {
73-
return aggregations.stream().map((p) -> (Aggregation) p).collect(Collectors.toList());
74-
}
75-
76-
/**
77-
* Returns the {@link Aggregation}s keyed by map.
78-
*/
79-
@Override
80-
public Map<String, Aggregation> asMap() {
81-
return getAsMap();
82-
}
83-
84-
/**
85-
* Returns the {@link Aggregation}s keyed by map.
86-
*/
87-
@Override
88-
public Map<String, Aggregation> getAsMap() {
89-
if (aggregationsAsMap == null) {
90-
Map<String, InternalAggregation> newAggregationsAsMap = new HashMap<>();
91-
for (InternalAggregation aggregation : aggregations) {
92-
newAggregationsAsMap.put(aggregation.getName(), aggregation);
93-
}
94-
this.aggregationsAsMap = unmodifiableMap(newAggregationsAsMap);
95-
}
96-
return aggregationsAsMap;
97-
}
98-
99-
/**
100-
* @return the aggregation of the specified name.
101-
*/
102-
@SuppressWarnings("unchecked")
103-
@Override
104-
public <A extends Aggregation> A get(String name) {
105-
return (A) asMap().get(name);
49+
super(aggregations);
10650
}
10751

10852
/**
@@ -117,21 +61,16 @@ public static InternalAggregations reduce(List<InternalAggregations> aggregation
11761
}
11862

11963
// first we collect all aggregations of the same type and list them together
120-
12164
Map<String, List<InternalAggregation>> aggByName = new HashMap<>();
12265
for (InternalAggregations aggregations : aggregationsList) {
123-
for (InternalAggregation aggregation : aggregations.aggregations) {
124-
List<InternalAggregation> aggs = aggByName.get(aggregation.getName());
125-
if (aggs == null) {
126-
aggs = new ArrayList<>(aggregationsList.size());
127-
aggByName.put(aggregation.getName(), aggs);
128-
}
129-
aggs.add(aggregation);
66+
for (Aggregation aggregation : aggregations.aggregations) {
67+
List<InternalAggregation> aggs = aggByName.computeIfAbsent(
68+
aggregation.getName(), k -> new ArrayList<>(aggregationsList.size()));
69+
aggs.add((InternalAggregation)aggregation);
13070
}
13171
}
13272

13373
// now we can use the first aggregation of each list to handle the reduce of its list
134-
13574
List<InternalAggregation> reducedAggregations = new ArrayList<>();
13675
for (Map.Entry<String, List<InternalAggregation>> entry : aggByName.entrySet()) {
13776
List<InternalAggregation> aggregations = entry.getValue();
@@ -141,31 +80,27 @@ public static InternalAggregations reduce(List<InternalAggregations> aggregation
14180
return new InternalAggregations(reducedAggregations);
14281
}
14382

144-
/** The fields required to write this addAggregation to xcontent */
145-
static class Fields {
146-
public static final String AGGREGATIONS = "aggregations";
147-
}
148-
14983
@Override
15084
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
15185
if (aggregations.isEmpty()) {
15286
return builder;
15387
}
154-
builder.startObject(Fields.AGGREGATIONS);
88+
builder.startObject("aggregations");
15589
toXContentInternal(builder, params);
15690
return builder.endObject();
15791
}
15892

15993
/**
160-
* Directly write all the addAggregation without their bounding object. Used by sub-addAggregation (non top level addAggregation)
94+
* Directly write all the aggregations without their bounding object. Used by sub-aggregations (non top level aggs)
16195
*/
16296
public XContentBuilder toXContentInternal(XContentBuilder builder, Params params) throws IOException {
16397
for (Aggregation aggregation : aggregations) {
164-
((InternalAggregation) aggregation).toXContent(builder, params);
98+
((InternalAggregation)aggregation).toXContent(builder, params);
16599
}
166100
return builder;
167101
}
168102

103+
169104
public static InternalAggregations readAggregations(StreamInput in) throws IOException {
170105
InternalAggregations result = new InternalAggregations();
171106
result.readFrom(in);
@@ -180,13 +115,13 @@ public static InternalAggregations readOptionalAggregations(StreamInput in) thro
180115
public void readFrom(StreamInput in) throws IOException {
181116
aggregations = in.readList(stream -> in.readNamedWriteable(InternalAggregation.class));
182117
if (aggregations.isEmpty()) {
183-
aggregationsAsMap = emptyMap();
118+
aggregationsAsMap = Collections.emptyMap();
184119
}
185120
}
186121

187122
@Override
123+
@SuppressWarnings("unchecked")
188124
public void writeTo(StreamOutput out) throws IOException {
189-
out.writeNamedWriteableList(aggregations);
125+
out.writeNamedWriteableList((List<InternalAggregation>)aggregations);
190126
}
191-
192127
}

0 commit comments

Comments
 (0)