4747import org .elasticsearch .index .mapper .BlockStoredFieldsReader ;
4848import org .elasticsearch .index .mapper .DocumentParserContext ;
4949import org .elasticsearch .index .mapper .FieldMapper ;
50+ import org .elasticsearch .index .mapper .KeywordFieldMapper ;
5051import org .elasticsearch .index .mapper .MapperBuilderContext ;
5152import org .elasticsearch .index .mapper .SourceValueFetcher ;
5253import org .elasticsearch .index .mapper .StringFieldType ;
@@ -123,7 +124,7 @@ protected Parameter<?>[] getParameters() {
123124 return new Parameter <?>[] { meta };
124125 }
125126
126- private MatchOnlyTextFieldType buildFieldType (MapperBuilderContext context ) {
127+ private MatchOnlyTextFieldType buildFieldType (MapperBuilderContext context , boolean storeSource ) {
127128 NamedAnalyzer searchAnalyzer = analyzers .getSearchAnalyzer ();
128129 NamedAnalyzer searchQuoteAnalyzer = analyzers .getSearchQuoteAnalyzer ();
129130 NamedAnalyzer indexAnalyzer = analyzers .getIndexAnalyzer ();
@@ -132,15 +133,14 @@ private MatchOnlyTextFieldType buildFieldType(MapperBuilderContext context) {
132133 context .buildFullName (leafName ()),
133134 tsi ,
134135 indexAnalyzer ,
135- context . isSourceSynthetic () ,
136+ storeSource ,
136137 meta .getValue ()
137138 );
138139 return ft ;
139140 }
140141
141142 @ Override
142143 public MatchOnlyTextFieldMapper build (MapperBuilderContext context ) {
143- MatchOnlyTextFieldType tft = buildFieldType (context );
144144 final boolean storeSource ;
145145 if (multiFieldsNotStoredByDefaultIndexVersionCheck (indexCreatedVersion )) {
146146 storeSource = context .isSourceSynthetic ()
@@ -149,6 +149,7 @@ public MatchOnlyTextFieldMapper build(MapperBuilderContext context) {
149149 } else {
150150 storeSource = context .isSourceSynthetic ();
151151 }
152+ MatchOnlyTextFieldType tft = buildFieldType (context , storeSource );
152153 return new MatchOnlyTextFieldMapper (leafName (), Defaults .FIELD_TYPE , tft , builderParams (this , context ), storeSource , this );
153154 }
154155 }
@@ -211,14 +212,18 @@ private IOFunction<LeafReaderContext, CheckedIntFunction<List<Object>, IOExcepti
211212 }
212213 if (searchExecutionContext .isSourceSynthetic ()) {
213214 String name = storedFieldNameForSyntheticSource ();
214- StoredFieldLoader loader = StoredFieldLoader .create (false , Set .of (name ));
215- return context -> {
216- LeafStoredFieldLoader leafLoader = loader .getLoader (context , null );
217- return docId -> {
218- leafLoader .advanceTo (docId );
219- return leafLoader .storedFields ().get (name );
215+ // TODO: go the parent field and load either via stored fields or doc values the values instead synthesizing complete source
216+ // (in case of synthetic source and if this field is a multi field, then it will not have a stored field.)
217+ if (name != null ) {
218+ StoredFieldLoader loader = StoredFieldLoader .create (false , Set .of (name ));
219+ return context -> {
220+ LeafStoredFieldLoader leafLoader = loader .getLoader (context , null );
221+ return docId -> {
222+ leafLoader .advanceTo (docId );
223+ return leafLoader .storedFields ().get (name );
224+ };
220225 };
221- };
226+ }
222227 }
223228 return context -> {
224229 ValueFetcher valueFetcher = valueFetcher (searchExecutionContext , null );
@@ -506,18 +511,30 @@ public MatchOnlyTextFieldType fieldType() {
506511
507512 @ Override
508513 protected SyntheticSourceSupport syntheticSourceSupport () {
509- return new SyntheticSourceSupport .Native (
510- () -> new StringStoredFieldFieldLoader (fieldType ().storedFieldNameForSyntheticSource (), fieldType ().name (), leafName ()) {
511- @ Override
512- protected void write (XContentBuilder b , Object value ) throws IOException {
513- if (value instanceof BytesRef valueBytes ) {
514- b .value (valueBytes .utf8ToString ());
515- } else {
516- assert value instanceof String ;
517- b .value (value .toString ());
514+ if (storeSource ) {
515+ return new SyntheticSourceSupport .Native (
516+ () -> new StringStoredFieldFieldLoader (fieldType ().storedFieldNameForSyntheticSource (), fieldType ().name (), leafName ()) {
517+ @ Override
518+ protected void write (XContentBuilder b , Object value ) throws IOException {
519+ if (value instanceof BytesRef valueBytes ) {
520+ b .value (valueBytes .utf8ToString ());
521+ } else {
522+ assert value instanceof String ;
523+ b .value (value .toString ());
524+ }
525+ }
526+ }
527+ );
528+ } else {
529+ for (FieldMapper multiField : multiFields ()) {
530+ if (multiField instanceof KeywordFieldMapper kwd ) {
531+ if (kwd .hasNormalizer () == false && (kwd .fieldType ().hasDocValues () || kwd .fieldType ().isStored ())) {
532+ return kwd .syntheticSourceSupport ();
518533 }
519534 }
520535 }
521- );
536+ assert false : "there should be a suite field mapper with native synthetic source support" ;
537+ return null ;
538+ }
522539 }
523540}
0 commit comments