Skip to content

Commit fd06f8e

Browse files
Petar Tahchievakonczak
authored andcommitted
Created AggregatedPage to hold the Aggregations
Create AggregatedPage and populate it in the DefaultResultMapper.
1 parent 8c77d31 commit fd06f8e

File tree

5 files changed

+139
-34
lines changed

5 files changed

+139
-34
lines changed

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

Lines changed: 33 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -25,29 +25,30 @@
2525
import java.util.LinkedList;
2626
import java.util.List;
2727

28+
import com.fasterxml.jackson.core.JsonEncoding;
29+
import com.fasterxml.jackson.core.JsonFactory;
30+
import com.fasterxml.jackson.core.JsonGenerator;
2831
import org.apache.commons.lang.StringUtils;
2932
import org.elasticsearch.action.get.GetResponse;
3033
import org.elasticsearch.action.get.MultiGetItemResponse;
3134
import org.elasticsearch.action.get.MultiGetResponse;
3235
import org.elasticsearch.action.search.SearchResponse;
33-
import com.fasterxml.jackson.core.JsonEncoding;
34-
import com.fasterxml.jackson.core.JsonFactory;
35-
import com.fasterxml.jackson.core.JsonGenerator;
3636
import org.elasticsearch.search.SearchHit;
3737
import org.elasticsearch.search.SearchHitField;
3838
import org.springframework.data.domain.Page;
39-
import org.springframework.data.domain.PageImpl;
4039
import org.springframework.data.domain.Pageable;
4140
import org.springframework.data.elasticsearch.ElasticsearchException;
4241
import org.springframework.data.elasticsearch.annotations.Document;
4342
import org.springframework.data.elasticsearch.annotations.ScriptedField;
43+
import org.springframework.data.elasticsearch.core.domain.impl.AggregatedPageImpl;
4444
import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentEntity;
4545
import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentProperty;
4646
import org.springframework.data.mapping.PersistentProperty;
4747
import org.springframework.data.mapping.context.MappingContext;
4848

4949
/**
5050
* @author Artur Konczak
51+
* @author Petar Tahchiev
5152
*/
5253
public class DefaultResultMapper extends AbstractResultMapper {
5354

@@ -86,38 +87,39 @@ public <T> Page<T> mapResults(SearchResponse response, Class<T> clazz, Pageable
8687
result = mapEntity(hit.getFields().values(), clazz);
8788
}
8889
setPersistentEntityId(result, hit.getId(), clazz);
89-
populateScriptFields(result, hit);
90+
populateScriptFields(result, hit);
9091
results.add(result);
9192
}
9293
}
93-
return new PageImpl<T>(results, pageable, totalHits);
94+
95+
return new AggregatedPageImpl<T>(results, pageable, totalHits, response.getAggregations());
96+
}
97+
98+
private <T> void populateScriptFields(T result, SearchHit hit) {
99+
if (hit.getFields() != null && !hit.getFields().isEmpty() && result != null) {
100+
for (java.lang.reflect.Field field : result.getClass().getDeclaredFields()) {
101+
ScriptedField scriptedField = field.getAnnotation(ScriptedField.class);
102+
if (scriptedField != null) {
103+
String name = scriptedField.name().isEmpty() ? field.getName() : scriptedField.name();
104+
SearchHitField searchHitField = hit.getFields().get(name);
105+
if (searchHitField != null) {
106+
field.setAccessible(true);
107+
try {
108+
field.set(result, searchHitField.getValue());
109+
} catch (IllegalArgumentException e) {
110+
throw new ElasticsearchException("failed to set scripted field: " + name + " with value: "
111+
+ searchHitField.getValue(), e);
112+
} catch (IllegalAccessException e) {
113+
throw new ElasticsearchException("failed to access scripted field: " + name, e);
114+
}
115+
}
116+
}
117+
}
118+
}
94119
}
95120

