Skip to content

Commit ab7e870

Browse files
author
Rizwan Idrees
committed
DATAES-96 - Add support for aggregation in ElasticsearchTemplate
1 parent 369b2eb commit ab7e870

File tree

9 files changed

+361
-174
lines changed

9 files changed

+361
-174
lines changed

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -471,4 +471,7 @@ public interface ElasticsearchOperations {
471471
* @return
472472
*/
473473
Set<String> queryForAlias(String indexName);
474+
475+
476+
<T> T query(SearchQuery query, ResultsExtractor<T> resultsExtractor);
474477
}

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

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@
6464
import org.elasticsearch.index.query.QueryBuilder;
6565
import org.elasticsearch.index.query.QueryBuilders;
6666
import org.elasticsearch.search.SearchHit;
67+
import org.elasticsearch.search.aggregations.AbstractAggregationBuilder;
6768
import org.elasticsearch.search.facet.FacetBuilder;
6869
import org.elasticsearch.search.highlight.HighlightBuilder;
6970
import org.elasticsearch.search.sort.SortBuilder;
@@ -247,7 +248,13 @@ public <T> FacetedPage<T> queryForPage(SearchQuery query, Class<T> clazz, Search
247248
return mapper.mapResults(response, clazz, query.getPageable());
248249
}
249250

250-
@Override
251+
@Override
252+
public <T> T query(SearchQuery query, ResultsExtractor<T> resultsExtractor) {
253+
SearchResponse response = doSearch(prepareSearch(query), query);
254+
return resultsExtractor.extract(response);
255+
}
256+
257+
@Override
251258
public <T> List<T> queryForList(CriteriaQuery query, Class<T> clazz) {
252259
return queryForPage(query, clazz).getContent();
253260
}
@@ -608,6 +615,12 @@ private SearchResponse doSearch(SearchRequestBuilder searchRequest, SearchQuery
608615
}
609616
}
610617

618+
if(CollectionUtils.isNotEmpty(searchQuery.getAggregations())){
619+
for(AbstractAggregationBuilder aggregationBuilder : searchQuery.getAggregations()){
620+
searchRequest.addAggregation(aggregationBuilder);
621+
}
622+
}
623+
611624
return searchRequest.setQuery(searchQuery.getQuery()).execute().actionGet();
612625
}
613626

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
/*
2+
* Copyright 2013-2014 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.data.elasticsearch.core;
18+
19+
import org.elasticsearch.action.search.SearchResponse;
20+
21+
public interface ResultsExtractor<T> {
22+
T extract(SearchResponse response);
23+
}

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

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,16 @@
1515
*/
1616
package org.springframework.data.elasticsearch.core.query;
1717

18-
import java.util.ArrayList;
19-
import java.util.List;
20-
2118
import org.elasticsearch.index.query.FilterBuilder;
2219
import org.elasticsearch.index.query.QueryBuilder;
20+
import org.elasticsearch.search.aggregations.AbstractAggregationBuilder;
2321
import org.elasticsearch.search.highlight.HighlightBuilder;
2422
import org.elasticsearch.search.sort.SortBuilder;
2523
import org.springframework.data.elasticsearch.core.facet.FacetRequest;
2624

