Browse Source

Merge pull request #15324 from cbuescher/highlight-builder-searchContextHighlight

Enable HighlightBuilder to create SearchContextHighlight
Christoph Büscher 9 years ago
parent
commit
79cdc40afe

+ 4 - 4
core/src/main/java/org/elasticsearch/search/highlight/AbstractHighlighterBuilder.java

@@ -125,7 +125,7 @@ public abstract class AbstractHighlighterBuilder<HB extends AbstractHighlighterB
     }
 
     /**
-     * Set the fragment size in characters, defaults to {@link HighlighterParseElement#DEFAULT_FRAGMENT_CHAR_SIZE}
+     * Set the fragment size in characters, defaults to {@link HighlightBuilder#DEFAULT_FRAGMENT_CHAR_SIZE}
      */
     @SuppressWarnings("unchecked")
     public HB fragmentSize(Integer fragmentSize) {
@@ -141,7 +141,7 @@ public abstract class AbstractHighlighterBuilder<HB extends AbstractHighlighterB
     }
 
     /**
-     * Set the number of fragments, defaults to {@link HighlighterParseElement#DEFAULT_NUMBER_OF_FRAGMENTS}
+     * Set the number of fragments, defaults to {@link HighlightBuilder#DEFAULT_NUMBER_OF_FRAGMENTS}
      */
     @SuppressWarnings("unchecked")
     public HB numOfFragments(Integer numOfFragments) {
@@ -428,7 +428,7 @@ public abstract class AbstractHighlighterBuilder<HB extends AbstractHighlighterB
     }
 
     /**
-     * internal hashCode calculation to overwrite for the implementing classes.
+     * fields only present in subclass should contribute to hashCode in the implementation
      */
     protected abstract int doHashCode();
 
@@ -462,7 +462,7 @@ public abstract class AbstractHighlighterBuilder<HB extends AbstractHighlighterB
     }
 
     /**
-     * internal equals to overwrite for the implementing classes.
+     * fields only present in subclass should be checked for equality in the implementation
      */
     protected abstract boolean doEquals(HB other);
 

+ 139 - 5
core/src/main/java/org/elasticsearch/search/highlight/HighlightBuilder.java

@@ -19,6 +19,8 @@
 
 package org.elasticsearch.search.highlight;
 
+import org.apache.lucene.search.Query;
+import org.apache.lucene.search.vectorhighlight.SimpleBoundaryScanner;
 import org.elasticsearch.ExceptionsHelper;
 import org.elasticsearch.common.ParsingException;
 import org.elasticsearch.common.io.stream.StreamInput;
@@ -28,13 +30,20 @@ import org.elasticsearch.common.xcontent.ToXContent;
 import org.elasticsearch.common.xcontent.XContentBuilder;
 import org.elasticsearch.common.xcontent.XContentFactory;
 import org.elasticsearch.common.xcontent.XContentParser;
+import org.elasticsearch.index.query.QueryBuilder;
 import org.elasticsearch.index.query.QueryParseContext;
