diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/SearchDocumentationIT.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/SearchDocumentationIT.java index 5b6ad3a334d..0baf708d3b5 100644 --- a/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/SearchDocumentationIT.java +++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/SearchDocumentationIT.java @@ -33,6 +33,7 @@ import org.elasticsearch.action.support.IndicesOptions; import org.elasticsearch.action.support.WriteRequest; import org.elasticsearch.client.ESRestHighLevelClientTestCase; import org.elasticsearch.client.RestHighLevelClient; +import org.elasticsearch.common.text.Text; import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.common.xcontent.XContentType; import org.elasticsearch.index.query.QueryBuilders; @@ -49,6 +50,8 @@ import org.elasticsearch.search.aggregations.bucket.terms.Terms.Bucket; import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder; import org.elasticsearch.search.aggregations.metrics.avg.Avg; import org.elasticsearch.search.builder.SearchSourceBuilder; +import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder; +import org.elasticsearch.search.fetch.subphase.highlight.HighlightField; import org.elasticsearch.search.sort.ScoreSortBuilder; import org.elasticsearch.search.sort.SortOrder; import org.elasticsearch.search.suggest.Suggest; @@ -65,6 +68,7 @@ import java.util.Map; import java.util.concurrent.TimeUnit; import static org.elasticsearch.index.query.QueryBuilders.matchQuery; +import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.greaterThan; /** @@ -330,6 +334,69 @@ public class SearchDocumentationIT extends ESRestHighLevelClientTestCase { } } + public void testSearchRequestHighlighting() throws IOException { + RestHighLevelClient client = highLevelClient(); + { + BulkRequest request = new BulkRequest(); + request.add(new IndexRequest("posts", "doc", "1") + .source(XContentType.JSON, "title", "In which order are my Elasticsearch queries executed?", "user", + Arrays.asList("kimchy", "luca"), "innerObject", Collections.singletonMap("key", "value"))); + request.add(new IndexRequest("posts", "doc", "2") + .source(XContentType.JSON, "title", "Current status and upcoming changes in Elasticsearch", "user", + Arrays.asList("kimchy", "christoph"), "innerObject", Collections.singletonMap("key", "value"))); + request.add(new IndexRequest("posts", "doc", "3") + .source(XContentType.JSON, "title", "The Future of Federated Search in Elasticsearch", "user", + Arrays.asList("kimchy", "tanguy"), "innerObject", Collections.singletonMap("key", "value"))); + request.setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE); + BulkResponse bulkResponse = client.bulk(request); + assertSame(bulkResponse.status(), RestStatus.OK); + assertFalse(bulkResponse.hasFailures()); + } + { + SearchRequest searchRequest = new SearchRequest(); + // tag::search-request-highlighting + SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder(); + HighlightBuilder highlightBuilder = new HighlightBuilder(); // <1> + HighlightBuilder.Field highlightTitle = + new HighlightBuilder.Field("title"); // <2> + highlightTitle.highlighterType("unified"); // <3> + highlightBuilder.field(highlightTitle); // <4> + HighlightBuilder.Field highlightUser = new HighlightBuilder.Field("user"); + highlightBuilder.field(highlightUser); + searchSourceBuilder.highlighter(highlightBuilder); + // end::search-request-highlighting + searchSourceBuilder.query(QueryBuilders.boolQuery() + .should(matchQuery("title", "Elasticsearch")) + .should(matchQuery("user", "kimchy"))); + searchRequest.source(searchSourceBuilder); + SearchResponse searchResponse = client.search(searchRequest); + { + // tag::search-request-highlighting-get + SearchHits hits = searchResponse.getHits(); + for (SearchHit hit : hits.getHits()) { + Map highlightFields = hit.getHighlightFields(); + HighlightField highlight = highlightFields.get("title"); // <1> + Text[] fragments = highlight.fragments(); // <2> + String fragmentString = fragments[0].string(); + } + // end::search-request-highlighting-get + hits = searchResponse.getHits(); + for (SearchHit hit : hits.getHits()) { + Map highlightFields = hit.getHighlightFields(); + HighlightField highlight = highlightFields.get("title"); + Text[] fragments = highlight.fragments(); + assertEquals(1, fragments.length); + assertThat(fragments[0].string(), containsString("Elasticsearch")); + highlight = highlightFields.get("user"); + fragments = highlight.fragments(); + assertEquals(1, fragments.length); + assertThat(fragments[0].string(), containsString("kimchy")); + } + } + + } + } + public void testScroll() throws IOException { RestHighLevelClient client = highLevelClient(); { diff --git a/docs/java-rest/high-level/apis/search.asciidoc b/docs/java-rest/high-level/apis/search.asciidoc index 1ccf1566ae3..5ad1c82048e 100644 --- a/docs/java-rest/high-level/apis/search.asciidoc +++ b/docs/java-rest/high-level/apis/search.asciidoc @@ -82,6 +82,28 @@ After this, the `SearchSourceBuilder` only needs to be added to the include-tagged::{doc-tests}/SearchDocumentationIT.java[search-source-setter] -------------------------------------------------- +[[java-rest-high-request-highlighting]] +===== Requesting Highlighting + +Highlighting search results can be achieved by setting a `HighlightBuilder` on the +`SearchSourceBuilder`. Different highlighting behaviour can be defined for each +fields by adding one or more `HighlightBuilder.Field` instances to a `HighlightBuilder`. + +["source","java",subs="attributes,callouts,macros"] +-------------------------------------------------- +include-tagged::{doc-tests}/SearchDocumentationIT.java[search-request-highlighting] +-------------------------------------------------- +<1> Creates a new `HighlightBuilder` +<2> Create a field highlighter for the `title` field +<3> Set the field highlighter type +<4> Add the field highlighter to the highlight builder + +There are many options which are explained in detail in the Rest API documentation. The Rest +API parameters (e.g. `pre_tags`) are usually changed by +setters with a similar name (e.g. `#preTags(String ...)`). + +Highlighted text fragments can <> from the `SearchResponse`. + ===== Requesting Aggregations Aggregations can be added to the search by first creating the appropriate @@ -110,7 +132,7 @@ include-tagged::{doc-tests}/SearchDocumentationIT.java[search-request-suggestion the text `kmichy` <2> Adds the suggestion builder and names it `suggest_user` -We will later see how to <> from the +We will later see how to <> from the `SearchResponse`. [[java-rest-high-document-search-sync]] @@ -210,6 +232,21 @@ cases need to be cast accordingly: include-tagged::{doc-tests}/SearchDocumentationIT.java[search-hits-singleHit-source] -------------------------------------------------- +[[java-rest-high-retrieve-highlighting]] +===== Retrieving Highlighting + +If <>, highlighted text fragments can be retrieved from each `SearchHit` in the result. The hit object offers +access to a map of field names to `HighlightField` instances, each of which contains one +or many highlighted text fragments: + + +["source","java",subs="attributes,callouts,macros"] +-------------------------------------------------- +include-tagged::{doc-tests}/SearchDocumentationIT.java[search-request-highlighting-get] +-------------------------------------------------- +<1> Get the highlighting for the `title` field +<2> Get one or many fragments containing the highlighted field content + [[java-rest-high-retrieve-aggs]] ===== Retrieving Aggregations