Skip to content

Commit df0d65e

Browse files
authored
Add pipeline aggregations to NativeSearchQuery.
Original Pull Request #1809 Closes #1255
1 parent 3a90059 commit df0d65e

File tree

4 files changed

+122
-8
lines changed

4 files changed

+122
-8
lines changed

src/main/java/org/springframework/data/elasticsearch/core/RequestFactory.java

+10-7
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,6 @@
7777
import org.elasticsearch.index.reindex.UpdateByQueryRequest;
7878
import org.elasticsearch.index.reindex.UpdateByQueryRequestBuilder;
7979
import org.elasticsearch.script.Script;
80-
import org.elasticsearch.search.aggregations.AbstractAggregationBuilder;
8180
import org.elasticsearch.search.builder.SearchSourceBuilder;
8281
import org.elasticsearch.search.fetch.subphase.FetchSourceContext;
8382
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
@@ -1119,9 +1118,11 @@ private void prepareNativeSearch(NativeSearchQuery query, SearchSourceBuilder so
11191118
}
11201119

11211120
if (!isEmpty(query.getAggregations())) {
1122-
for (AbstractAggregationBuilder<?> aggregationBuilder : query.getAggregations()) {
1123-
sourceBuilder.aggregation(aggregationBuilder);
1124-
}
1121+
query.getAggregations().forEach(sourceBuilder::aggregation);
1122+
}
1123+
1124+
if (!isEmpty(query.getPipelineAggregations())) {
1125+
query.getPipelineAggregations().forEach(sourceBuilder::aggregation);
11251126
}
11261127

11271128
}
@@ -1144,9 +1145,11 @@ private void prepareNativeSearch(SearchRequestBuilder searchRequestBuilder, Nati
11441145
}
11451146

11461147
if (!isEmpty(nativeSearchQuery.getAggregations())) {
1147-
for (AbstractAggregationBuilder<?> aggregationBuilder : nativeSearchQuery.getAggregations()) {
1148-
searchRequestBuilder.addAggregation(aggregationBuilder);
1149-
}
1148+
nativeSearchQuery.getAggregations().forEach(searchRequestBuilder::addAggregation);
1149+
}
1150+
1151+
if (!isEmpty(nativeSearchQuery.getPipelineAggregations())) {
1152+
nativeSearchQuery.getPipelineAggregations().forEach(searchRequestBuilder::addAggregation);
11501153
}
11511154
}
11521155

src/main/java/org/springframework/data/elasticsearch/core/query/NativeSearchQuery.java

