diff --git a/src/main/java/org/elasticsearch/search/highlight/HighlightBuilder.java b/src/main/java/org/elasticsearch/search/highlight/HighlightBuilder.java index 74d444abcb8..4e0ccc65fa6 100644 --- a/src/main/java/org/elasticsearch/search/highlight/HighlightBuilder.java +++ b/src/main/java/org/elasticsearch/search/highlight/HighlightBuilder.java @@ -202,7 +202,7 @@ public class HighlightBuilder implements ToXContent { } /** - * Allows to set custom options for custom highlighters + * Allows to set custom options for custom highlighters. */ public HighlightBuilder options(Map options) { this.options = options; @@ -243,6 +243,12 @@ public class HighlightBuilder implements ToXContent { builder.startObject("fields"); for (Field field : fields) { builder.startObject(field.name()); + if (field.preTags != null) { + builder.field("pre_tags", field.preTags); + } + if (field.postTags != null) { + builder.field("post_tags", field.postTags); + } if (field.fragmentSize != -1) { builder.field("fragment_size", field.fragmentSize); } @@ -252,9 +258,21 @@ public class HighlightBuilder implements ToXContent { if (field.fragmentOffset != -1) { builder.field("fragment_offset", field.fragmentOffset); } + if (field.highlightFilter != null) { + builder.field("highlight_filter", field.highlightFilter); + } + if (field.order != null) { + builder.field("order", field.order); + } if (field.requireFieldMatch != null) { builder.field("require_field_match", field.requireFieldMatch); } + if (field.boundaryMaxScan != -1) { + builder.field("boundary_max_scan", field.boundaryMaxScan); + } + if (field.boundaryChars != null) { + builder.field("boundary_chars", field.boundaryChars); + } if (field.highlighterType != null) { builder.field("type", field.highlighterType); } @@ -276,10 +294,16 @@ public class HighlightBuilder implements ToXContent { public static class Field { final String name; + String[] preTags; + String[] postTags; int fragmentSize = -1; int fragmentOffset = -1; int numOfFragments = -1; + Boolean highlightFilter; + String order; Boolean requireFieldMatch; + int boundaryMaxScan = -1; + char[] boundaryChars; String highlighterType; String fragmenter; Map options; @@ -292,6 +316,24 @@ public class HighlightBuilder implements ToXContent { return name; } + /** + * Explicitly set the pre tags for this field that will be used for highlighting. + * This overrides global settings set by {@link HighlightBuilder#preTags(String...)}. + */ + public Field preTags(String... preTags) { + this.preTags = preTags; + return this; + } + + /** + * Explicitly set the post tags for this field that will be used for highlighting. + * This overrides global settings set by {@link HighlightBuilder#postTags(String...)}. + */ + public Field postTags(String... postTags) { + this.postTags = postTags; + return this; + } + public Field fragmentSize(int fragmentSize) { this.fragmentSize = fragmentSize; return this; @@ -307,21 +349,61 @@ public class HighlightBuilder implements ToXContent { return this; } + public Field highlightFilter(boolean highlightFilter) { + this.highlightFilter = highlightFilter; + return this; + } + + /** + * The order of fragments per field. By default, ordered by the order in the + * highlighted text. Can be score, which then it will be ordered + * by score of the fragments. + * This overrides global settings set by {@link HighlightBuilder#order(String)}. + */ + public Field order(String order) { + this.order = order; + return this; + } + public Field requireFieldMatch(boolean requireFieldMatch) { this.requireFieldMatch = requireFieldMatch; return this; } + public Field boundaryMaxScan(int boundaryMaxScan) { + this.boundaryMaxScan = boundaryMaxScan; + return this; + } + + public Field boundaryChars(char[] boundaryChars) { + this.boundaryChars = boundaryChars; + return this; + } + + /** + * Set type of highlighter to use. Supported types + * are highlighter and fast-vector-highlighter. + * This overrides global settings set by {@link HighlightBuilder#highlighterType(String)}. + */ public Field highlighterType(String highlighterType) { this.highlighterType = highlighterType; return this; } + /** + * Sets what fragmenter to use to break up text that is eligible for highlighting. + * This option is only applicable when using plain / normal highlighter. + * This overrides global settings set by {@link HighlightBuilder#fragmenter(String)}. + */ public Field fragmenter(String fragmenter) { this.fragmenter = fragmenter; return this; } + /** + * Allows to set custom options for custom highlighters. + * This overrides global settings set by {@link HighlightBuilder#options(Map)}. + */ public Field options(Map options) { this.options = options; return this; diff --git a/src/test/java/org/elasticsearch/test/integration/search/highlight/HighlighterSearchTests.java b/src/test/java/org/elasticsearch/test/integration/search/highlight/HighlighterSearchTests.java index 18e6f0651ff..5271a19e329 100644 --- a/src/test/java/org/elasticsearch/test/integration/search/highlight/HighlighterSearchTests.java +++ b/src/test/java/org/elasticsearch/test/integration/search/highlight/HighlighterSearchTests.java @@ -540,9 +540,33 @@ public class HighlighterSearchTests extends AbstractSharedClusterTest { assertThat(search.getHits().hits()[0].highlightFields().get("titleTV").fragments()[1].string(), equalTo("highlight other text")); } + @Test + public void testGlobalHighlightingSettingsOverriddenAtFieldLevel() { + client().admin().indices().prepareCreate("test").execute().actionGet(); + client().admin().cluster().prepareHealth("test").setWaitForGreenStatus().execute().actionGet(); + + client().prepareIndex("test", "type1") + .setSource("field1", "this is a test", "field2", "this is another test") + .setRefresh(true).execute().actionGet(); + + logger.info("--> highlighting and searching on field1 and field2 produces different tags"); + SearchSourceBuilder source = searchSource() + .query(termQuery("field1", "test")) + .from(0).size(60).explain(true) + .highlight(highlight().order("score").preTags("").postTags("") + .field(new HighlightBuilder.Field("field1")) + .field(new HighlightBuilder.Field("field2").preTags("").postTags(""))); + + SearchResponse searchResponse = client().search(searchRequest("test").source(source).searchType(QUERY_THEN_FETCH).scroll(timeValueMinutes(10))).actionGet(); + assertThat("Failures " + Arrays.toString(searchResponse.getShardFailures()), searchResponse.getShardFailures().length, equalTo(0)); + assertThat(searchResponse.getHits().totalHits(), equalTo(1l)); + + assertThat(searchResponse.getHits().getAt(0).highlightFields().get("field1").fragments()[0].string(), equalTo("this is a test")); + assertThat(searchResponse.getHits().getAt(0).highlightFields().get("field2").fragments()[0].string(), equalTo("this is another test")); + } + @Test public void testHighlightingOnWildcardFields() throws Exception { - client().admin().indices().prepareDelete().execute().actionGet(); client().admin().indices().prepareCreate("test").execute().actionGet(); client().admin().cluster().prepareHealth("test").setWaitForGreenStatus().execute().actionGet();