From 99a30a2a4b35598ff39375f06f5b3e0ea89c3bb3 Mon Sep 17 00:00:00 2001 From: Mohsin Husen Date: Wed, 7 Aug 2013 10:15:06 +0100 Subject: [PATCH] DATAES-17 : Add support to retrieve highlighted text in search result --- .../core/ElasticsearchTemplate.java | 7 +++ .../core/query/NativeSearchQuery.java | 15 +++++- .../core/query/NativeSearchQueryBuilder.java | 9 +++- .../elasticsearch/core/query/SearchQuery.java | 4 +- .../data/elasticsearch/SampleEntity.java | 9 ++++ .../core/ElasticsearchTemplateTests.java | 53 ++++++++++++++++++- 6 files changed, 93 insertions(+), 4 deletions(-) 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 570c5bb12..3b8d57cb8 100644 --- a/src/main/java/org/springframework/data/elasticsearch/core/ElasticsearchTemplate.java +++ b/src/main/java/org/springframework/data/elasticsearch/core/ElasticsearchTemplate.java @@ -40,6 +40,7 @@ import org.elasticsearch.index.query.QueryBuilder; import org.elasticsearch.search.SearchHit; import org.elasticsearch.search.facet.Facet; import org.elasticsearch.search.facet.FacetBuilder; +import org.elasticsearch.search.highlight.HighlightBuilder; import org.elasticsearch.search.sort.SortOrder; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; @@ -388,6 +389,12 @@ public class ElasticsearchTemplate implements ElasticsearchOperations { } } + if(searchQuery.getHighlightFields() != null) { + for(HighlightBuilder.Field highlightField : searchQuery.getHighlightFields()){ + searchRequest.addHighlightedField(highlightField); + } + } + return searchRequest.setQuery(searchQuery.getQuery()).execute().actionGet(); } 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 46f80e264..0b4ca5121 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 @@ -17,7 +17,7 @@ package org.springframework.data.elasticsearch.core.query; import org.elasticsearch.index.query.FilterBuilder; import org.elasticsearch.index.query.QueryBuilder; -import org.elasticsearch.search.facet.FacetBuilder; +import org.elasticsearch.search.highlight.HighlightBuilder; import org.elasticsearch.search.sort.SortBuilder; import org.springframework.data.elasticsearch.core.facet.FacetRequest; @@ -37,6 +37,7 @@ public class NativeSearchQuery extends AbstractQuery implements SearchQuery { private FilterBuilder filter; private SortBuilder sort; private List facets; + private HighlightBuilder.Field[] highlightFields; public NativeSearchQuery(QueryBuilder query) { @@ -54,6 +55,13 @@ public class NativeSearchQuery extends AbstractQuery implements SearchQuery { this.sort = sort; } + public NativeSearchQuery(QueryBuilder query, FilterBuilder filter, SortBuilder sort, HighlightBuilder.Field[] highlightFields) { + this.query = query; + this.filter = filter; + this.sort = sort; + this.highlightFields = highlightFields; + } + public QueryBuilder getQuery() { return query; } @@ -64,6 +72,11 @@ public class NativeSearchQuery extends AbstractQuery implements SearchQuery { public SortBuilder getElasticsearchSort() { return sort; + } + + @Override + public HighlightBuilder.Field[] getHighlightFields() { + return highlightFields; } public void addFacet(FacetRequest facetRequest){ 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 6d8e354c4..db667a245 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 @@ -18,6 +18,7 @@ package org.springframework.data.elasticsearch.core.query; import org.apache.commons.collections.CollectionUtils; import org.elasticsearch.index.query.FilterBuilder; import org.elasticsearch.index.query.QueryBuilder; +import org.elasticsearch.search.highlight.HighlightBuilder; import org.elasticsearch.search.sort.SortBuilder; import org.springframework.data.domain.Pageable; import org.springframework.data.elasticsearch.core.facet.FacetRequest; @@ -39,6 +40,7 @@ public class NativeSearchQueryBuilder { private FilterBuilder filterBuilder; private SortBuilder sortBuilder; private List facetRequests = new ArrayList(); + private HighlightBuilder.Field[] highlightFields; private Pageable pageable; private String[] indices; private String[] types; @@ -64,6 +66,11 @@ public class NativeSearchQueryBuilder { return this; } + public NativeSearchQueryBuilder withHighlightFields(HighlightBuilder.Field... highlightFields){ + this.highlightFields = highlightFields; + return this; + } + public NativeSearchQueryBuilder withPageable(Pageable pageable) { this.pageable = pageable; return this; @@ -85,7 +92,7 @@ public class NativeSearchQueryBuilder { } public NativeSearchQuery build() { - NativeSearchQuery nativeSearchQuery = new NativeSearchQuery(queryBuilder, filterBuilder, sortBuilder); + NativeSearchQuery nativeSearchQuery = new NativeSearchQuery(queryBuilder, filterBuilder, sortBuilder, 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 21a925073..2d823d720 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 @@ -17,7 +17,7 @@ package org.springframework.data.elasticsearch.core.query; import org.elasticsearch.index.query.FilterBuilder; import org.elasticsearch.index.query.QueryBuilder; -import org.elasticsearch.search.facet.FacetBuilder; +import org.elasticsearch.search.highlight.HighlightBuilder; import org.elasticsearch.search.sort.SortBuilder; import org.springframework.data.elasticsearch.core.facet.FacetRequest; @@ -38,4 +38,6 @@ public interface SearchQuery extends Query { SortBuilder getElasticsearchSort(); List getFacets(); + + HighlightBuilder.Field[] getHighlightFields(); } diff --git a/src/test/java/org/springframework/data/elasticsearch/SampleEntity.java b/src/test/java/org/springframework/data/elasticsearch/SampleEntity.java index dc890d840..aceb9588a 100644 --- a/src/test/java/org/springframework/data/elasticsearch/SampleEntity.java +++ b/src/test/java/org/springframework/data/elasticsearch/SampleEntity.java @@ -34,6 +34,7 @@ public class SampleEntity { private String message; private int rate; private boolean available; + private String highlightedMessage; @Version private Long version; @@ -77,6 +78,14 @@ public class SampleEntity { this.available = available; } + public String getHighlightedMessage() { + return highlightedMessage; + } + + public void setHighlightedMessage(String highlightedMessage) { + this.highlightedMessage = highlightedMessage; + } + public Long getVersion() { return version; } 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 9171fa592..7bdad91dd 100644 --- a/src/test/java/org/springframework/data/elasticsearch/core/ElasticsearchTemplateTests.java +++ b/src/test/java/org/springframework/data/elasticsearch/core/ElasticsearchTemplateTests.java @@ -19,6 +19,7 @@ import org.elasticsearch.action.index.IndexRequest; import org.elasticsearch.action.search.SearchResponse; import org.elasticsearch.index.engine.DocumentMissingException; import org.elasticsearch.search.SearchHit; +import org.elasticsearch.search.highlight.HighlightBuilder; import org.elasticsearch.search.sort.FieldSortBuilder; import org.elasticsearch.search.sort.SortOrder; import org.junit.Before; @@ -27,7 +28,6 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Page; -import org.springframework.data.domain.PageImpl; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Sort; import org.springframework.data.elasticsearch.SampleEntity; @@ -44,6 +44,7 @@ import static org.elasticsearch.index.query.FilterBuilders.boolFilter; import static org.elasticsearch.index.query.FilterBuilders.termFilter; import static org.elasticsearch.index.query.QueryBuilders.fieldQuery; import static org.elasticsearch.index.query.QueryBuilders.matchAllQuery; +import static org.elasticsearch.index.query.QueryBuilders.termQuery; import static org.hamcrest.Matchers.*; import static org.junit.Assert.*; @@ -778,4 +779,54 @@ public class ElasticsearchTemplateTests { assertThat(indexedEntity.getMessage(), is(message)); } + @Test + public void shouldReturnHighlightedFieldsForGivenQueryAndFields(){ + + //given + String documentId = randomNumeric(5); + String actualMessage = "some test message"; + String highlightedMessage = "some test message"; + + SampleEntity sampleEntity = new SampleEntity(); + sampleEntity.setId(documentId); + sampleEntity.setMessage(actualMessage); + sampleEntity.setVersion(System.currentTimeMillis()); + + IndexQuery indexQuery = new IndexQuery(); + indexQuery.setId(documentId); + indexQuery.setObject(sampleEntity); + + elasticsearchTemplate.index(indexQuery); + elasticsearchTemplate.refresh(SampleEntity.class, true); + + SearchQuery searchQuery = new NativeSearchQueryBuilder() + .withQuery(termQuery("message", "test")) + .withHighlightFields(new HighlightBuilder.Field("message")) + .build(); + + Page sampleEntities = elasticsearchTemplate.queryForPage(searchQuery, new ResultsMapper() { + @Override + public FacetedPage mapResults(SearchResponse response) { + List chunk = new ArrayList(); + for (SearchHit searchHit : response.getHits()) { + if (response.getHits().getHits().length <= 0) { + return null; + } + SampleEntity user = new SampleEntity(); + user.setId(searchHit.getId()); + user.setMessage((String) searchHit.getSource().get("message")); + user.setHighlightedMessage(searchHit.getHighlightFields().get("message").fragments()[0].toString()); + chunk.add(user); + } + if(chunk.size() > 0){ + return new FacetedPageImpl(chunk); + } + return null; + } + }); + + assertThat(sampleEntities.getContent().get(0).getHighlightedMessage(), is(highlightedMessage)); + + } + }