1
0
Эх сурвалжийг харах

Remove force_source option for highlighting (#93193)

This was only needed because the percolator uses a MemoryIndex which did
not support stored fields, and so when it ran a highlighting phase it needed to
force it to read from source. MemoryIndex added stored fields support in
lucene 9.5, so we can remove this internal parameter.

The parameter remains available, but deprecated, via the rest layer, and no
longer has any effect.
Alan Woodward 2 жил өмнө
parent
commit
639eab0549
15 өөрчлөгдсөн 42 нэмэгдсэн , 204 устгасан
  1. 2 28
      docs/reference/search/search-your-data/highlighting.asciidoc
  2. 1 2
      modules/percolator/src/main/java/org/elasticsearch/percolator/PercolatorHighlightSubFetchPhase.java
  3. 2 3
      plugins/mapper-annotated-text/src/main/java/org/elasticsearch/index/mapper/annotatedtext/AnnotatedTextHighlighter.java
  4. 1 3
      server/src/internalClusterTest/java/org/elasticsearch/search/aggregations/metrics/TopHitsIT.java
  5. 0 66
      server/src/internalClusterTest/java/org/elasticsearch/search/fetch/subphase/highlight/HighlighterSearchIT.java
  6. 9 29
      server/src/main/java/org/elasticsearch/search/fetch/subphase/highlight/AbstractHighlighterBuilder.java
  7. 1 4
      server/src/main/java/org/elasticsearch/search/fetch/subphase/highlight/FastVectorHighlighter.java
  8. 0 3
      server/src/main/java/org/elasticsearch/search/fetch/subphase/highlight/FieldHighlightContext.java
  9. 0 4
      server/src/main/java/org/elasticsearch/search/fetch/subphase/highlight/HighlightBuilder.java
  10. 1 9
      server/src/main/java/org/elasticsearch/search/fetch/subphase/highlight/HighlightPhase.java
  11. 2 3
      server/src/main/java/org/elasticsearch/search/fetch/subphase/highlight/HighlightUtils.java
  12. 1 6
      server/src/main/java/org/elasticsearch/search/fetch/subphase/highlight/PlainHighlighter.java
  13. 0 25
      server/src/main/java/org/elasticsearch/search/fetch/subphase/highlight/SearchHighlightContext.java
  14. 4 6
      server/src/main/java/org/elasticsearch/search/fetch/subphase/highlight/UnifiedHighlighter.java
  15. 18 13
      server/src/test/java/org/elasticsearch/search/fetch/subphase/highlight/HighlightBuilderTests.java

+ 2 - 28
docs/reference/search/search-your-data/highlighting.asciidoc

@@ -171,13 +171,12 @@ NOTE: Only text, match_only_text, and keyword fields are highlighted when
 you use wildcards. If you use a custom mapper and want to highlight on a
 field anyway, you must explicitly specify that field name.
 
-force_source:: Highlight based on the source even if the field is
-stored separately. Defaults to `false`.
-
 fragmenter:: Specifies how text should be broken up in highlight
 snippets: `simple` or `span`. Only valid for the `plain` highlighter.
 Defaults to `span`.
 
+force_source:: deprecated; this parameter has no effect
+
 `simple`::: Breaks up text into same-sized fragments.
 `span`::: Breaks up text into same-sized fragments, but tries to avoid
 breaking up text between highlighted terms. This is helpful when you're
@@ -277,7 +276,6 @@ type:: The highlighter to use: `unified`, `plain`, or `fvh`. Defaults to
 * <<specify-highlight-query, Specify a highlight query>>
 * <<set-highlighter-type, Set highlighter type>>
 * <<configure-tags, Configure highlighting tags>>
-* <<highlight-source, Highlight source>>
 * <<highlight-all, Highlight all fields>>
 * <<matched-fields, Combine matches on multiple fields>>
 * <<explicit-field-order, Explicitly order highlighted fields>>
@@ -472,30 +470,6 @@ GET /_search
 --------------------------------------------------
 // TEST[setup:my_index]
 
-[discrete]
-[[highlight-source]]
-== Highlight on source
-
-Forces the highlighting to highlight fields based on the source even if fields
-are stored separately. Defaults to `false`.
-
-[source,console]
---------------------------------------------------
-GET /_search
-{
-  "query" : {
-    "match": { "user.id": "kimchy" }
-  },
-  "highlight" : {
-    "fields" : {
-      "comment" : {"force_source" : true}
-    }
-  }
-}
---------------------------------------------------
-// TEST[setup:my_index]
-
-
 [[highlight-all]]
 [discrete]
 == Highlight in all fields

+ 1 - 2
modules/percolator/src/main/java/org/elasticsearch/percolator/PercolatorHighlightSubFetchPhase.java

@@ -95,8 +95,7 @@ final class PercolatorHighlightSubFetchPhase implements FetchSubPhase {
                                 Map.of(),
                                 Source.fromBytes(document)
                             );
-                            // force source because MemoryIndex does not store fields
-                            SearchHighlightContext highlight = new SearchHighlightContext(fetchContext.highlight().fields(), true);
+                            SearchHighlightContext highlight = new SearchHighlightContext(fetchContext.highlight().fields());
                             FetchSubPhaseProcessor processor = highlightPhase.getProcessor(fetchContext, highlight, query);
                             processor.process(subContext);
                             for (Map.Entry<String, HighlightField> entry : subContext.hit().getHighlightFields().entrySet()) {

+ 2 - 3
plugins/mapper-annotated-text/src/main/java/org/elasticsearch/index/mapper/annotatedtext/AnnotatedTextHighlighter.java

@@ -34,10 +34,9 @@ public class AnnotatedTextHighlighter extends UnifiedHighlighter {
         CustomUnifiedHighlighter highlighter,
         SearchExecutionContext searchContext,
         MappedFieldType fieldType,
-        HitContext hitContext,
-        boolean forceSource
+        HitContext hitContext
     ) throws IOException {
-        List<Object> fieldValues = super.loadFieldValues(highlighter, searchContext, fieldType, hitContext, forceSource);
+        List<Object> fieldValues = super.loadFieldValues(highlighter, searchContext, fieldType, hitContext);
 
         List<Object> strings = new ArrayList<>(fieldValues.size());
         AnnotatedText[] annotations = new AnnotatedText[fieldValues.size()];

+ 1 - 3
server/src/internalClusterTest/java/org/elasticsearch/search/aggregations/metrics/TopHitsIT.java

@@ -895,9 +895,7 @@ public class TopHitsIT extends ESIntegTestCase {
         String hlType = randomFrom("plain", "fvh", "unified");
         HighlightBuilder.Field hlField = new HighlightBuilder.Field("comments.message").highlightQuery(
             matchQuery("comments.message", "comment")
-        )
-            .forceSource(randomBoolean()) // randomly from stored field or _source
-            .highlighterType(hlType);
+        ).highlighterType(hlType);
 
         SearchResponse searchResponse = client().prepareSearch("articles")
             .setQuery(nestedQuery("comments", matchQuery("comments.message", "comment").queryName("test"), ScoreMode.Avg))

+ 0 - 66
server/src/internalClusterTest/java/org/elasticsearch/search/fetch/subphase/highlight/HighlighterSearchIT.java

@@ -94,7 +94,6 @@ import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertHitC
 import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertNoFailures;
 import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertNotHighlighted;
 import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertSearchResponse;
-import static org.elasticsearch.test.hamcrest.RegexMatcher.matches;
 import static org.elasticsearch.xcontent.XContentFactory.jsonBuilder;
 import static org.hamcrest.Matchers.anyOf;
 import static org.hamcrest.Matchers.containsString;
@@ -738,71 +737,6 @@ public class HighlighterSearchIT extends ESIntegTestCase {
         assertHighlight(searchResponse, 0, "field-plain", 0, 1, equalTo("This is the <xxx>test</xxx> for the plain highlighter"));
     }
 
-    public void testForceSourceWithSourceDisabled() throws Exception {
-        assertAcked(
-            prepareCreate("test").setMapping(
-                jsonBuilder().startObject()
-                    .startObject("_doc")
-                    .startObject("_source")
-                    .field("enabled", false)
-                    .endObject()
-                    .startObject("properties")
-                    .startObject("field1")
-                    .field("type", "text")
-                    .field("store", true)
-                    .field("index_options", "offsets")
-                    .field("term_vector", "with_positions_offsets")
-                    .endObject()
-                    .startObject("field2")
-                    .field("type", "text")
-                    .endObject()
-                    .endObject()
-                    .endObject()
-                    .endObject()
-            )
-        );
-
-        ensureGreen();
-
-        client().prepareIndex("test")
-            .setSource("field1", "The quick brown fox jumps over the lazy dog", "field2", "second field content")
-            .get();
-        refresh();
-
-        // works using stored field
-        SearchResponse searchResponse = client().prepareSearch("test")
-            .setQuery(termQuery("field1", "quick"))
-            .highlighter(new HighlightBuilder().field(new Field("field1").preTags("<xxx>").postTags("</xxx>")))
-            .get();
-        assertHighlight(searchResponse, 0, "field1", 0, 1, equalTo("The <xxx>quick</xxx> brown fox jumps over the lazy dog"));
-
-        assertFailures(
-            client().prepareSearch("test")
-                .setQuery(termQuery("field1", "quick"))
-                .highlighter(new HighlightBuilder().field(new Field("field1").preTags("<xxx>").postTags("</xxx>").forceSource(true))),
-            RestStatus.BAD_REQUEST,
-            containsString("source is forced for fields [field1] but _source is disabled")
-        );
-
-        SearchSourceBuilder searchSource = SearchSourceBuilder.searchSource()
-            .query(termQuery("field1", "quick"))
-            .highlighter(highlight().forceSource(true).field("field1"));
-        assertFailures(
-            client().prepareSearch("test").setSource(searchSource),
-            RestStatus.BAD_REQUEST,
-            containsString("source is forced for fields [field1] but _source is disabled")
-        );
-
-        searchSource = SearchSourceBuilder.searchSource()
-            .query(termQuery("field1", "quick"))
-            .highlighter(highlight().forceSource(true).field("field*"));
-        assertFailures(
-            client().prepareSearch("test").setSource(searchSource),
-            RestStatus.BAD_REQUEST,
-            matches("source is forced for fields \\[field\\d, field\\d\\] but _source is disabled")
-        );
-    }
-
     public void testPlainHighlighter() throws Exception {
         ensureGreen();
 

+ 9 - 29
server/src/main/java/org/elasticsearch/search/fetch/subphase/highlight/AbstractHighlighterBuilder.java

@@ -62,7 +62,7 @@ public abstract class AbstractHighlighterBuilder<HB extends AbstractHighlighterB
     public static final ParseField TYPE_FIELD = new ParseField("type");
     public static final ParseField FRAGMENTER_FIELD = new ParseField("fragmenter");
     public static final ParseField NO_MATCH_SIZE_FIELD = new ParseField("no_match_size");
-    public static final ParseField FORCE_SOURCE_FIELD = new ParseField("force_source");
+    public static final ParseField FORCE_SOURCE_FIELD = new ParseField("force_source").withAllDeprecated();
     public static final ParseField PHRASE_LIMIT_FIELD = new ParseField("phrase_limit");
     public static final ParseField OPTIONS_FIELD = new ParseField("options");
     public static final ParseField HIGHLIGHT_QUERY_FIELD = new ParseField("highlight_query");
@@ -87,8 +87,6 @@ public abstract class AbstractHighlighterBuilder<HB extends AbstractHighlighterB
 
     protected Boolean highlightFilter;
 
-    protected Boolean forceSource;
-
     protected BoundaryScannerType boundaryScannerType;
 
     protected Integer boundaryMaxScan;
@@ -119,7 +117,6 @@ public abstract class AbstractHighlighterBuilder<HB extends AbstractHighlighterB
         highlightQuery = queryBuilder;
         order = template.order;
         highlightFilter = template.highlightFilter;
-        forceSource = template.forceSource;
         boundaryScannerType = template.boundaryScannerType;
         boundaryMaxScan = template.boundaryMaxScan;
         boundaryChars = template.boundaryChars;
@@ -146,7 +143,9 @@ public abstract class AbstractHighlighterBuilder<HB extends AbstractHighlighterB
         }
         order(in.readOptionalWriteable(Order::readFromStream));
         highlightFilter(in.readOptionalBoolean());
-        forceSource(in.readOptionalBoolean());
+        if (in.getTransportVersion().before(TransportVersion.V_8_8_0)) {
+            in.readOptionalBoolean();   // force_source, now deprecated
+        }
         boundaryScannerType(in.readOptionalWriteable(BoundaryScannerType::readFromStream));
         boundaryMaxScan(in.readOptionalVInt());
         if (in.readBoolean()) {
@@ -184,7 +183,9 @@ public abstract class AbstractHighlighterBuilder<HB extends AbstractHighlighterB
         }
         out.writeOptionalWriteable(order);
         out.writeOptionalBoolean(highlightFilter);
-        out.writeOptionalBoolean(forceSource);
+        if (out.getTransportVersion().before(TransportVersion.V_8_8_0)) {
+            out.writeOptionalBoolean(false);
+        }
         out.writeOptionalWriteable(boundaryScannerType);
         out.writeOptionalVInt(boundaryMaxScan);
         boolean hasBounaryChars = boundaryChars != null;
@@ -527,22 +528,6 @@ public abstract class AbstractHighlighterBuilder<HB extends AbstractHighlighterB
         return this.phraseLimit;
     }
 
-    /**
-     * Forces the highlighting to highlight fields based on the source even if fields are stored separately.
-     */
-    @SuppressWarnings("unchecked")
-    public HB forceSource(Boolean forceSource) {
-        this.forceSource = forceSource;
-        return (HB) this;
-    }
-
-    /**
-     * @return the value set by {@link #forceSource(Boolean)}
-     */
-    public Boolean forceSource() {
-        return this.forceSource;
-    }
-
     /**
      * Set to a non-negative value which represents the max offset used to analyze
      * the field thus avoiding exceptions if the field exceeds this limit.
@@ -550,7 +535,7 @@ public abstract class AbstractHighlighterBuilder<HB extends AbstractHighlighterB
     @SuppressWarnings("unchecked")
     public HB maxAnalyzedOffset(Integer maxAnalyzedOffset) {
         if (maxAnalyzedOffset != null && maxAnalyzedOffset <= 0) {
-            throw new IllegalArgumentException("[" + MAX_ANALYZED_OFFSET_FIELD.toString() + "] must be a positive integer");
+            throw new IllegalArgumentException("[" + MAX_ANALYZED_OFFSET_FIELD + "] must be a positive integer");
         }
         this.maxAnalyzedOffset = maxAnalyzedOffset;
         return (HB) this;
@@ -616,9 +601,6 @@ public abstract class AbstractHighlighterBuilder<HB extends AbstractHighlighterB
         if (options != null && options.size() > 0) {
             builder.field(OPTIONS_FIELD.getPreferredName(), options);
         }
-        if (forceSource != null) {
-            builder.field(FORCE_SOURCE_FIELD.getPreferredName(), forceSource);
-        }
         if (requireFieldMatch != null) {
             builder.field(REQUIRE_FIELD_MATCH_FIELD.getPreferredName(), requireFieldMatch);
         }
@@ -648,7 +630,7 @@ public abstract class AbstractHighlighterBuilder<HB extends AbstractHighlighterB
         parser.declareString(HB::highlighterType, TYPE_FIELD);
         parser.declareString(HB::fragmenter, FRAGMENTER_FIELD);
         parser.declareInt(HB::noMatchSize, NO_MATCH_SIZE_FIELD);
-        parser.declareBoolean(HB::forceSource, FORCE_SOURCE_FIELD);
+        parser.declareBoolean((builder, value) -> {}, FORCE_SOURCE_FIELD);  // force_source is ignored
         parser.declareInt(HB::phraseLimit, PHRASE_LIMIT_FIELD);
         parser.declareInt(HB::maxAnalyzedOffset, MAX_ANALYZED_OFFSET_FIELD);
         parser.declareObject(HB::options, (XContentParser p, Void c) -> {
@@ -691,7 +673,6 @@ public abstract class AbstractHighlighterBuilder<HB extends AbstractHighlighterB
             highlightQuery,
             order,
             highlightFilter,
-            forceSource,
             boundaryScannerType,
             boundaryMaxScan,
             Arrays.hashCode(boundaryChars),
@@ -729,7 +710,6 @@ public abstract class AbstractHighlighterBuilder<HB extends AbstractHighlighterB
             && Objects.equals(highlightQuery, other.highlightQuery)
             && Objects.equals(order, other.order)
             && Objects.equals(highlightFilter, other.highlightFilter)
-            && Objects.equals(forceSource, other.forceSource)
             && Objects.equals(boundaryScannerType, other.boundaryScannerType)
             && Objects.equals(boundaryMaxScan, other.boundaryMaxScan)
             && Arrays.equals(boundaryChars, other.boundaryChars)

+ 1 - 4
server/src/main/java/org/elasticsearch/search/fetch/subphase/highlight/FastVectorHighlighter.java

@@ -68,7 +68,6 @@ public class FastVectorHighlighter implements Highlighter {
         SearchHighlightContext.Field field = fieldContext.field;
         FetchSubPhase.HitContext hitContext = fieldContext.hitContext;
         MappedFieldType fieldType = fieldContext.fieldType;
-        boolean forceSource = fieldContext.forceSource;
         boolean fixBrokenAnalysis = fieldContext.context.containsBrokenAnalysis(fieldContext.fieldName);
 
         if (canHighlight(fieldType) == false) {
@@ -100,7 +99,6 @@ public class FastVectorHighlighter implements Highlighter {
                 field,
                 fieldType,
                 fieldContext.context,
-                forceSource,
                 fixBrokenAnalysis
             );
 
@@ -220,13 +218,12 @@ public class FastVectorHighlighter implements Highlighter {
         SearchHighlightContext.Field field,
         MappedFieldType fieldType,
         FetchContext fetchContext,
-        boolean forceSource,
         boolean fixBrokenAnalysis
     ) {
         BoundaryScanner boundaryScanner = getBoundaryScanner(field);
         FieldOptions options = field.fieldOptions();
         Function<Source, BaseFragmentsBuilder> supplier;
-        if (forceSource == false && fieldType.isStored()) {
+        if (fieldType.isStored()) {
             if (options.numberOfFragments() != 0 && options.scoreOrdered()) {
                 supplier = ignored -> new ScoreOrderFragmentsBuilder(options.preTags(), options.postTags(), boundaryScanner);
             } else {

+ 0 - 3
server/src/main/java/org/elasticsearch/search/fetch/subphase/highlight/FieldHighlightContext.java

@@ -22,7 +22,6 @@ public class FieldHighlightContext {
     public final FetchContext context;
     public final FetchSubPhase.HitContext hitContext;
     public final Query query;
-    public final boolean forceSource;
     public final Map<String, Object> cache;
 
     public FieldHighlightContext(
@@ -32,7 +31,6 @@ public class FieldHighlightContext {
         FetchContext context,
         FetchSubPhase.HitContext hitContext,
         Query query,
-        boolean forceSource,
         Map<String, Object> cache
     ) {
         this.fieldName = fieldName;
@@ -41,7 +39,6 @@ public class FieldHighlightContext {
         this.context = context;
         this.hitContext = hitContext;
         this.query = query;
-        this.forceSource = forceSource;
         this.cache = cache;
     }
 }

+ 0 - 4
server/src/main/java/org/elasticsearch/search/fetch/subphase/highlight/HighlightBuilder.java

@@ -94,7 +94,6 @@ public class HighlightBuilder extends AbstractHighlighterBuilder<HighlightBuilde
         .highlightFilter(DEFAULT_HIGHLIGHT_FILTER)
         .requireFieldMatch(DEFAULT_REQUIRE_FIELD_MATCH)
         .maxAnalyzedOffset(DEFAULT_MAX_ANALYZED_OFFSET)
-        .forceSource(DEFAULT_FORCE_SOURCE)
         .fragmentCharSize(DEFAULT_FRAGMENT_CHAR_SIZE)
         .numberOfFragments(DEFAULT_NUMBER_OF_FRAGMENTS)
         .encoder(DEFAULT_ENCODER)
@@ -366,9 +365,6 @@ public class HighlightBuilder extends AbstractHighlighterBuilder<HighlightBuilde
         if (highlighterBuilder.noMatchSize != null) {
             targetOptionsBuilder.noMatchSize(highlighterBuilder.noMatchSize);
         }
-        if (highlighterBuilder.forceSource != null) {
-            targetOptionsBuilder.forceSource(highlighterBuilder.forceSource);
-        }
         if (highlighterBuilder.phraseLimit != null) {
             targetOptionsBuilder.phraseLimit(highlighterBuilder.phraseLimit);
         }

+ 1 - 9
server/src/main/java/org/elasticsearch/search/fetch/subphase/highlight/HighlightPhase.java

@@ -106,16 +106,9 @@ public class HighlightPhase implements FetchSubPhase {
 
             Collection<String> fieldNamesToHighlight = context.getSearchExecutionContext().getMatchingFieldNames(field.field());
 
-            if (highlightContext.forceSource(field)) {
-                if (context.getSearchExecutionContext().isSourceEnabled() == false) {
-                    throw new IllegalArgumentException("source is forced for fields " + fieldNamesToHighlight + " but _source is disabled");
-                }
-            }
-            boolean forceSource = highlightContext.forceSource(field);
-
             boolean fieldNameContainsWildcards = field.field().contains("*");
             Set<String> storedFields = new HashSet<>();
-            boolean sourceRequired = forceSource;
+            boolean sourceRequired = false;
             for (String fieldName : fieldNamesToHighlight) {
                 MappedFieldType fieldType = context.getSearchExecutionContext().getFieldType(fieldName);
 
@@ -156,7 +149,6 @@ public class HighlightPhase implements FetchSubPhase {
                         context,
                         hc,
                         highlightQuery == null ? query : highlightQuery,
-                        forceSource,
                         sharedCache
                     )
                 );

+ 2 - 3
server/src/main/java/org/elasticsearch/search/fetch/subphase/highlight/HighlightUtils.java

@@ -40,10 +40,9 @@ public final class HighlightUtils {
     public static List<Object> loadFieldValues(
         MappedFieldType fieldType,
         SearchExecutionContext searchContext,
-        FetchSubPhase.HitContext hitContext,
-        boolean forceSource
+        FetchSubPhase.HitContext hitContext
     ) throws IOException {
-        if (forceSource == false && fieldType.isStored()) {
+        if (fieldType.isStored()) {
             CustomFieldsVisitor fieldVisitor = new CustomFieldsVisitor(singleton(fieldType.name()), false);
             hitContext.reader().document(hitContext.docId(), fieldVisitor);
             List<Object> textsToHighlight = fieldVisitor.fields().get(fieldType.name());

+ 1 - 6
server/src/main/java/org/elasticsearch/search/fetch/subphase/highlight/PlainHighlighter.java

@@ -112,12 +112,7 @@ public class PlainHighlighter implements Highlighter {
             queryMaxAnalyzedOffset
         );
 
-        textsToHighlight = HighlightUtils.loadFieldValues(
-            fieldType,
-            context.getSearchExecutionContext(),
-            hitContext,
-            fieldContext.forceSource
-        );
+        textsToHighlight = HighlightUtils.loadFieldValues(fieldType, context.getSearchExecutionContext(), hitContext);
 
         int fragNumBase = 0;
         for (Object textToHighlight : textsToHighlight) {

+ 0 - 25
server/src/main/java/org/elasticsearch/search/fetch/subphase/highlight/SearchHighlightContext.java

@@ -22,34 +22,19 @@ import java.util.Set;
 public class SearchHighlightContext {
 
     private final Map<String, Field> fields;
-    private final boolean globalForceSource;
 
     public SearchHighlightContext(Collection<Field> fields) {
-        this(fields, false);
-    }
-
-    public SearchHighlightContext(Collection<Field> fields, boolean globalForceSource) {
         assert fields != null;
         this.fields = Maps.newLinkedHashMapWithExpectedSize(fields.size());
         for (Field field : fields) {
             this.fields.put(field.field, field);
         }
-        this.globalForceSource = globalForceSource;
     }
 
     public Collection<Field> fields() {
         return fields.values();
     }
 
-    public boolean forceSource(Field field) {
-        if (globalForceSource) {
-            return true;
-        }
-
-        Field _field = fields.get(field.field);
-        return _field == null ? false : _field.fieldOptions.forceSource;
-    }
-
     public static class Field {
         private final String field;
         private final FieldOptions fieldOptions;
@@ -95,8 +80,6 @@ public class SearchHighlightContext {
 
         private String highlighterType;
 
-        private Boolean forceSource;
-
         private String fragmenter;
 
         private BoundaryScannerType boundaryScannerType;
@@ -260,11 +243,6 @@ public class SearchHighlightContext {
                 return this;
             }
 
-            Builder forceSource(boolean forceSource) {
-                fieldOptions.forceSource = forceSource;
-                return this;
-            }
-
             Builder fragmenter(String fragmenter) {
                 fieldOptions.fragmenter = fragmenter;
                 return this;
@@ -374,9 +352,6 @@ public class SearchHighlightContext {
                 if (fieldOptions.noMatchSize == -1) {
                     fieldOptions.noMatchSize = globalOptions.noMatchSize;
                 }
-                if (fieldOptions.forceSource == null) {
-                    fieldOptions.forceSource = globalOptions.forceSource;
-                }
                 if (fieldOptions.phraseLimit == -1) {
                     fieldOptions.phraseLimit = globalOptions.phraseLimit;
                 }

+ 4 - 6
server/src/main/java/org/elasticsearch/search/fetch/subphase/highlight/UnifiedHighlighter.java

@@ -68,8 +68,7 @@ public class UnifiedHighlighter implements Highlighter {
                 highlighter,
                 fieldContext.context.getSearchExecutionContext(),
                 fieldType,
-                hitContext,
-                fieldContext.forceSource
+                hitContext
             );
             if (fieldValues.size() == 0) {
                 return null;
@@ -169,10 +168,9 @@ public class UnifiedHighlighter implements Highlighter {
         CustomUnifiedHighlighter highlighter,
         SearchExecutionContext searchContext,
         MappedFieldType fieldType,
-        FetchSubPhase.HitContext hitContext,
-        boolean forceSource
+        FetchSubPhase.HitContext hitContext
     ) throws IOException {
-        return HighlightUtils.loadFieldValues(fieldType, searchContext, hitContext, forceSource)
+        return HighlightUtils.loadFieldValues(fieldType, searchContext, hitContext)
             .stream()
             .<Object>map((s) -> convertFieldValue(fieldType, s))
             .toList();
@@ -195,7 +193,7 @@ public class UnifiedHighlighter implements Highlighter {
                 // ignore maxLen
                 return BreakIterator.getWordInstance(locale);
             default:
-                throw new IllegalArgumentException("Invalid boundary scanner type: " + type.toString());
+                throw new IllegalArgumentException("Invalid boundary scanner type: " + type);
         }
     }
 

+ 18 - 13
server/src/test/java/org/elasticsearch/search/fetch/subphase/highlight/HighlightBuilderTests.java

@@ -560,6 +560,17 @@ public class HighlightBuilderTests extends ESTestCase {
         }
     }
 
+    public void testForceSourceDeprecation() throws IOException {
+        String highlightJson = """
+            { "fields" : { }, "force_source" : true }
+            """;
+        try (XContentParser parser = createParser(JsonXContent.jsonXContent, highlightJson)) {
+            HighlightBuilder.fromXContent(parser);
+        }
+
+        assertWarnings("Deprecated field [force_source] used, this field is unused and will be removed entirely");
+    }
+
     protected static XContentBuilder toXContent(HighlightBuilder highlight, XContentType contentType) throws IOException {
         XContentBuilder builder = XContentFactory.contentBuilder(contentType);
         if (randomBoolean()) {
@@ -633,9 +644,6 @@ public class HighlightBuilderTests extends ESTestCase {
         if (randomBoolean()) {
             highlightBuilder.highlightFilter(randomBoolean());
         }
-        if (randomBoolean()) {
-            highlightBuilder.forceSource(randomBoolean());
-        }
         if (randomBoolean()) {
             if (randomBoolean()) {
                 highlightBuilder.boundaryScannerType(randomFrom(BoundaryScannerType.values()));
@@ -682,7 +690,7 @@ public class HighlightBuilderTests extends ESTestCase {
 
     @SuppressWarnings({ "unchecked", "rawtypes" })
     private static void mutateCommonOptions(AbstractHighlighterBuilder highlightBuilder) {
-        switch (randomIntBetween(1, 17)) {
+        switch (randomIntBetween(1, 16)) {
             case 1:
                 highlightBuilder.preTags(randomStringArray(4, 6));
                 break;
@@ -717,21 +725,18 @@ public class HighlightBuilderTests extends ESTestCase {
                 highlightBuilder.highlightFilter(toggleOrSet(highlightBuilder.highlightFilter()));
                 break;
             case 10:
-                highlightBuilder.forceSource(toggleOrSet(highlightBuilder.forceSource()));
-                break;
-            case 11:
                 highlightBuilder.boundaryMaxScan(randomIntBetween(11, 20));
                 break;
-            case 12:
+            case 11:
                 highlightBuilder.boundaryChars(randomAlphaOfLengthBetween(11, 20).toCharArray());
                 break;
-            case 13:
+            case 12:
                 highlightBuilder.noMatchSize(randomIntBetween(11, 20));
                 break;
-            case 14:
+            case 13:
                 highlightBuilder.phraseLimit(randomIntBetween(11, 20));
                 break;
-            case 15:
+            case 14:
                 int items = 6;
                 Map<String, Object> options = Maps.newMapWithExpectedSize(items);
                 for (int i = 0; i < items; i++) {
@@ -739,10 +744,10 @@ public class HighlightBuilderTests extends ESTestCase {
                 }
                 highlightBuilder.options(options);
                 break;
-            case 16:
+            case 15:
                 highlightBuilder.requireFieldMatch(toggleOrSet(highlightBuilder.requireFieldMatch()));
                 break;
-            case 17:
+            case 16:
                 highlightBuilder.maxAnalyzedOffset(
                     randomValueOtherThan(highlightBuilder.maxAnalyzedOffset(), () -> randomIntBetween(1, 100))
                 );