Skip to content

Commit 9245a18

Browse files
committed
Aggregations Refactor: Refactor Nested and Reverse Nested Aggregations
1 parent c47989a commit 9245a18

File tree

7 files changed

+187
-9
lines changed

7 files changed

+187
-9
lines changed

core/src/main/java/org/elasticsearch/search/aggregations/bucket/nested/NestedAggregator.java

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,11 @@
2727
import org.apache.lucene.search.Weight;
2828
import org.apache.lucene.search.join.BitSetProducer;
2929
import org.apache.lucene.util.BitSet;
30+
import org.elasticsearch.common.ParseField;
31+
import org.elasticsearch.common.io.stream.StreamInput;
32+
import org.elasticsearch.common.io.stream.StreamOutput;
3033
import org.elasticsearch.common.lucene.search.Queries;
34+
import org.elasticsearch.common.xcontent.XContentBuilder;
3135
import org.elasticsearch.index.mapper.object.ObjectMapper;
3236
import org.elasticsearch.search.aggregations.AggregationExecutionException;
3337
import org.elasticsearch.search.aggregations.Aggregator;
@@ -44,12 +48,15 @@
4448
import java.io.IOException;
4549
import java.util.List;
4650
import java.util.Map;
51+
import java.util.Objects;
4752

4853
/**
4954
*
5055
*/
5156
public class NestedAggregator extends SingleBucketAggregator {
5257

58+
static final ParseField PATH_FIELD = new ParseField("path");
59+
5360
private BitSetProducer parentFilter;
5461
private final Query childFilter;
5562

@@ -141,11 +148,25 @@ public static class Factory extends AggregatorFactory {
141148

142149
private final String path;
143150

151+
/**
152+
* @param name
153+
* the name of this aggregation
154+
* @param path
155+
* the path to use for this nested aggregation. The path must
156+
* match the path to a nested object in the mappings.
157+
*/
144158
public Factory(String name, String path) {
145159
super(name, InternalNested.TYPE);
146160
this.path = path;
147161
}
148162

163+
/**
164+
* Get the path to use for this nested aggregation.
165+
*/
166+
public String path() {
167+
return path;
168+
}
169+
149170
@Override
150171
public Aggregator createInternal(AggregationContext context, Aggregator parent, boolean collectsFromSingleBucket,
151172
List<PipelineAggregator> pipelineAggregators, Map<String, Object> metaData) throws IOException {
@@ -162,6 +183,37 @@ public Aggregator createInternal(AggregationContext context, Aggregator parent,
162183
return new NestedAggregator(name, factories, objectMapper, context, parent, pipelineAggregators, metaData);
163184
}
164185

186+
@Override
187+
protected XContentBuilder internalXContent(XContentBuilder builder, Params params) throws IOException {
188+
builder.startObject();
189+
builder.field(PATH_FIELD.getPreferredName(), path);
190+
builder.endObject();
191+
return builder;
192+
}
193+
194+
@Override
195+
protected AggregatorFactory doReadFrom(String name, StreamInput in) throws IOException {
196+
String path = in.readString();
197+
Factory factory = new Factory(name, path);
198+
return factory;
199+
}
200+
201+
@Override
202+
protected void doWriteTo(StreamOutput out) throws IOException {
203+
out.writeString(path);
204+
}
205+
206+
@Override
207+
protected int doHashCode() {
208+
return Objects.hash(path);
209+
}
210+
211+
@Override
212+
protected boolean doEquals(Object obj) {
213+
Factory other = (Factory) obj;
214+
return Objects.equals(path, other.path);
215+
}
216+
165217
private final static class Unmapped extends NonCollectingAggregator {
166218

167219
public Unmapped(String name, AggregationContext context, Aggregator parent, List<PipelineAggregator> pipelineAggregators, Map<String, Object> metaData)

core/src/main/java/org/elasticsearch/search/aggregations/bucket/nested/NestedParser.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ public AggregatorFactory parse(String aggregationName, XContentParser parser, Se
4646
if (token == XContentParser.Token.FIELD_NAME) {
4747
currentFieldName = parser.currentName();
4848
} else if (token == XContentParser.Token.VALUE_STRING) {
49-
if ("path".equals(currentFieldName)) {
49+
if (context.parseFieldMatcher().match(currentFieldName, NestedAggregator.PATH_FIELD)) {
5050
path = parser.text();
5151
} else {
5252
throw new SearchParseException(context, "Unknown key for a " + token + " in [" + aggregationName + "]: ["
@@ -67,9 +67,8 @@ public AggregatorFactory parse(String aggregationName, XContentParser parser, Se
6767
return new NestedAggregator.Factory(aggregationName, path);
6868
}
6969

70-
// NORELEASE implement this method when refactoring this aggregation
7170
@Override
7271
public AggregatorFactory[] getFactoryPrototypes() {
73-
return null;
72+
return new AggregatorFactory[] { new NestedAggregator.Factory(null, null) };
7473
}
7574
}

core/src/main/java/org/elasticsearch/search/aggregations/bucket/nested/ReverseNestedAggregator.java

Lines changed: 57 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,11 @@
2525
import org.apache.lucene.search.Query;
2626
import org.apache.lucene.search.join.BitSetProducer;
2727
import org.apache.lucene.util.BitSet;
28+
import org.elasticsearch.common.ParseField;
29+
import org.elasticsearch.common.io.stream.StreamInput;
30+
import org.elasticsearch.common.io.stream.StreamOutput;
2831
import org.elasticsearch.common.lucene.search.Queries;
32+
import org.elasticsearch.common.xcontent.XContentBuilder;
2933
import org.elasticsearch.index.mapper.object.ObjectMapper;
3034
import org.elasticsearch.search.SearchParseException;
3135
import org.elasticsearch.search.aggregations.AggregationExecutionException;
@@ -43,12 +47,15 @@
4347
import java.io.IOException;
4448
import java.util.List;
4549
import java.util.Map;
50+
import java.util.Objects;
4651

4752
/**
4853
*
4954
*/
5055
public class ReverseNestedAggregator extends SingleBucketAggregator {
5156

57+
static final ParseField PATH_FIELD = new ParseField("path");
58+
5259
private final Query parentFilter;
5360
private final BitSetProducer parentBitsetProducer;
5461

@@ -121,13 +128,28 @@ Query getParentFilter() {
121128

122129
public static class Factory extends AggregatorFactory {
123130

124-
private final String path;
131+
private String path;
125132

126-
public Factory(String name, String path) {
133+
public Factory(String name) {
127134
super(name, InternalReverseNested.TYPE);
135+
}
136+
137+
/**
138+
* Set the path to use for this nested aggregation. The path must match
139+
* the path to a nested object in the mappings. If it is not specified
140+
* then this aggregation will go back to the root document.
141+
*/
142+
public void path(String path) {
128143
this.path = path;
129144
}
130145

146+
/**
147+
* Get the path to use for this nested aggregation.
148+
*/
149+
public String path() {
150+
return path;
151+
}
152+
131153
@Override
132154
public Aggregator createInternal(AggregationContext context, Aggregator parent, boolean collectsFromSingleBucket,
133155
List<PipelineAggregator> pipelineAggregators, Map<String, Object> metaData) throws IOException {
@@ -153,6 +175,39 @@ public Aggregator createInternal(AggregationContext context, Aggregator parent,
153175
return new ReverseNestedAggregator(name, factories, objectMapper, context, parent, pipelineAggregators, metaData);
154176
}
155177

178+
@Override
179+
protected XContentBuilder internalXContent(XContentBuilder builder, Params params) throws IOException {
180+
builder.startObject();
181+
if (path != null) {
182+
builder.field(PATH_FIELD.getPreferredName(), path);
183+
}
184+
builder.endObject();
185+
return builder;
186+
}
187+
188+
@Override
189+
protected AggregatorFactory doReadFrom(String name, StreamInput in) throws IOException {
190+
Factory factory = new Factory(name);
191+
factory.path = in.readOptionalString();
192+
return factory;
193+
}
194+
195+
@Override
196+
protected void doWriteTo(StreamOutput out) throws IOException {
197+
out.writeOptionalString(path);
198+
}
199+
200+
@Override
201+
protected int doHashCode() {
202+
return Objects.hash(path);
203+
}
204+
205+
@Override
206+
protected boolean doEquals(Object obj) {
207+
Factory other = (Factory) obj;
208+
return Objects.equals(path, other.path);
209+
}
210+
156211
private final static class Unmapped extends NonCollectingAggregator {
157212

158213
public Unmapped(String name, AggregationContext context, Aggregator parent, List<PipelineAggregator> pipelineAggregators, Map<String, Object> metaData)

core/src/main/java/org/elasticsearch/search/aggregations/bucket/nested/ReverseNestedParser.java

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -58,12 +58,15 @@ public AggregatorFactory parse(String aggregationName, XContentParser parser, Se
5858
}
5959
}
6060

61-
return new ReverseNestedAggregator.Factory(aggregationName, path);
61+
ReverseNestedAggregator.Factory factory = new ReverseNestedAggregator.Factory(aggregationName);
62+
if (path != null) {
63+
factory.path(path);
64+
}
65+
return factory;
6266
}
6367

64-
// NORELEASE implement this method when refactoring this aggregation
6568
@Override
6669
public AggregatorFactory[] getFactoryPrototypes() {
67-
return null;
70+
return new AggregatorFactory[] { new ReverseNestedAggregator.Factory(null) };
6871
}
6972
}

core/src/test/java/org/elasticsearch/search/aggregations/bucket/nested/NestedAggregatorTests.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,8 @@ public void testResetRootDocId() throws Exception {
119119
AggregationContext context = new AggregationContext(searchContext);
120120

121121
AggregatorFactories.Builder builder = AggregatorFactories.builder();
122-
builder.addAggregator(new NestedAggregator.Factory("test", "nested_field"));
122+
NestedAggregator.Factory factory = new NestedAggregator.Factory("test", "nested_field");
123+
builder.addAggregator(factory);
123124
AggregatorFactories factories = builder.build();
124125
searchContext.aggregations(new SearchContextAggregations(factories));
125126
factories.init(context);
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/*
2+
* Licensed to Elasticsearch under one or more contributor
3+
* license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright
5+
* ownership. Elasticsearch licenses this file to you under
6+
* the Apache License, Version 2.0 (the "License"); you may
7+
* not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
20+
package org.elasticsearch.search.aggregations.bucket.nested;
21+
22+
import org.elasticsearch.search.aggregations.BaseAggregationTestCase;
23+
import org.elasticsearch.search.aggregations.bucket.nested.NestedAggregator.Factory;
24+
25+
public class NestedTests extends BaseAggregationTestCase<NestedAggregator.Factory> {
26+
27+
@Override
28+
protected Factory createTestAggregatorFactory() {
29+
return new Factory(randomAsciiOfLengthBetween(1, 20), randomAsciiOfLengthBetween(3, 40));
30+
}
31+
32+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/*
2+
* Licensed to Elasticsearch under one or more contributor
3+
* license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright
5+
* ownership. Elasticsearch licenses this file to you under
6+
* the Apache License, Version 2.0 (the "License"); you may
7+
* not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
20+
package org.elasticsearch.search.aggregations.bucket.nested;
21+
22+
import org.elasticsearch.search.aggregations.BaseAggregationTestCase;
23+
import org.elasticsearch.search.aggregations.bucket.nested.ReverseNestedAggregator.Factory;
24+
25+
public class ReverseNestedTests extends BaseAggregationTestCase<ReverseNestedAggregator.Factory> {
26+
27+
@Override
28+
protected Factory createTestAggregatorFactory() {
29+
Factory factory = new Factory(randomAsciiOfLengthBetween(1, 20));
30+
if (randomBoolean()) {
31+
factory.path(randomAsciiOfLengthBetween(3, 40));
32+
}
33+
return factory;
34+
}
35+
36+
}

0 commit comments

Comments
 (0)