-
+import org.elasticsearch.index.query.QueryShardContext;
+import org.elasticsearch.search.highlight.SearchContextHighlight.FieldOptions;
+import org.elasticsearch.search.highlight.SearchContextHighlight.FieldOptions.Builder;
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Objects;
+import java.util.Set;
 
 /**
  * A builder for search highlighting. Settings can control how large fields
@@ -48,6 +57,51 @@ public class HighlightBuilder extends AbstractHighlighterBuilder<HighlightBuilde
 
     public static final String HIGHLIGHT_ELEMENT_NAME = "highlight";
 
+    /** default for whether to highlight fields based on the source even if stored separately */
+    public static final boolean DEFAULT_FORCE_SOURCE = false;
+    /** default for whether a field should be highlighted only if a query matches that field */
+    public static final boolean DEFAULT_REQUIRE_FIELD_MATCH = true;
+    /** default for whether <tt>fvh</tt> should provide highlighting on filter clauses */
+    public static final boolean DEFAULT_HIGHLIGHT_FILTER = false;
+    /** default for highlight fragments being ordered by score */
+    public static final boolean DEFAULT_SCORE_ORDERED = false;
+    /** the default encoder setting */
+    public static final String DEFAULT_ENCODER = "default";
+    /** default for the maximum number of phrases the fvh will consider */
+    public static final int DEFAULT_PHRASE_LIMIT = 256;
+    /** default for fragment size when there are no matches */
+    public static final int DEFAULT_NO_MATCH_SIZE = 0;
+    /** the default number of fragments for highlighting */
+    public static final int DEFAULT_NUMBER_OF_FRAGMENTS = 5;
+    /** the default number of fragments size in characters */
+    public static final int DEFAULT_FRAGMENT_CHAR_SIZE = 100;
+    /** the default opening tag  */
+    public static final String[] DEFAULT_PRE_TAGS = new String[]{"<em>"};
+    /** the default closing tag  */
+    public static final String[] DEFAULT_POST_TAGS = new String[]{"</em>"};
+
+    /** the default opening tags when <tt>tag_schema = "styled"</tt>  */
+    public static final String[] DEFAULT_STYLED_PRE_TAG = {
+            "<em class=\"hlt1\">", "<em class=\"hlt2\">", "<em class=\"hlt3\">",
+            "<em class=\"hlt4\">", "<em class=\"hlt5\">", "<em class=\"hlt6\">",
+            "<em class=\"hlt7\">", "<em class=\"hlt8\">", "<em class=\"hlt9\">",
+            "<em class=\"hlt10\">"
+    };
+    /** the default closing tags when <tt>tag_schema = "styled"</tt>  */
+    public static final String[] DEFAULT_STYLED_POST_TAGS = {"</em>"};
+
+    /**
+     * a {@link FieldOptions.Builder} with default settings
+     */
+    public final static Builder defaultFieldOptions() {
+        return new SearchContextHighlight.FieldOptions.Builder()
+                .preTags(DEFAULT_PRE_TAGS).postTags(DEFAULT_POST_TAGS).scoreOrdered(DEFAULT_SCORE_ORDERED).highlightFilter(DEFAULT_HIGHLIGHT_FILTER)
+                .requireFieldMatch(DEFAULT_REQUIRE_FIELD_MATCH).forceSource(DEFAULT_FORCE_SOURCE).fragmentCharSize(DEFAULT_FRAGMENT_CHAR_SIZE).numberOfFragments(DEFAULT_NUMBER_OF_FRAGMENTS)
+                .encoder(DEFAULT_ENCODER).boundaryMaxScan(SimpleBoundaryScanner.DEFAULT_MAX_SCAN)
+                .boundaryChars(SimpleBoundaryScanner.DEFAULT_BOUNDARY_CHARS)
+                .noMatchSize(DEFAULT_NO_MATCH_SIZE).phraseLimit(DEFAULT_PHRASE_LIMIT);
+    }
+
     private final List<Field> fields = new ArrayList<>();
 
     private String encoder;