96-
private <T> void populateScriptFields(T result, SearchHit hit) {
97-
if (hit.getFields() != null && !hit.getFields().isEmpty() && result != null) {
98-
for (java.lang.reflect.Field field : result.getClass().getDeclaredFields()) {
99-
ScriptedField scriptedField = field.getAnnotation(ScriptedField.class);
100-
if (scriptedField != null) {
101-
String name = scriptedField.name().isEmpty() ? field.getName() : scriptedField.name();
102-
SearchHitField searchHitField = hit.getFields().get(name);
103-
if (searchHitField != null) {
104-
field.setAccessible(true);
105-
try {
106-
field.set(result, searchHitField.getValue());
107-
} catch (IllegalArgumentException e) {
108-
throw new ElasticsearchException("failed to set scripted field: " + name + " with value: "
109-
+ searchHitField.getValue(), e);
110-
} catch (IllegalAccessException e) {
111-
throw new ElasticsearchException("failed to access scripted field: " + name, e);
112-
}
113-
}
114-
}
115-
}
116-
}
117-
}
118-
119-
120-
private <T> T mapEntity(Collection<SearchHitField> values, Class<T> clazz) {
121+
122+
private <T> T mapEntity(Collection<SearchHitField> values, Class<T> clazz) {
121123
return mapEntity(buildJSONFromFields(values), clazz);
122124
}
123125

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,11 @@
1818
import org.elasticsearch.action.search.SearchResponse;
1919
import org.springframework.data.domain.Page;
2020
import org.springframework.data.domain.Pageable;
21+
import org.springframework.data.elasticsearch.core.domain.AggregatedPage;
2122

2223
/**
2324
* @author Artur Konczak
25+
* @author Petar Tahchiev
2426
*/
2527
public interface SearchResultMapper {
2628

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package org.springframework.data.elasticsearch.core.domain;
2+
3+
import org.elasticsearch.search.aggregations.Aggregation;
4+
import org.elasticsearch.search.aggregations.Aggregations;
5+
6+
/**
7+
* @author Petar Tahchiev
8+
*/
9+
public interface AggregatedPage<T> {
10+
11+
boolean hasAggregations();
12+
13+
Aggregations getAggregations();
14+
15+
Aggregation getAggregation(String name);
16+
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
package org.springframework.data.elasticsearch.core.domain.impl;
2+
3+
import java.util.HashMap;
4+
import java.util.List;
5+
import java.util.Map;
6+
7+
import org.elasticsearch.search.aggregations.Aggregation;
8+
import org.elasticsearch.search.aggregations.Aggregations;
9+
import org.springframework.data.domain.PageImpl;
10+
import org.springframework.data.domain.Pageable;
11+
import org.springframework.data.elasticsearch.core.domain.AggregatedPage;
12+
13+
/**
14+
* @author Petar Tahchiev
15+
*/
16+
public class AggregatedPageImpl<T> extends PageImpl<T> implements AggregatedPage<T> {
17+
18+
private Aggregations aggregations;
19+
private Map<String, Aggregation> mapOfAggregations = new HashMap<String, Aggregation>();
20+
21+
public AggregatedPageImpl(List<T> content) {
22+
super(content);
23+
}
24+
25+
public AggregatedPageImpl(List<T> content, Pageable pageable, long total) {
26+
super(content, pageable, total);
27+
}
28+
29+
public AggregatedPageImpl(List<T> content, Pageable pageable, long total, Aggregations aggregations) {
30+
super(content, pageable, total);
31+
this.aggregations = aggregations;
32+
if (aggregations != null) {
33+
for (Aggregation aggregation : aggregations) {
34+
mapOfAggregations.put(aggregation.getName(), aggregation);
35+
}
36+
}
37+
}
38+
39+
@Override
40+
public boolean hasAggregations() {
41+
return aggregations != null && mapOfAggregations.size() > 0;
42+
}
43+
44+
@Override
45+
public Aggregations getAggregations() {
46+
return aggregations;
47+
}
48+
49+
@Override
50+
public Aggregation getAggregation(String name) {
51+
return aggregations == null ? null : aggregations.get(name);
52+
}
53+
}

src/test/java/org/springframework/data/elasticsearch/core/DefaultResultMapperTests.java

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,22 +19,23 @@
1919
import static org.junit.Assert.*;
2020
import static org.mockito.Mockito.*;
2121

22-
import java.util.Arrays;
23-
import java.util.HashMap;
24-
import java.util.Map;
22+
import java.util.*;
2523

2624
import com.fasterxml.jackson.databind.util.ArrayIterator;
2725
import org.elasticsearch.action.get.GetResponse;
2826
import org.elasticsearch.action.search.SearchResponse;
2927
import org.elasticsearch.search.SearchHit;
3028
import org.elasticsearch.search.SearchHitField;
3129
import org.elasticsearch.search.SearchHits;
30+
import org.elasticsearch.search.aggregations.Aggregation;
31+
import org.elasticsearch.search.aggregations.Aggregations;
3232
import org.elasticsearch.search.internal.InternalSearchHitField;
3333
import org.junit.Before;
3434
import org.junit.Test;
3535
import org.mockito.Mock;
3636
import org.mockito.MockitoAnnotations;
3737
import org.springframework.data.domain.Page;
38+
import org.springframework.data.elasticsearch.core.domain.AggregatedPage;
3839
import org.springframework.data.elasticsearch.entities.Car;
3940

4041
/**
@@ -54,6 +55,31 @@ public void init() {
5455
resultMapper = new DefaultResultMapper();
5556
}
5657

58+
@Test
59+
public void shouldMapAggregationsToPage() {
60+
//Given
61+
SearchHit[] hits = {createCarHit("Ford", "Grat"), createCarHit("BMW", "Arrow")};
62+
SearchHits searchHits = mock(SearchHits.class);
63+
when(searchHits.totalHits()).thenReturn(2L);
64+
when(searchHits.iterator()).thenReturn(new ArrayIterator(hits));
65+
when(response.getHits()).thenReturn(searchHits);
66+
67+
Aggregation aggregationToReturn = createCarAggregation();
68+
Aggregations aggregations = mock(Aggregations.class);
69+
Iterator<Aggregation> iter = Collections.singletonList(aggregationToReturn).iterator();
70+
71+
when(aggregations.iterator()).thenReturn(iter);
72+
when(aggregations.get("engine")).thenReturn(aggregationToReturn);
73+
when(response.getAggregations()).thenReturn(aggregations);
74+
75+
//When
76+
AggregatedPage<Car> page = (AggregatedPage<Car>) resultMapper.mapResults(response, Car.class, null);
77+
78+
//Then
79+
assertThat(page.hasAggregations(), is(true));
80+
assertThat(page.getAggregation("engine").getName(), is("Diesel"));
81+
}
82+
5783
@Test
5884
public void shouldMapSearchRequestToPage() {
5985
//Given
@@ -105,6 +131,12 @@ public void shouldMapGetRequestToObject() {
105131
assertThat(result.getName(), is("Ford"));
106132
}
107133

134+
private Aggregation createCarAggregation() {
135+
Aggregation aggregation = mock(Aggregation.class);
136+
when(aggregation.getName()).thenReturn("Diesel");
137+
return aggregation;
138+
}
139+
108140
private SearchHit createCarHit(String name, String model) {
109141
SearchHit hit = mock(SearchHit.class);
110142
when(hit.sourceAsString()).thenReturn(createJsonCar(name, model));

0 commit comments

Comments
 (0)