+11
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import org.elasticsearch.index.query.QueryBuilder;
2323
import org.elasticsearch.script.mustache.SearchTemplateRequestBuilder;
2424
import org.elasticsearch.search.aggregations.AbstractAggregationBuilder;
25+
import org.elasticsearch.search.aggregations.PipelineAggregationBuilder;
2526
import org.elasticsearch.search.collapse.CollapseBuilder;
2627
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
2728
import org.elasticsearch.search.sort.SortBuilder;
@@ -48,6 +49,7 @@ public class NativeSearchQuery extends AbstractQuery {
4849
private final List<ScriptField> scriptFields = new ArrayList<>();
4950
@Nullable private CollapseBuilder collapseBuilder;
5051
@Nullable private List<AbstractAggregationBuilder<?>> aggregations;
52+
@Nullable private List<PipelineAggregationBuilder> pipelineAggregations;
5153
@Nullable private HighlightBuilder highlightBuilder;
5254
@Nullable private HighlightBuilder.Field[] highlightFields;
5355
@Nullable private List<IndexBoost> indicesBoost;
@@ -143,6 +145,11 @@ public List<AbstractAggregationBuilder<?>> getAggregations() {
143145
return aggregations;
144146
}
145147

148+
@Nullable
149+
public List<PipelineAggregationBuilder> getPipelineAggregations() {
150+
return pipelineAggregations;
151+
}
152+
146153
public void addAggregation(AbstractAggregationBuilder<?> aggregationBuilder) {
147154

148155
if (aggregations == null) {
@@ -156,6 +163,10 @@ public void setAggregations(List<AbstractAggregationBuilder<?>> aggregations) {
156163
this.aggregations = aggregations;
157164
}
158165

166+
public void setPipelineAggregations(List<PipelineAggregationBuilder> pipelineAggregationBuilders) {
167+
this.pipelineAggregations = pipelineAggregationBuilders;
168+
}
169+
159170
@Nullable
160171
public List<IndexBoost> getIndicesBoost() {
161172
return indicesBoost;

src/main/java/org/springframework/data/elasticsearch/core/query/NativeSearchQueryBuilder.java

+14
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import org.elasticsearch.index.query.QueryBuilder;
2828
import org.elasticsearch.script.mustache.SearchTemplateRequestBuilder;
2929
import org.elasticsearch.search.aggregations.AbstractAggregationBuilder;
30+
import org.elasticsearch.search.aggregations.PipelineAggregationBuilder;
3031
import org.elasticsearch.search.collapse.CollapseBuilder;
3132
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
3233
import org.elasticsearch.search.sort.SortBuilder;
@@ -55,6 +56,7 @@ public class NativeSearchQueryBuilder {
5556
private final List<ScriptField> scriptFields = new ArrayList<>();
5657
private final List<SortBuilder<?>> sortBuilders = new ArrayList<>();
5758
private final List<AbstractAggregationBuilder<?>> aggregationBuilders = new ArrayList<>();
59+
private final List<PipelineAggregationBuilder> pipelineAggregationBuilders = new ArrayList<>();
5860
@Nullable private HighlightBuilder highlightBuilder;
5961
@Nullable private HighlightBuilder.Field[] highlightFields;
6062
private Pageable pageable = Pageable.unpaged();
@@ -105,6 +107,14 @@ public NativeSearchQueryBuilder addAggregation(AbstractAggregationBuilder<?> agg
105107
return this;
106108
}
107109

110+
/**
111+
* @since 4.3
112+
*/
113+
public NativeSearchQueryBuilder addAggregation(PipelineAggregationBuilder pipelineAggregationBuilder) {
114+
this.pipelineAggregationBuilders.add(pipelineAggregationBuilder);
115+
return this;
116+
}
117+
108118
public NativeSearchQueryBuilder withHighlightBuilder(HighlightBuilder highlightBuilder) {
109119
this.highlightBuilder = highlightBuilder;
110120
return this;
@@ -239,6 +249,10 @@ public NativeSearchQuery build() {
239249
nativeSearchQuery.setAggregations(aggregationBuilders);
240250
}
241251

252+
if (!isEmpty(pipelineAggregationBuilders)) {
253+
nativeSearchQuery.setPipelineAggregations(pipelineAggregationBuilders);
254+
}
255+
242256
if (minScore > 0) {
243257
nativeSearchQuery.setMinScore(minScore);
244258
}

src/test/java/org/springframework/data/elasticsearch/core/aggregation/ElasticsearchTemplateAggregationTests.java

+87-1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import static org.assertj.core.api.Assertions.*;
1919
import static org.elasticsearch.index.query.QueryBuilders.*;
2020
import static org.elasticsearch.search.aggregations.AggregationBuilders.*;
21+
import static org.elasticsearch.search.aggregations.PipelineAggregatorBuilders.*;
2122
import static org.springframework.data.elasticsearch.annotations.FieldType.*;
2223
import static org.springframework.data.elasticsearch.annotations.FieldType.Integer;
2324

@@ -26,9 +27,14 @@
2627
import java.util.List;
2728

2829
import org.elasticsearch.action.search.SearchType;
30+
import org.elasticsearch.search.aggregations.Aggregation;
2931
import org.elasticsearch.search.aggregations.Aggregations;
32+
import org.elasticsearch.search.aggregations.pipeline.InternalStatsBucket;
33+
import org.elasticsearch.search.aggregations.pipeline.ParsedStatsBucket;
34+
import org.elasticsearch.search.aggregations.pipeline.StatsBucket;
3035
import org.junit.jupiter.api.AfterEach;
3136
import org.junit.jupiter.api.BeforeEach;
37+
import org.junit.jupiter.api.DisplayName;
3238
import org.junit.jupiter.api.Test;
3339
import org.springframework.beans.factory.annotation.Autowired;
3440
import org.springframework.context.annotation.Configuration;
@@ -109,7 +115,7 @@ public void after() {
109115
indexOperations.delete();
110116
}
111117

112-
@Test
118+
@Test // DATAES-96
113119
public void shouldReturnAggregatedResponseForGivenSearchQuery() {
114120

115121
// given
@@ -130,6 +136,56 @@ public void shouldReturnAggregatedResponseForGivenSearchQuery() {
130136
assertThat(searchHits.hasSearchHits()).isFalse();
131137
}
132138

139+
@Test // #1255
140+
@DisplayName("should work with pipeline aggregations")
141+
void shouldWorkWithPipelineAggregations() {
142+
143+
IndexInitializer.init(operations.indexOps(PipelineAggsEntity.class));
144+
operations.save( //
145+
new PipelineAggsEntity("1-1", "one"), //
146+
new PipelineAggsEntity("2-1", "two"), //
147+
new PipelineAggsEntity("2-2", "two"), //
148+
new PipelineAggsEntity("3-1", "three"), //
149+
new PipelineAggsEntity("3-2", "three"), //
150+
new PipelineAggsEntity("3-3", "three") //
151+
); //
152+
153+
NativeSearchQuery searchQuery = new NativeSearchQueryBuilder() //
154+
.withQuery(matchAllQuery()) //
155+
.withSearchType(SearchType.DEFAULT) //
156+
.addAggregation(terms("keyword_aggs").field("keyword")) //
157+
.addAggregation(statsBucket("keyword_bucket_stats", "keyword_aggs._count")) //
158+
.withMaxResults(0) //
159+
.build();
160+
161+
SearchHits<PipelineAggsEntity> searchHits = operations.search(searchQuery, PipelineAggsEntity.class);
162+
163+
Aggregations aggregations = searchHits.getAggregations();
164+
assertThat(aggregations).isNotNull();
165+
assertThat(aggregations.asMap().get("keyword_aggs")).isNotNull();
166+
Aggregation keyword_bucket_stats = aggregations.asMap().get("keyword_bucket_stats");
167+
assertThat(keyword_bucket_stats).isInstanceOf(StatsBucket.class);
168+
if (keyword_bucket_stats instanceof ParsedStatsBucket) {
169+
// Rest client
170+
ParsedStatsBucket statsBucket = (ParsedStatsBucket) keyword_bucket_stats;
171+
assertThat(statsBucket.getMin()).isEqualTo(1.0);
172+
assertThat(statsBucket.getMax()).isEqualTo(3.0);
173+
assertThat(statsBucket.getAvg()).isEqualTo(2.0);
174+
assertThat(statsBucket.getSum()).isEqualTo(6.0);
175+
assertThat(statsBucket.getCount()).isEqualTo(3L);
176+
}
177+
if (keyword_bucket_stats instanceof InternalStatsBucket) {
178+
// transport client
179+
InternalStatsBucket statsBucket = (InternalStatsBucket) keyword_bucket_stats;
180+
assertThat(statsBucket.getMin()).isEqualTo(1.0);
181+
assertThat(statsBucket.getMax()).isEqualTo(3.0);
182+
assertThat(statsBucket.getAvg()).isEqualTo(2.0);
183+
assertThat(statsBucket.getSum()).isEqualTo(6.0);
184+
assertThat(statsBucket.getCount()).isEqualTo(3L);
185+
}
186+
}
187+
188+
// region entities
133189
@Document(indexName = "test-index-articles-core-aggregation")
134190
static class ArticleEntity {
135191

@@ -256,4 +312,34 @@ public IndexQuery buildIndex() {
256312
}
257313
}
258314

315+
@Document(indexName = "pipeline-aggs")
316+
static class PipelineAggsEntity {
317+
@Id private String id;
318+
@Field(type = Keyword) private String keyword;
319+
320+
public PipelineAggsEntity() {}
321+
322+
public PipelineAggsEntity(String id, String keyword) {
323+
this.id = id;
324+
this.keyword = keyword;
325+
}
326+
327+
public String getId() {
328+
return id;
329+
}
330+
331+
public void setId(String id) {
332+
this.id = id;
333+
}
334+
335+
public String getKeyword() {
336+
return keyword;
337+
}
338+
339+
public void setKeyword(String keyword) {
340+
this.keyword = keyword;
341+
}
342+
}
343+
// endregion
344+
259345
}

0 commit comments

Comments
 (0)