diff --git a/server/src/main/java/org/elasticsearch/search/fetch/subphase/highlight/UnifiedHighlighter.java b/server/src/main/java/org/elasticsearch/search/fetch/subphase/highlight/UnifiedHighlighter.java index 35064def777..e5f406e430a 100644 --- a/server/src/main/java/org/elasticsearch/search/fetch/subphase/highlight/UnifiedHighlighter.java +++ b/server/src/main/java/org/elasticsearch/search/fetch/subphase/highlight/UnifiedHighlighter.java @@ -67,7 +67,7 @@ public class UnifiedHighlighter implements Highlighter { final int maxAnalyzedOffset = context.getIndexSettings().getHighlightMaxAnalyzedOffset(); List snippets = new ArrayList<>(); - int numberOfFragments; + int numberOfFragments = field.fieldOptions().numberOfFragments(); try { final Analyzer analyzer = getAnalyzer(context.getMapperService().documentMapper(hitContext.hit().getType()), @@ -90,14 +90,16 @@ public class UnifiedHighlighter implements Highlighter { "This maximum can be set by changing the [" + IndexSettings.MAX_ANALYZED_OFFSET_SETTING.getKey() + "] index level setting. " + "For large texts, indexing with offsets or term vectors is recommended!"); } - if (field.fieldOptions().numberOfFragments() == 0) { + if (numberOfFragments == 0 + // non-tokenized fields should not use any break iterator (ignore boundaryScannerType) + || fieldType.tokenized() == false) { // we use a control char to separate values, which is the only char that the custom break iterator // breaks the text on, so we don't lose the distinction between the different values of a field and we // get back a snippet per value CustomSeparatorBreakIterator breakIterator = new CustomSeparatorBreakIterator(MULTIVAL_SEP_CHAR); highlighter = new CustomUnifiedHighlighter(searcher, analyzer, offsetSource, passageFormatter, field.fieldOptions().boundaryScannerLocale(), breakIterator, fieldValue, field.fieldOptions().noMatchSize()); - numberOfFragments = fieldValues.size(); // we are highlighting the whole content, one snippet per value + numberOfFragments = numberOfFragments == 0 ? fieldValues.size() : numberOfFragments; } else { //using paragraph separator we make sure that each field value holds a discrete passage for highlighting BreakIterator bi = getBreakIterator(field); diff --git a/server/src/test/java/org/elasticsearch/search/fetch/subphase/highlight/HighlighterSearchIT.java b/server/src/test/java/org/elasticsearch/search/fetch/subphase/highlight/HighlighterSearchIT.java index 1467fd1f097..dc045044e6f 100644 --- a/server/src/test/java/org/elasticsearch/search/fetch/subphase/highlight/HighlighterSearchIT.java +++ b/server/src/test/java/org/elasticsearch/search/fetch/subphase/highlight/HighlighterSearchIT.java @@ -121,6 +121,35 @@ public class HighlighterSearchIT extends ESIntegTestCase { return Arrays.asList(InternalSettingsPlugin.class, MockKeywordPlugin.class, MockAnalysisPlugin.class); } + public void testHighlightingWithKeywordIgnoreBoundaryScanner() throws IOException { + XContentBuilder mappings = jsonBuilder(); + mappings.startObject(); + mappings.startObject("type") + .startObject("properties") + .startObject("tags") + .field("type", "keyword") + .endObject() + .endObject().endObject(); + mappings.endObject(); + assertAcked(prepareCreate("test") + .addMapping("type", mappings)); + client().prepareIndex("test").setId("1") + .setSource(jsonBuilder().startObject().array("tags", "foo bar", "foo bar", "foo bar", "foo baz").endObject()) + .get(); + client().prepareIndex("test").setId("2") + .setSource(jsonBuilder().startObject().array("tags", "foo baz", "foo baz", "foo baz", "foo bar").endObject()) + .get(); + refresh(); + + for (BoundaryScannerType scanner : BoundaryScannerType.values()) { + SearchResponse search = client().prepareSearch().setQuery(matchQuery("tags", "foo bar")) + .highlighter(new HighlightBuilder().field(new Field("tags")).numOfFragments(2).boundaryScannerType(scanner)).get(); + assertHighlight(search, 0, "tags", 0, 2, equalTo("foo bar")); + assertHighlight(search, 0, "tags", 1, 2, equalTo("foo bar")); + assertHighlight(search, 1, "tags", 0, 1, equalTo("foo bar")); + } + } + public void testHighlightingWithStoredKeyword() throws IOException { XContentBuilder mappings = jsonBuilder(); mappings.startObject();