diff --git a/src/main/java/org/springframework/data/elasticsearch/core/ElasticsearchTemplate.java b/src/main/java/org/springframework/data/elasticsearch/core/ElasticsearchTemplate.java index 7c78cfa22..b82969477 100644 --- a/src/main/java/org/springframework/data/elasticsearch/core/ElasticsearchTemplate.java +++ b/src/main/java/org/springframework/data/elasticsearch/core/ElasticsearchTemplate.java @@ -57,6 +57,7 @@ import org.elasticsearch.index.query.QueryBuilders; import org.elasticsearch.search.SearchHit; import org.elasticsearch.search.facet.FacetBuilder; import org.elasticsearch.search.highlight.HighlightBuilder; +import org.elasticsearch.search.sort.SortBuilder; import org.elasticsearch.search.sort.SortOrder; import org.springframework.data.domain.Page; import org.springframework.data.domain.Sort; @@ -451,8 +452,10 @@ public class ElasticsearchTemplate implements ElasticsearchOperations { searchRequest.setPostFilter(searchQuery.getFilter()); } - if (searchQuery.getElasticsearchSort() != null) { - searchRequest.addSort(searchQuery.getElasticsearchSort()); + if (CollectionUtils.isNotEmpty(searchQuery.getElasticsearchSorts())) { + for (SortBuilder sort : searchQuery.getElasticsearchSorts()) { + searchRequest.addSort(sort); + } } if (CollectionUtils.isNotEmpty(searchQuery.getFacets())) { diff --git a/src/main/java/org/springframework/data/elasticsearch/core/query/NativeSearchQuery.java b/src/main/java/org/springframework/data/elasticsearch/core/query/NativeSearchQuery.java index f668829b0..55b2687b7 100644 --- a/src/main/java/org/springframework/data/elasticsearch/core/query/NativeSearchQuery.java +++ b/src/main/java/org/springframework/data/elasticsearch/core/query/NativeSearchQuery.java @@ -35,7 +35,7 @@ public class NativeSearchQuery extends AbstractQuery implements SearchQuery { private QueryBuilder query; private FilterBuilder filter; - private SortBuilder sort; + private List sorts; private List facets; private HighlightBuilder.Field[] highlightFields; @@ -49,16 +49,16 @@ public class NativeSearchQuery extends AbstractQuery implements SearchQuery { this.filter = filter; } - public NativeSearchQuery(QueryBuilder query, FilterBuilder filter, SortBuilder sort) { + public NativeSearchQuery(QueryBuilder query, FilterBuilder filter, List sorts) { this.query = query; this.filter = filter; - this.sort = sort; + this.sorts = sorts; } - public NativeSearchQuery(QueryBuilder query, FilterBuilder filter, SortBuilder sort, HighlightBuilder.Field[] highlightFields) { + public NativeSearchQuery(QueryBuilder query, FilterBuilder filter, List sorts, HighlightBuilder.Field[] highlightFields) { this.query = query; this.filter = filter; - this.sort = sort; + this.sorts = sorts; this.highlightFields = highlightFields; } @@ -70,8 +70,8 @@ public class NativeSearchQuery extends AbstractQuery implements SearchQuery { return filter; } - public SortBuilder getElasticsearchSort() { - return sort; + public List getElasticsearchSorts() { + return sorts; } @Override diff --git a/src/main/java/org/springframework/data/elasticsearch/core/query/NativeSearchQueryBuilder.java b/src/main/java/org/springframework/data/elasticsearch/core/query/NativeSearchQueryBuilder.java index dfb896d5f..ca8e1c139 100644 --- a/src/main/java/org/springframework/data/elasticsearch/core/query/NativeSearchQueryBuilder.java +++ b/src/main/java/org/springframework/data/elasticsearch/core/query/NativeSearchQueryBuilder.java @@ -38,7 +38,7 @@ public class NativeSearchQueryBuilder { private QueryBuilder queryBuilder; private FilterBuilder filterBuilder; - private SortBuilder sortBuilder; + private List sortBuilders = new ArrayList(); private List facetRequests = new ArrayList(); private HighlightBuilder.Field[] highlightFields; private Pageable pageable; @@ -58,7 +58,7 @@ public class NativeSearchQueryBuilder { } public NativeSearchQueryBuilder withSort(SortBuilder sortBuilder) { - this.sortBuilder = sortBuilder; + this.sortBuilders.add(sortBuilder); return this; } @@ -98,7 +98,7 @@ public class NativeSearchQueryBuilder { } public NativeSearchQuery build() { - NativeSearchQuery nativeSearchQuery = new NativeSearchQuery(queryBuilder, filterBuilder, sortBuilder, highlightFields); + NativeSearchQuery nativeSearchQuery = new NativeSearchQuery(queryBuilder, filterBuilder, sortBuilders, highlightFields); if (pageable != null) { nativeSearchQuery.setPageable(pageable); } diff --git a/src/main/java/org/springframework/data/elasticsearch/core/query/SearchQuery.java b/src/main/java/org/springframework/data/elasticsearch/core/query/SearchQuery.java index 80ed5f126..e96b99ed3 100644 --- a/src/main/java/org/springframework/data/elasticsearch/core/query/SearchQuery.java +++ b/src/main/java/org/springframework/data/elasticsearch/core/query/SearchQuery.java @@ -36,7 +36,7 @@ public interface SearchQuery extends Query { FilterBuilder getFilter(); - SortBuilder getElasticsearchSort(); + List getElasticsearchSorts(); List getFacets(); diff --git a/src/test/java/org/springframework/data/elasticsearch/core/ElasticsearchTemplateTests.java b/src/test/java/org/springframework/data/elasticsearch/core/ElasticsearchTemplateTests.java index 223674a26..7f9451d11 100644 --- a/src/test/java/org/springframework/data/elasticsearch/core/ElasticsearchTemplateTests.java +++ b/src/test/java/org/springframework/data/elasticsearch/core/ElasticsearchTemplateTests.java @@ -322,6 +322,64 @@ public class ElasticsearchTemplateTests { assertThat(sampleEntities.getContent().get(0).getRate(), is(sampleEntity2.getRate())); } + @Test + public void shouldSortResultsGivenMultipleSortCriteria() { + // given + List indexQueries = new ArrayList(); + // first document + String documentId = randomNumeric(5); + SampleEntity sampleEntity1 = new SampleEntity(); + sampleEntity1.setId(documentId); + sampleEntity1.setMessage("abc"); + sampleEntity1.setRate(15); + sampleEntity1.setVersion(System.currentTimeMillis()); + + IndexQuery indexQuery1 = new IndexQuery(); + indexQuery1.setId(documentId); + indexQuery1.setObject(sampleEntity1); + + // second document + String documentId2 = randomNumeric(5); + SampleEntity sampleEntity2 = new SampleEntity(); + sampleEntity2.setId(documentId2); + sampleEntity2.setMessage("xyz"); + sampleEntity2.setRate(5); + sampleEntity2.setVersion(System.currentTimeMillis()); + + IndexQuery indexQuery2 = new IndexQuery(); + indexQuery2.setId(documentId2); + indexQuery2.setObject(sampleEntity2); + + // third document + String documentId3 = randomNumeric(5); + SampleEntity sampleEntity3 = new SampleEntity(); + sampleEntity3.setId(documentId3); + sampleEntity3.setMessage("xyz"); + sampleEntity3.setRate(15); + sampleEntity3.setVersion(System.currentTimeMillis()); + + IndexQuery indexQuery3 = new IndexQuery(); + indexQuery3.setId(documentId3); + indexQuery3.setObject(sampleEntity3); + + indexQueries.add(indexQuery1); + indexQueries.add(indexQuery2); + indexQueries.add(indexQuery3); + + elasticsearchTemplate.bulkIndex(indexQueries); + elasticsearchTemplate.refresh(SampleEntity.class, true); + + SearchQuery searchQuery = new NativeSearchQueryBuilder().withQuery(matchAllQuery()) + .withSort(new FieldSortBuilder("rate").ignoreUnmapped(true).order(SortOrder.ASC)) + .withSort(new FieldSortBuilder("message").ignoreUnmapped(true).order(SortOrder.ASC)).build(); + // when + Page sampleEntities = elasticsearchTemplate.queryForPage(searchQuery, SampleEntity.class); + // then + assertThat(sampleEntities.getTotalElements(), equalTo(3L)); + assertThat(sampleEntities.getContent().get(0).getRate(), is(sampleEntity2.getRate())); + assertThat(sampleEntities.getContent().get(1).getMessage(), is(sampleEntity1.getMessage())); + } + @Test public void shouldExecuteStringQuery() { // given