@@ -120,12 +174,12 @@ public class HighlightBuilder extends AbstractHighlighterBuilder<HighlightBuilde
     public HighlightBuilder tagsSchema(String schemaName) {
         switch (schemaName) {
         case "default":
-            preTags(HighlighterParseElement.DEFAULT_PRE_TAGS);
-            postTags(HighlighterParseElement.DEFAULT_POST_TAGS);
+            preTags(DEFAULT_PRE_TAGS);
+            postTags(DEFAULT_POST_TAGS);
             break;
         case "styled":
-            preTags(HighlighterParseElement.STYLED_PRE_TAG);
-            postTags(HighlighterParseElement.STYLED_POST_TAGS);
+            preTags(DEFAULT_STYLED_PRE_TAG);
+            postTags(DEFAULT_STYLED_POST_TAGS);
             break;
         default:
             throw new IllegalArgumentException("Unknown tag schema ["+ schemaName +"]");
@@ -289,7 +343,87 @@ public class HighlightBuilder extends AbstractHighlighterBuilder<HighlightBuilde
         return highlightBuilder;
     }
 
+    public SearchContextHighlight build(QueryShardContext context) throws IOException {
+        // create template global options that are later merged with any partial field options
+        final SearchContextHighlight.FieldOptions.Builder globalOptionsBuilder = new SearchContextHighlight.FieldOptions.Builder();
+        globalOptionsBuilder.encoder(this.encoder);
+        transferOptions(this, globalOptionsBuilder, context);
+
+        // overwrite unset global options by default values
+        globalOptionsBuilder.merge(defaultFieldOptions().build());
+
+        // create field options
+        Collection<org.elasticsearch.search.highlight.SearchContextHighlight.Field> fieldOptions = new ArrayList<>();
+        for (Field field : this.fields) {
+            final SearchContextHighlight.FieldOptions.Builder fieldOptionsBuilder = new SearchContextHighlight.FieldOptions.Builder();
+            fieldOptionsBuilder.fragmentOffset(field.fragmentOffset);
+            if (field.matchedFields != null) {
+                Set<String> matchedFields = new HashSet<String>(field.matchedFields.length);
+                Collections.addAll(matchedFields, field.matchedFields);
+                fieldOptionsBuilder.matchedFields(matchedFields);
+            }
+            transferOptions(field, fieldOptionsBuilder, context);
+            fieldOptions.add(new SearchContextHighlight.Field(field.name(), fieldOptionsBuilder.merge(globalOptionsBuilder.build()).build()));
+        }
+        return new SearchContextHighlight(fieldOptions);
+    }
 
+    /**
+     * Transfers field options present in the input {@link AbstractHighlighterBuilder} to the receiving
+     * {@link FieldOptions.Builder}, effectively overwriting existing settings
+     * @param targetOptionsBuilder the receiving options builder
+     * @param highlighterBuilder highlight builder with the input options
+     * @param context needed to convert {@link QueryBuilder} to {@link Query}
+     * @throws IOException on errors parsing any optional nested highlight query
+     */
+    @SuppressWarnings({ "rawtypes", "unchecked" })
+    private static void transferOptions(AbstractHighlighterBuilder highlighterBuilder, SearchContextHighlight.FieldOptions.Builder targetOptionsBuilder, QueryShardContext context) throws IOException {
+        targetOptionsBuilder.preTags(highlighterBuilder.preTags);
+        targetOptionsBuilder.postTags(highlighterBuilder.postTags);
+        targetOptionsBuilder.scoreOrdered("score".equals(highlighterBuilder.order));
+        if (highlighterBuilder.highlightFilter != null) {
+            targetOptionsBuilder.highlightFilter(highlighterBuilder.highlightFilter);
+        }
+        if (highlighterBuilder.fragmentSize != null) {
+            targetOptionsBuilder.fragmentCharSize(highlighterBuilder.fragmentSize);
+        }
+        if (highlighterBuilder.numOfFragments != null) {
+            targetOptionsBuilder.numberOfFragments(highlighterBuilder.numOfFragments);
+        }
+        if (highlighterBuilder.requireFieldMatch != null) {
+            targetOptionsBuilder.requireFieldMatch(highlighterBuilder.requireFieldMatch);
+        }
+        if (highlighterBuilder.boundaryMaxScan != null) {
+            targetOptionsBuilder.boundaryMaxScan(highlighterBuilder.boundaryMaxScan);
+        }
+        targetOptionsBuilder.boundaryChars(convertCharArray(highlighterBuilder.boundaryChars));
+        targetOptionsBuilder.highlighterType(highlighterBuilder.highlighterType);
+        targetOptionsBuilder.fragmenter(highlighterBuilder.fragmenter);
+        if (highlighterBuilder.noMatchSize != null) {
+            targetOptionsBuilder.noMatchSize(highlighterBuilder.noMatchSize);
+        }
+        if (highlighterBuilder.forceSource != null) {
+            targetOptionsBuilder.forceSource(highlighterBuilder.forceSource);
+        }
+        if (highlighterBuilder.phraseLimit != null) {
+            targetOptionsBuilder.phraseLimit(highlighterBuilder.phraseLimit);
+        }
+        targetOptionsBuilder.options(highlighterBuilder.options);
+        if (highlighterBuilder.highlightQuery != null) {
+            targetOptionsBuilder.highlightQuery(highlighterBuilder.highlightQuery.toQuery(context));
+        }
+    }
+
+    private static Character[] convertCharArray(char[] array) {
+        if (array == null) {
+            return null;
+        }
+        Character[] charArray = new Character[array.length];
+        for (int i = 0; i < array.length; i++) {
+            charArray[i] = array[i];
+        }
+        return charArray;
+    }
 
     public void innerXContent(XContentBuilder builder) throws IOException {
         // first write common options

+ 3 - 42
core/src/main/java/org/elasticsearch/search/highlight/HighlighterParseElement.java

@@ -19,7 +19,6 @@
 
 package org.elasticsearch.search.highlight;
 
-import org.apache.lucene.search.vectorhighlight.SimpleBoundaryScanner;
 import org.elasticsearch.common.collect.Tuple;
 import org.elasticsearch.common.xcontent.XContentParser;
 import org.elasticsearch.index.query.QueryShardContext;
@@ -52,39 +51,6 @@ import java.util.Set;
  */
 public class HighlighterParseElement implements SearchParseElement {
 
-    /** default for whether to highlight fields based on the source even if stored separately */
-    public static final boolean DEFAULT_FORCE_SOURCE = false;
-    /** default for whether a field should be highlighted only if a query matches that field */
-    public static final boolean DEFAULT_REQUIRE_FIELD_MATCH = true;
-    /** default for whether <tt>fvh</tt> should provide highlighting on filter clauses */
-    public static final boolean DEFAULT_HIGHLIGHT_FILTER = false;
-    /** default for highlight fragments being ordered by score */
-    public static final boolean DEFAULT_SCORE_ORDERED = false;
-    /** the default encoder setting */
-    public static final String DEFAULT_ENCODER = "default";
-    /** default for the maximum number of phrases the fvh will consider */
-    public static final int DEFAULT_PHRASE_LIMIT = 256;
-    /** default for fragment size when there are no matches */
-    public static final int DEFAULT_NO_MATCH_SIZE = 0;
-    /** the default number of fragments for highlighting */
-    public static final int DEFAULT_NUMBER_OF_FRAGMENTS = 5;
-    /** the default number of fragments size in characters */
-    public static final int DEFAULT_FRAGMENT_CHAR_SIZE = 100;
-    /** the default opening tag  */
-    public static final String[] DEFAULT_PRE_TAGS = new String[]{"<em>"};
-    /** the default closing tag  */
-    public static final String[] DEFAULT_POST_TAGS = new String[]{"</em>"};
-
-    /** the default opening tags when <tt>tag_schema = "styled"</tt>  */
-    public static final String[] STYLED_PRE_TAG = {
-            "<em class=\"hlt1\">", "<em class=\"hlt2\">", "<em class=\"hlt3\">",
-            "<em class=\"hlt4\">", "<em class=\"hlt5\">", "<em class=\"hlt6\">",
-            "<em class=\"hlt7\">", "<em class=\"hlt8\">", "<em class=\"hlt9\">",
-            "<em class=\"hlt10\">"
-    };
-    /** the default closing tags when <tt>tag_schema = "styled"</tt>  */
-    public static final String[] STYLED_POST_TAGS = {"</em>"};
-
     @Override
     public void parse(XContentParser parser, SearchContext context) throws Exception {
         try {
@@ -99,12 +65,7 @@ public class HighlighterParseElement implements SearchParseElement {
         String topLevelFieldName = null;
         final List<Tuple<String, SearchContextHighlight.FieldOptions.Builder>> fieldsOptions = new ArrayList<>();
 
-        final SearchContextHighlight.FieldOptions.Builder globalOptionsBuilder = new SearchContextHighlight.FieldOptions.Builder()
-                .preTags(DEFAULT_PRE_TAGS).postTags(DEFAULT_POST_TAGS).scoreOrdered(DEFAULT_SCORE_ORDERED).highlightFilter(DEFAULT_HIGHLIGHT_FILTER)
-                .requireFieldMatch(DEFAULT_REQUIRE_FIELD_MATCH).forceSource(DEFAULT_FORCE_SOURCE).fragmentCharSize(DEFAULT_FRAGMENT_CHAR_SIZE).numberOfFragments(DEFAULT_NUMBER_OF_FRAGMENTS)
-                .encoder(DEFAULT_ENCODER).boundaryMaxScan(SimpleBoundaryScanner.DEFAULT_MAX_SCAN)
-                .boundaryChars(SimpleBoundaryScanner.DEFAULT_BOUNDARY_CHARS)
-                .noMatchSize(DEFAULT_NO_MATCH_SIZE).phraseLimit(DEFAULT_PHRASE_LIMIT);
+        final SearchContextHighlight.FieldOptions.Builder globalOptionsBuilder = HighlightBuilder.defaultFieldOptions();
 
         while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
             if (token == XContentParser.Token.FIELD_NAME) {
@@ -147,8 +108,8 @@ public class HighlighterParseElement implements SearchParseElement {
                 } else if ("tags_schema".equals(topLevelFieldName) || "tagsSchema".equals(topLevelFieldName)) {
                     String schema = parser.text();
                     if ("styled".equals(schema)) {
-                        globalOptionsBuilder.preTags(STYLED_PRE_TAG);
-                        globalOptionsBuilder.postTags(STYLED_POST_TAGS);
+                        globalOptionsBuilder.preTags(HighlightBuilder.DEFAULT_STYLED_PRE_TAG);
+                        globalOptionsBuilder.postTags(HighlightBuilder.DEFAULT_STYLED_POST_TAGS);
                     }
                 } else if ("highlight_filter".equals(topLevelFieldName) || "highlightFilter".equals(topLevelFieldName)) {
                     globalOptionsBuilder.highlightFilter(parser.booleanValue());

+ 4 - 0
core/src/main/java/org/elasticsearch/search/highlight/SearchContextHighlight.java

@@ -53,6 +53,10 @@ public class SearchContextHighlight {
         this.globalForceSource = globalForceSource;
     }
 
+    boolean globalForceSource() {
+        return this.globalForceSource;
+    }
+
     public boolean forceSource(Field field) {
         if (globalForceSource) {
             return true;

+ 83 - 5
core/src/test/java/org/elasticsearch/search/highlight/HighlightBuilderTests.java

@@ -21,6 +21,8 @@ package org.elasticsearch.search.highlight;
 
 import org.elasticsearch.common.ParseFieldMatcher;
 import org.elasticsearch.common.ParsingException;
+import org.elasticsearch.Version;
+import org.elasticsearch.cluster.metadata.IndexMetaData;
 import org.elasticsearch.common.io.stream.BytesStreamOutput;
 import org.elasticsearch.common.io.stream.NamedWriteableAwareStreamInput;
 import org.elasticsearch.common.io.stream.NamedWriteableRegistry;
@@ -32,6 +34,13 @@ import org.elasticsearch.common.xcontent.XContentFactory;
 import org.elasticsearch.common.xcontent.XContentHelper;
 import org.elasticsearch.common.xcontent.XContentParser;
 import org.elasticsearch.common.xcontent.XContentType;
+import org.elasticsearch.index.Index;
+import org.elasticsearch.index.IndexSettings;
+import org.elasticsearch.index.mapper.ContentPath;
+import org.elasticsearch.index.mapper.MappedFieldType;
+import org.elasticsearch.index.mapper.Mapper;
+import org.elasticsearch.index.mapper.MapperBuilders;
+import org.elasticsearch.index.mapper.core.StringFieldMapper;
 import org.elasticsearch.index.query.IdsQueryBuilder;
 import org.elasticsearch.index.query.IdsQueryParser;
 import org.elasticsearch.index.query.MatchAllQueryBuilder;
@@ -39,11 +48,15 @@ import org.elasticsearch.index.query.MatchAllQueryParser;
 import org.elasticsearch.index.query.QueryBuilder;
 import org.elasticsearch.index.query.QueryParseContext;
 import org.elasticsearch.index.query.QueryParser;
+import org.elasticsearch.index.query.QueryShardContext;
 import org.elasticsearch.index.query.TermQueryBuilder;
 import org.elasticsearch.index.query.TermQueryParser;
 import org.elasticsearch.indices.query.IndicesQueriesRegistry;
+import org.elasticsearch.search.highlight.HighlightBuilder;
 import org.elasticsearch.search.highlight.HighlightBuilder.Field;
+import org.elasticsearch.search.highlight.SearchContextHighlight.FieldOptions;
 import org.elasticsearch.test.ESTestCase;
+import org.elasticsearch.test.IndexSettingsModule;
 import org.junit.AfterClass;
 import org.junit.BeforeClass;
 
@@ -51,6 +64,7 @@ import java.io.IOException;
 import java.util.Arrays;
 import java.util.HashMap;
 import java.util.HashSet;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -128,7 +142,7 @@ public class HighlightBuilderTests extends ESTestCase {
     }
 
     /**
-     * Generic test that creates new highlighter from the test highlighter and checks both for equality
+     *  creates random highlighter, renders it to xContent and back to new instance that should be equal to original
      */
     public void testFromXContent() throws IOException {
         QueryParseContext context = new QueryParseContext(indicesQueriesRegistry);
@@ -261,6 +275,70 @@ public class HighlightBuilderTests extends ESTestCase {
         } catch (ParsingException e) {
             assertEquals("cannot parse object with name [bad_fieldname]", e.getMessage());
         }
+     }
+
+     /**
+     * test that build() outputs a {@link SearchContextHighlight} that is similar to the one
+     * we would get when parsing the xContent the test highlight builder is rendering out
+     */
+    public void testBuildSearchContextHighlight() throws IOException {
+        Settings indexSettings = Settings.settingsBuilder()
+                .put(IndexMetaData.SETTING_VERSION_CREATED, Version.CURRENT).build();
+        Index index = new Index(randomAsciiOfLengthBetween(1, 10));
+        IndexSettings idxSettings = IndexSettingsModule.newIndexSettings(index, indexSettings);
+        // shard context will only need indicesQueriesRegistry for building Query objects nested in highlighter
+        QueryShardContext mockShardContext = new QueryShardContext(idxSettings, null, null, null, null, null, null, indicesQueriesRegistry) {
+            @Override
+            public MappedFieldType fieldMapper(String name) {
+                StringFieldMapper.Builder builder = MapperBuilders.stringField(name);
+                return builder.build(new Mapper.BuilderContext(idxSettings.getSettings(), new ContentPath(1))).fieldType();
+            }
+        };
+        mockShardContext.setMapUnmappedFieldAsString(true);
+
+        for (int runs = 0; runs < NUMBER_OF_TESTBUILDERS; runs++) {
+            HighlightBuilder highlightBuilder = randomHighlighterBuilder();
+            SearchContextHighlight highlight = highlightBuilder.build(mockShardContext);
+            XContentBuilder builder = XContentFactory.contentBuilder(randomFrom(XContentType.values()));
+            if (randomBoolean()) {
+                builder.prettyPrint();
+            }
+            builder.startObject();
+            highlightBuilder.innerXContent(builder);
+            builder.endObject();
+            XContentParser parser = XContentHelper.createParser(builder.bytes());
+
+            SearchContextHighlight parsedHighlight = new HighlighterParseElement().parse(parser, mockShardContext);
+            assertNotSame(highlight, parsedHighlight);
+            assertEquals(highlight.globalForceSource(), parsedHighlight.globalForceSource());
+            assertEquals(highlight.fields().size(), parsedHighlight.fields().size());
+
+            Iterator<org.elasticsearch.search.highlight.SearchContextHighlight.Field> iterator = parsedHighlight.fields().iterator();
+            for (org.elasticsearch.search.highlight.SearchContextHighlight.Field field : highlight.fields()) {
+                org.elasticsearch.search.highlight.SearchContextHighlight.Field otherField = iterator.next();
+                assertEquals(field.field(), otherField.field());
+                FieldOptions options = field.fieldOptions();
+                FieldOptions otherOptions = otherField.fieldOptions();
+                assertArrayEquals(options.boundaryChars(), options.boundaryChars());
+                assertEquals(options.boundaryMaxScan(), otherOptions.boundaryMaxScan());
+                assertEquals(options.encoder(), otherOptions.encoder());
+                assertEquals(options.fragmentCharSize(), otherOptions.fragmentCharSize());
+                assertEquals(options.fragmenter(), otherOptions.fragmenter());
+                assertEquals(options.fragmentOffset(), otherOptions.fragmentOffset());
+                assertEquals(options.highlighterType(), otherOptions.highlighterType());
+                assertEquals(options.highlightFilter(), otherOptions.highlightFilter());
+                assertEquals(options.highlightQuery(), otherOptions.highlightQuery());
+                assertEquals(options.matchedFields(), otherOptions.matchedFields());
+                assertEquals(options.noMatchSize(), otherOptions.noMatchSize());
+                assertEquals(options.numberOfFragments(), otherOptions.numberOfFragments());
+                assertEquals(options.options(), otherOptions.options());
+                assertEquals(options.phraseLimit(), otherOptions.phraseLimit());
+                assertArrayEquals(options.preTags(), otherOptions.preTags());
+                assertArrayEquals(options.postTags(), otherOptions.postTags());
+                assertEquals(options.requireFieldMatch(), otherOptions.requireFieldMatch());
+                assertEquals(options.scoreOrdered(), otherOptions.scoreOrdered());
+            }
+        }
     }
 
     /**
@@ -277,9 +355,9 @@ public class HighlightBuilderTests extends ESTestCase {
 
         context.reset(parser);
         HighlightBuilder highlightBuilder = HighlightBuilder.fromXContent(context);
-        assertArrayEquals("setting tags_schema 'styled' should alter pre_tags", HighlighterParseElement.STYLED_PRE_TAG,
+        assertArrayEquals("setting tags_schema 'styled' should alter pre_tags", HighlightBuilder.DEFAULT_STYLED_PRE_TAG,
                 highlightBuilder.preTags());
-        assertArrayEquals("setting tags_schema 'styled' should alter post_tags", HighlighterParseElement.STYLED_POST_TAGS,
+        assertArrayEquals("setting tags_schema 'styled' should alter post_tags", HighlightBuilder.DEFAULT_STYLED_POST_TAGS,
                 highlightBuilder.postTags());
 
         highlightElement = "{\n" +
@@ -289,9 +367,9 @@ public class HighlightBuilderTests extends ESTestCase {
 
         context.reset(parser);
         highlightBuilder = HighlightBuilder.fromXContent(context);
-        assertArrayEquals("setting tags_schema 'default' should alter pre_tags", HighlighterParseElement.DEFAULT_PRE_TAGS,
+        assertArrayEquals("setting tags_schema 'default' should alter pre_tags", HighlightBuilder.DEFAULT_PRE_TAGS,
                 highlightBuilder.preTags());
-        assertArrayEquals("setting tags_schema 'default' should alter post_tags", HighlighterParseElement.DEFAULT_POST_TAGS,
+        assertArrayEquals("setting tags_schema 'default' should alter post_tags", HighlightBuilder.DEFAULT_POST_TAGS,
                 highlightBuilder.postTags());
 
         highlightElement = "{\n" +