mirror of
https://github.com/spring-projects/spring-data-elasticsearch.git
synced 2025-06-23 12:32:10 +00:00
Created AggregatedPage to hold the Aggregations
Create AggregatedPage and populate it in the DefaultResultMapper.
This commit is contained in:
parent
8c77d314aa
commit
fd06f8efd7
@ -25,22 +25,22 @@ import java.util.Collection;
|
|||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.core.JsonEncoding;
|
||||||
|
import com.fasterxml.jackson.core.JsonFactory;
|
||||||
|
import com.fasterxml.jackson.core.JsonGenerator;
|
||||||
import org.apache.commons.lang.StringUtils;
|
import org.apache.commons.lang.StringUtils;
|
||||||
import org.elasticsearch.action.get.GetResponse;
|
import org.elasticsearch.action.get.GetResponse;
|
||||||
import org.elasticsearch.action.get.MultiGetItemResponse;
|
import org.elasticsearch.action.get.MultiGetItemResponse;
|
||||||
import org.elasticsearch.action.get.MultiGetResponse;
|
import org.elasticsearch.action.get.MultiGetResponse;
|
||||||
import org.elasticsearch.action.search.SearchResponse;
|
import org.elasticsearch.action.search.SearchResponse;
|
||||||
import com.fasterxml.jackson.core.JsonEncoding;
|
|
||||||
import com.fasterxml.jackson.core.JsonFactory;
|
|
||||||
import com.fasterxml.jackson.core.JsonGenerator;
|
|
||||||
import org.elasticsearch.search.SearchHit;
|
import org.elasticsearch.search.SearchHit;
|
||||||
import org.elasticsearch.search.SearchHitField;
|
import org.elasticsearch.search.SearchHitField;
|
||||||
import org.springframework.data.domain.Page;
|
import org.springframework.data.domain.Page;
|
||||||
import org.springframework.data.domain.PageImpl;
|
|
||||||
import org.springframework.data.domain.Pageable;
|
import org.springframework.data.domain.Pageable;
|
||||||
import org.springframework.data.elasticsearch.ElasticsearchException;
|
import org.springframework.data.elasticsearch.ElasticsearchException;
|
||||||
import org.springframework.data.elasticsearch.annotations.Document;
|
import org.springframework.data.elasticsearch.annotations.Document;
|
||||||
import org.springframework.data.elasticsearch.annotations.ScriptedField;
|
import org.springframework.data.elasticsearch.annotations.ScriptedField;
|
||||||
|
import org.springframework.data.elasticsearch.core.domain.impl.AggregatedPageImpl;
|
||||||
import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentEntity;
|
import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentEntity;
|
||||||
import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentProperty;
|
import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentProperty;
|
||||||
import org.springframework.data.mapping.PersistentProperty;
|
import org.springframework.data.mapping.PersistentProperty;
|
||||||
@ -48,6 +48,7 @@ import org.springframework.data.mapping.context.MappingContext;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Artur Konczak
|
* @author Artur Konczak
|
||||||
|
* @author Petar Tahchiev
|
||||||
*/
|
*/
|
||||||
public class DefaultResultMapper extends AbstractResultMapper {
|
public class DefaultResultMapper extends AbstractResultMapper {
|
||||||
|
|
||||||
@ -86,38 +87,39 @@ public class DefaultResultMapper extends AbstractResultMapper {
|
|||||||
result = mapEntity(hit.getFields().values(), clazz);
|
result = mapEntity(hit.getFields().values(), clazz);
|
||||||
}
|
}
|
||||||
setPersistentEntityId(result, hit.getId(), clazz);
|
setPersistentEntityId(result, hit.getId(), clazz);
|
||||||
populateScriptFields(result, hit);
|
populateScriptFields(result, hit);
|
||||||
results.add(result);
|
results.add(result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return new PageImpl<T>(results, pageable, totalHits);
|
|
||||||
|
return new AggregatedPageImpl<T>(results, pageable, totalHits, response.getAggregations());
|
||||||
}
|
}
|
||||||
|
|
||||||
private <T> void populateScriptFields(T result, SearchHit hit) {
|
private <T> void populateScriptFields(T result, SearchHit hit) {
|
||||||
if (hit.getFields() != null && !hit.getFields().isEmpty() && result != null) {
|
if (hit.getFields() != null && !hit.getFields().isEmpty() && result != null) {
|
||||||
for (java.lang.reflect.Field field : result.getClass().getDeclaredFields()) {
|
for (java.lang.reflect.Field field : result.getClass().getDeclaredFields()) {
|
||||||
ScriptedField scriptedField = field.getAnnotation(ScriptedField.class);
|
ScriptedField scriptedField = field.getAnnotation(ScriptedField.class);
|
||||||
if (scriptedField != null) {
|
if (scriptedField != null) {
|
||||||
String name = scriptedField.name().isEmpty() ? field.getName() : scriptedField.name();
|
String name = scriptedField.name().isEmpty() ? field.getName() : scriptedField.name();
|
||||||
SearchHitField searchHitField = hit.getFields().get(name);
|
SearchHitField searchHitField = hit.getFields().get(name);
|
||||||
if (searchHitField != null) {
|
if (searchHitField != null) {
|
||||||
field.setAccessible(true);
|
field.setAccessible(true);
|
||||||
try {
|
try {
|
||||||
field.set(result, searchHitField.getValue());
|
field.set(result, searchHitField.getValue());
|
||||||
} catch (IllegalArgumentException e) {
|
} catch (IllegalArgumentException e) {
|
||||||
throw new ElasticsearchException("failed to set scripted field: " + name + " with value: "
|
throw new ElasticsearchException("failed to set scripted field: " + name + " with value: "
|
||||||
+ searchHitField.getValue(), e);
|
+ searchHitField.getValue(), e);
|
||||||
} catch (IllegalAccessException e) {
|
} catch (IllegalAccessException e) {
|
||||||
throw new ElasticsearchException("failed to access scripted field: " + name, e);
|
throw new ElasticsearchException("failed to access scripted field: " + name, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private <T> T mapEntity(Collection<SearchHitField> values, Class<T> clazz) {
|
private <T> T mapEntity(Collection<SearchHitField> values, Class<T> clazz) {
|
||||||
return mapEntity(buildJSONFromFields(values), clazz);
|
return mapEntity(buildJSONFromFields(values), clazz);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,9 +18,11 @@ package org.springframework.data.elasticsearch.core;
|
|||||||
import org.elasticsearch.action.search.SearchResponse;
|
import org.elasticsearch.action.search.SearchResponse;
|
||||||
import org.springframework.data.domain.Page;
|
import org.springframework.data.domain.Page;
|
||||||
import org.springframework.data.domain.Pageable;
|
import org.springframework.data.domain.Pageable;
|
||||||
|
import org.springframework.data.elasticsearch.core.domain.AggregatedPage;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Artur Konczak
|
* @author Artur Konczak
|
||||||
|
* @author Petar Tahchiev
|
||||||
*/
|
*/
|
||||||
public interface SearchResultMapper {
|
public interface SearchResultMapper {
|
||||||
|
|
||||||
|
@ -0,0 +1,16 @@
|
|||||||
|
package org.springframework.data.elasticsearch.core.domain;
|
||||||
|
|
||||||
|
import org.elasticsearch.search.aggregations.Aggregation;
|
||||||
|
import org.elasticsearch.search.aggregations.Aggregations;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Petar Tahchiev
|
||||||
|
*/
|
||||||
|
public interface AggregatedPage<T> {
|
||||||
|
|
||||||
|
boolean hasAggregations();
|
||||||
|
|
||||||
|
Aggregations getAggregations();
|
||||||
|
|
||||||
|
Aggregation getAggregation(String name);
|
||||||
|
}
|
@ -0,0 +1,53 @@
|
|||||||
|
package org.springframework.data.elasticsearch.core.domain.impl;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.elasticsearch.search.aggregations.Aggregation;
|
||||||
|
import org.elasticsearch.search.aggregations.Aggregations;
|
||||||
|
import org.springframework.data.domain.PageImpl;
|
||||||
|
import org.springframework.data.domain.Pageable;
|
||||||
|
import org.springframework.data.elasticsearch.core.domain.AggregatedPage;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Petar Tahchiev
|
||||||
|
*/
|
||||||
|
public class AggregatedPageImpl<T> extends PageImpl<T> implements AggregatedPage<T> {
|
||||||
|
|
||||||
|
private Aggregations aggregations;
|
||||||
|
private Map<String, Aggregation> mapOfAggregations = new HashMap<String, Aggregation>();
|
||||||
|
|
||||||
|
public AggregatedPageImpl(List<T> content) {
|
||||||
|
super(content);
|
||||||
|
}
|
||||||
|
|
||||||
|
public AggregatedPageImpl(List<T> content, Pageable pageable, long total) {
|
||||||
|
super(content, pageable, total);
|
||||||
|
}
|
||||||
|
|
||||||
|
public AggregatedPageImpl(List<T> content, Pageable pageable, long total, Aggregations aggregations) {
|
||||||
|
super(content, pageable, total);
|
||||||
|
this.aggregations = aggregations;
|
||||||
|
if (aggregations != null) {
|
||||||
|
for (Aggregation aggregation : aggregations) {
|
||||||
|
mapOfAggregations.put(aggregation.getName(), aggregation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasAggregations() {
|
||||||
|
return aggregations != null && mapOfAggregations.size() > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Aggregations getAggregations() {
|
||||||
|
return aggregations;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Aggregation getAggregation(String name) {
|
||||||
|
return aggregations == null ? null : aggregations.get(name);
|
||||||
|
}
|
||||||
|
}
|
@ -19,9 +19,7 @@ import static org.hamcrest.Matchers.*;
|
|||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.*;
|
||||||
import static org.mockito.Mockito.*;
|
import static org.mockito.Mockito.*;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.*;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.util.ArrayIterator;
|
import com.fasterxml.jackson.databind.util.ArrayIterator;
|
||||||
import org.elasticsearch.action.get.GetResponse;
|
import org.elasticsearch.action.get.GetResponse;
|
||||||
@ -29,12 +27,15 @@ import org.elasticsearch.action.search.SearchResponse;
|
|||||||
import org.elasticsearch.search.SearchHit;
|
import org.elasticsearch.search.SearchHit;
|
||||||
import org.elasticsearch.search.SearchHitField;
|
import org.elasticsearch.search.SearchHitField;
|
||||||
import org.elasticsearch.search.SearchHits;
|
import org.elasticsearch.search.SearchHits;
|
||||||
|
import org.elasticsearch.search.aggregations.Aggregation;
|
||||||
|
import org.elasticsearch.search.aggregations.Aggregations;
|
||||||
import org.elasticsearch.search.internal.InternalSearchHitField;
|
import org.elasticsearch.search.internal.InternalSearchHitField;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.mockito.Mock;
|
import org.mockito.Mock;
|
||||||
import org.mockito.MockitoAnnotations;
|
import org.mockito.MockitoAnnotations;
|
||||||
import org.springframework.data.domain.Page;
|
import org.springframework.data.domain.Page;
|
||||||
|
import org.springframework.data.elasticsearch.core.domain.AggregatedPage;
|
||||||
import org.springframework.data.elasticsearch.entities.Car;
|
import org.springframework.data.elasticsearch.entities.Car;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -54,6 +55,31 @@ public class DefaultResultMapperTests {
|
|||||||
resultMapper = new DefaultResultMapper();
|
resultMapper = new DefaultResultMapper();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldMapAggregationsToPage() {
|
||||||
|
//Given
|
||||||
|
SearchHit[] hits = {createCarHit("Ford", "Grat"), createCarHit("BMW", "Arrow")};
|
||||||
|
SearchHits searchHits = mock(SearchHits.class);
|
||||||
|
when(searchHits.totalHits()).thenReturn(2L);
|
||||||
|
when(searchHits.iterator()).thenReturn(new ArrayIterator(hits));
|
||||||
|
when(response.getHits()).thenReturn(searchHits);
|
||||||
|
|
||||||
|
Aggregation aggregationToReturn = createCarAggregation();
|
||||||
|
Aggregations aggregations = mock(Aggregations.class);
|
||||||
|
Iterator<Aggregation> iter = Collections.singletonList(aggregationToReturn).iterator();
|
||||||
|
|
||||||
|
when(aggregations.iterator()).thenReturn(iter);
|
||||||
|
when(aggregations.get("engine")).thenReturn(aggregationToReturn);
|
||||||
|
when(response.getAggregations()).thenReturn(aggregations);
|
||||||
|
|
||||||
|
//When
|
||||||
|
AggregatedPage<Car> page = (AggregatedPage<Car>) resultMapper.mapResults(response, Car.class, null);
|
||||||
|
|
||||||
|
//Then
|
||||||
|
assertThat(page.hasAggregations(), is(true));
|
||||||
|
assertThat(page.getAggregation("engine").getName(), is("Diesel"));
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void shouldMapSearchRequestToPage() {
|
public void shouldMapSearchRequestToPage() {
|
||||||
//Given
|
//Given
|
||||||
@ -105,6 +131,12 @@ public class DefaultResultMapperTests {
|
|||||||
assertThat(result.getName(), is("Ford"));
|
assertThat(result.getName(), is("Ford"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Aggregation createCarAggregation() {
|
||||||
|
Aggregation aggregation = mock(Aggregation.class);
|
||||||
|
when(aggregation.getName()).thenReturn("Diesel");
|
||||||
|
return aggregation;
|
||||||
|
}
|
||||||
|
|
||||||
private SearchHit createCarHit(String name, String model) {
|
private SearchHit createCarHit(String name, String model) {
|
||||||
SearchHit hit = mock(SearchHit.class);
|
SearchHit hit = mock(SearchHit.class);
|
||||||
when(hit.sourceAsString()).thenReturn(createJsonCar(name, model));
|
when(hit.sourceAsString()).thenReturn(createJsonCar(name, model));
|
||||||
|
Loading…
x
Reference in New Issue
Block a user