You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Fixes#22536 — When index.derived_source.enabled=true, TextFieldMapper.build() unconditionally forces store=true on every text mapper, including multi-field text subfields (e.g. keyword + fields.analyzed: text).
Multi-fields are not walked by derived-source _source reconstruction (ObjectMapper.deriveSource() only iterates top-level / object child mappers). The parent keyword field is rebuilt from doc_values. The text multi-field is never consulted for _source, so forcing stored fields wastes disk for no reconstruction benefit.
Root Cause
In TextFieldMapper.Builder.build():
if (context.indexSettings().getAsBoolean(IndexSettings.INDEX_DERIVED_SOURCE_SETTING.getKey(), false)
|| context.indexSettings().getAsBoolean(IndexSettings.PLUGGABLE_DATAFORMAT_ENABLED_SETTING.getKey(), false)) {
fieldType.setStored(true);
}
This runs for ALL text fields, including multi-fields built via MultiFields.Builder.build(). Multi-fields are not walked by deriveSource(), so forcing store=true on them is unnecessary.
Fix
Three changes across three files:
Mapper.java (BuilderContext): Added isMultiField() / setMultiField() methods to track whether a field is being built as a multi-field.
FieldMapper.java (MultiFields.Builder.build()): Set context.setMultiField(true) before building multi-field mappers and reset to false after.
TextFieldMapper.java (Builder.build()): Added && !context.isMultiField() check before forcing store=true, so multi-fields are no longer forced to be stored.
Expected Behavior
Field
Auto store=true with derived source?
Top-level type: text
Yes — needed to reconstruct _source
Object child text field
Yes — in deriveSource tree
Multi-field *.analyzed under keyword parent
No — not part of _source reconstruction
Explicit "store": true on a multi-field is still honored if the user asked for it.
Testing
Existing tests should continue to pass — no functional change for top-level or object-child text fields
Multi-fields under derived source will no longer be unnecessarily stored, reducing disk usage
context.setMultiField(true) is set before the loop but reset to false only after the loop completes normally. If any value.build(context) throws an exception, the multi-field flag remains true on the shared BuilderContext, potentially affecting subsequent field builds using the same context. Consider wrapping in try/finally to guarantee the flag is reset.
The flag is set to true on entry and unconditionally reset to false on exit. If multi-field builders can be nested (a build path that re-enters MultiFields.build), the inner completion will incorrectly clear the flag while the outer is still processing siblings. Saving the prior value and restoring it would be safer than always writing false.
The multiField flag is unconditionally reset to false after the loop, which breaks nested multi-field scenarios and can leak state if build() throws. Save the previous value before setting and restore it in a finally block to preserve correctness under exceptions and nesting.
Why: Using try/finally to restore the previous multiField state is a reasonable robustness improvement, protecting against exceptions and potential nested multi-field builds. However, multi-fields are typically not nested and the impact is minor in practice.
Please examine the workflow log, locate, and copy-paste the failure(s) below, then iterate to green. Is the failure a flaky test unrelated to your change?
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
bugSomething isn't workingStorageIssues and PRs relating to data and metadata storage
1 participant
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Fixes #22536 — When
index.derived_source.enabled=true,TextFieldMapper.build()unconditionally forcesstore=trueon every text mapper, including multi-field text subfields (e.g.keyword + fields.analyzed: text).Multi-fields are not walked by derived-source
_sourcereconstruction (ObjectMapper.deriveSource()only iterates top-level / object child mappers). The parentkeywordfield is rebuilt fromdoc_values. The text multi-field is never consulted for_source, so forcing stored fields wastes disk for no reconstruction benefit.Root Cause
In
TextFieldMapper.Builder.build():This runs for ALL text fields, including multi-fields built via
MultiFields.Builder.build(). Multi-fields are not walked byderiveSource(), so forcingstore=trueon them is unnecessary.Fix
Three changes across three files:
Mapper.java (BuilderContext): Added
isMultiField()/setMultiField()methods to track whether a field is being built as a multi-field.FieldMapper.java (MultiFields.Builder.build()): Set
context.setMultiField(true)before building multi-field mappers and reset tofalseafter.TextFieldMapper.java (Builder.build()): Added
&& !context.isMultiField()check before forcingstore=true, so multi-fields are no longer forced to be stored.Expected Behavior
store=truewith derived source?type: text_sourcederiveSourcetree*.analyzedunderkeywordparent_sourcereconstructionExplicit
"store": trueon a multi-field is still honored if the user asked for it.Testing
Closes #22536