25+
import java.util.ArrayList;
26+
import java.util.List;
27+
2728
/**
2829
* NativeSearchQuery
2930
*
@@ -37,6 +38,7 @@ public class NativeSearchQuery extends AbstractQuery implements SearchQuery {
3738
private FilterBuilder filter;
3839
private List<SortBuilder> sorts;
3940
private List<FacetRequest> facets;
41+
private List<AbstractAggregationBuilder> aggregations;
4042
private HighlightBuilder.Field[] highlightFields;
4143

4244

@@ -94,4 +96,21 @@ public void setFacets(List<FacetRequest> facets) {
9496
public List<FacetRequest> getFacets() {
9597
return facets;
9698
}
99+
100+
@Override
101+
public List<AbstractAggregationBuilder> getAggregations() {
102+
return aggregations;
103+
}
104+
105+
106+
public void addAggregation(AbstractAggregationBuilder aggregationBuilder) {
107+
if (aggregations == null) {
108+
aggregations = new ArrayList<AbstractAggregationBuilder>();
109+
}
110+
aggregations.add(aggregationBuilder);
111+
}
112+
113+
public void setAggregations(List<AbstractAggregationBuilder> aggregations) {
114+
this.aggregations = aggregations;
115+
}
97116
}

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

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import org.elasticsearch.action.search.SearchType;
2424
import org.elasticsearch.index.query.FilterBuilder;
2525
import org.elasticsearch.index.query.QueryBuilder;
26+
import org.elasticsearch.search.aggregations.AbstractAggregationBuilder;
2627
import org.elasticsearch.search.highlight.HighlightBuilder;
2728
import org.elasticsearch.search.sort.SortBuilder;
2829
import org.springframework.data.domain.Pageable;
@@ -42,6 +43,7 @@ public class NativeSearchQueryBuilder {
4243
private FilterBuilder filterBuilder;
4344
private List<SortBuilder> sortBuilders = new ArrayList<SortBuilder>();
4445
private List<FacetRequest> facetRequests = new ArrayList<FacetRequest>();
46+
private List<AbstractAggregationBuilder> aggregationBuilders = new ArrayList<AbstractAggregationBuilder>();
4547
private HighlightBuilder.Field[] highlightFields;
4648
private Pageable pageable;
4749
private String[] indices;
@@ -67,6 +69,11 @@ public NativeSearchQueryBuilder withSort(SortBuilder sortBuilder) {
6769
return this;
6870
}
6971

72+
public NativeSearchQueryBuilder addAggregation(AbstractAggregationBuilder aggregationBuilder){
73+
this.aggregationBuilders.add(aggregationBuilder);
74+
return this;
75+
}
76+
7077
public NativeSearchQueryBuilder withFacet(FacetRequest facetRequest) {
7178
facetRequests.add(facetRequest);
7279
return this;
@@ -139,6 +146,10 @@ public NativeSearchQuery build() {
139146
nativeSearchQuery.setFacets(facetRequests);
140147
}
141148

149+
if (CollectionUtils.isNotEmpty(aggregationBuilders)) {
150+
nativeSearchQuery.setAggregations(aggregationBuilders);
151+
}
152+
142153
if (minScore > 0) {
143154
nativeSearchQuery.setMinScore(minScore);
144155
}

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
import org.elasticsearch.index.query.FilterBuilder;
2121
import org.elasticsearch.index.query.QueryBuilder;
22+
import org.elasticsearch.search.aggregations.AbstractAggregationBuilder;
2223
import org.elasticsearch.search.highlight.HighlightBuilder;
2324
import org.elasticsearch.search.sort.SortBuilder;
2425
import org.springframework.data.elasticsearch.core.facet.FacetRequest;
@@ -40,5 +41,7 @@ public interface SearchQuery extends Query {
4041

4142
List<FacetRequest> getFacets();
4243

44+
List<AbstractAggregationBuilder> getAggregations();
45+
4346
HighlightBuilder.Field[] getHighlightFields();
4447
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
/*
2+
* Copyright 2013 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.springframework.data.elasticsearch.core.aggregation;
17+
18+
import org.elasticsearch.action.search.SearchResponse;
19+
import org.elasticsearch.search.aggregations.Aggregations;
20+
import org.junit.Before;
21+
import org.junit.Test;
22+
import org.junit.runner.RunWith;
23+
import org.springframework.beans.factory.annotation.Autowired;
24+
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
25+
import org.springframework.data.elasticsearch.core.ResultsExtractor;
26+
import org.springframework.data.elasticsearch.core.facet.ArticleEntity;
27+
import org.springframework.data.elasticsearch.core.facet.ArticleEntityBuilder;
28+
import org.springframework.data.elasticsearch.core.query.IndexQuery;
29+
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
30+
import org.springframework.data.elasticsearch.core.query.SearchQuery;
31+
import org.springframework.test.context.ContextConfiguration;
32+
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
33+
34+
import static org.elasticsearch.action.search.SearchType.COUNT;
35+
import static org.elasticsearch.index.query.QueryBuilders.matchAllQuery;
36+
import static org.elasticsearch.search.aggregations.AggregationBuilders.terms;
37+
import static org.hamcrest.Matchers.is;
38+
import static org.hamcrest.Matchers.notNullValue;
39+
import static org.junit.Assert.assertThat;
40+
41+
/**
42+
* @author Rizwan Idrees
43+
* @author Mohsin Husen
44+
* @author Jonathan Yan
45+
* @author Artur Konczak
46+
*/
47+
@RunWith(SpringJUnit4ClassRunner.class)
48+
@ContextConfiguration("classpath:elasticsearch-template-test.xml")
49+
public class ElasticsearchTemplateAggregationTests {
50+
51+
public static final String RIZWAN_IDREES = "Rizwan Idrees";
52+
public static final String MOHSIN_HUSEN = "Mohsin Husen";
53+
public static final String JONATHAN_YAN = "Jonathan Yan";
54+
public static final String ARTUR_KONCZAK = "Artur Konczak";
55+
public static final int YEAR_2002 = 2002;
56+
public static final int YEAR_2001 = 2001;
57+
public static final int YEAR_2000 = 2000;
58+
@Autowired
59+
private ElasticsearchTemplate elasticsearchTemplate;
60+
61+
@Before
62+
public void before() {
63+
elasticsearchTemplate.deleteIndex(ArticleEntity.class);
64+
elasticsearchTemplate.createIndex(ArticleEntity.class);
65+
elasticsearchTemplate.putMapping(ArticleEntity.class);
66+
elasticsearchTemplate.refresh(ArticleEntity.class, true);
67+
68+
IndexQuery article1 = new ArticleEntityBuilder("1").title("article four").subject("computing").addAuthor(RIZWAN_IDREES).addAuthor(ARTUR_KONCZAK).addAuthor(MOHSIN_HUSEN).addAuthor(JONATHAN_YAN).score(10).buildIndex();
69+
IndexQuery article2 = new ArticleEntityBuilder("2").title("article three").subject("computing").addAuthor(RIZWAN_IDREES).addAuthor(ARTUR_KONCZAK).addAuthor(MOHSIN_HUSEN).addPublishedYear(YEAR_2000).score(20).buildIndex();
70+
IndexQuery article3 = new ArticleEntityBuilder("3").title("article two").subject("computing").addAuthor(RIZWAN_IDREES).addAuthor(ARTUR_KONCZAK).addPublishedYear(YEAR_2001).addPublishedYear(YEAR_2000).score(30).buildIndex();
71+
IndexQuery article4 = new ArticleEntityBuilder("4").title("article one").subject("accounting").addAuthor(RIZWAN_IDREES).addPublishedYear(YEAR_2002).addPublishedYear(YEAR_2001).addPublishedYear(YEAR_2000).score(40).buildIndex();
72+
73+
elasticsearchTemplate.index(article1);
74+
elasticsearchTemplate.index(article2);
75+
elasticsearchTemplate.index(article3);
76+
elasticsearchTemplate.index(article4);
77+
elasticsearchTemplate.refresh(ArticleEntity.class, true);
78+
}
79+
80+
@Test
81+
public void shouldReturnAggregatedResponseForGivenSearchQuery() {
82+
// given
83+
SearchQuery searchQuery = new NativeSearchQueryBuilder()
84+
.withQuery(matchAllQuery())
85+
.withSearchType(COUNT)
86+
.withIndices("articles").withTypes("article")
87+
.addAggregation(terms("subjects").field("subject"))
88+
.build();
89+
// when
90+
Aggregations aggregations = elasticsearchTemplate.query(searchQuery, new ResultsExtractor<Aggregations>() {
91+
@Override
92+
public Aggregations extract(SearchResponse response) {
93+
return response.getAggregations();
94+
}
95+
});
96+
// then
97+
assertThat(aggregations, is(notNullValue()));
98+
assertThat(aggregations.asMap().get("subjects"), is(notNullValue()));
99+
}
100+
101+
}
102+
103+

0 commit comments

Comments
 (0)