1414import org .apache .lucene .document .Field ;
1515import org .apache .lucene .document .FieldType ;
1616import org .apache .lucene .document .StoredField ;
17+ import org .apache .lucene .index .DocValues ;
1718import org .apache .lucene .index .IndexOptions ;
1819import org .apache .lucene .index .LeafReaderContext ;
1920import org .apache .lucene .index .Term ;
4041import org .elasticsearch .index .fielddata .IndexFieldData ;
4142import org .elasticsearch .index .fielddata .SourceValueFetcherSortedBinaryIndexFieldData ;
4243import org .elasticsearch .index .fielddata .StoredFieldSortedBinaryIndexFieldData ;
43- import org .elasticsearch .index .fieldvisitor .LeafStoredFieldLoader ;
4444import org .elasticsearch .index .fieldvisitor .StoredFieldLoader ;
4545import org .elasticsearch .index .mapper .BlockLoader ;
4646import org .elasticsearch .index .mapper .BlockSourceReader ;
@@ -220,18 +220,34 @@ private IOFunction<LeafReaderContext, CheckedIntFunction<List<Object>, IOExcepti
220220 "Field [" + name () + "] of type [" + CONTENT_TYPE + "] cannot run positional queries since [_source] is disabled."
221221 );
222222 }
223- if (searchExecutionContext .isSourceSynthetic () && withinMultiField == false && hasCompatibleMultiFields == false ) {
223+ if (searchExecutionContext .isSourceSynthetic () && withinMultiField ) {
224+ String parentField = searchExecutionContext .parentPath (name ());
225+ var parent = searchExecutionContext .lookup ().fieldType (parentField );
226+ if (parent .isStored ()) {
227+ return storedFieldFetcher (parentField );
228+ } else if (parent .hasDocValues ()) {
229+ return docValuesFieldFetcher (parentField );
230+ } else {
231+ assert false : "parent field should either be stored or have doc values" ;
232+ }
233+ } else if (searchExecutionContext .isSourceSynthetic () && hasCompatibleMultiFields ) {
234+ var mapper = (MatchOnlyTextFieldMapper ) searchExecutionContext .getMappingLookup ().getMapper (name ());
235+ var kwd = TextFieldMapper .SyntheticSourceHelper .getKeywordFieldMapperForSyntheticSource (mapper );
236+ if (kwd != null ) {
237+ var fieldType = kwd .fieldType ();
238+ if (fieldType .isStored ()) {
239+ return storedFieldFetcher (fieldType .name ());
240+ } else if (fieldType .hasDocValues ()) {
241+ return docValuesFieldFetcher (fieldType .name ());
242+ } else {
243+ assert false : "multi field should either be stored or have doc values" ;
244+ }
245+ } else {
246+ assert false : "multi field of type keyword should exist" ;
247+ }
248+ } else if (searchExecutionContext .isSourceSynthetic ()) {
224249 String name = storedFieldNameForSyntheticSource ();
225- // TODO: go the parent field and load either via stored fields or doc values the values instead synthesizing complete source
226- // (in case of synthetic source and if this field is a multi field, then it will not have a stored field.)
227- StoredFieldLoader loader = StoredFieldLoader .create (false , Set .of (name ));
228- return context -> {
229- LeafStoredFieldLoader leafLoader = loader .getLoader (context , null );
230- return docId -> {
231- leafLoader .advanceTo (docId );
232- return leafLoader .storedFields ().get (name );
233- };
234- };
250+ return storedFieldFetcher (name );
235251 }
236252 return context -> {
237253 ValueFetcher valueFetcher = valueFetcher (searchExecutionContext , null );
@@ -247,6 +263,35 @@ private IOFunction<LeafReaderContext, CheckedIntFunction<List<Object>, IOExcepti
247263 };
248264 }
249265
266+ private static IOFunction <LeafReaderContext , CheckedIntFunction <List <Object >, IOException >> docValuesFieldFetcher (String name ) {
267+ return context -> {
268+ var sortedDocValues = DocValues .getSortedSet (context .reader (), name );
269+ return docId -> {
270+ if (sortedDocValues .advanceExact (docId )) {
271+ var values = new ArrayList <>(sortedDocValues .docValueCount ());
272+ for (int i = 0 ; i < sortedDocValues .docValueCount (); i ++) {
273+ long ord = sortedDocValues .nextOrd ();
274+ values .add (sortedDocValues .lookupOrd (ord ).utf8ToString ());
275+ }
276+ return values ;
277+ } else {
278+ return List .of ();
279+ }
280+ };
281+ };
282+ }
283+
284+ private static IOFunction <LeafReaderContext , CheckedIntFunction <List <Object >, IOException >> storedFieldFetcher (String name ) {
285+ var loader = StoredFieldLoader .create (false , Set .of (name ));
286+ return context -> {
287+ var leafLoader = loader .getLoader (context , null );
288+ return docId -> {
289+ leafLoader .advanceTo (docId );
290+ return leafLoader .storedFields ().get (name );
291+ };
292+ };
293+ }
294+
250295 private Query toQuery (Query query , SearchExecutionContext searchExecutionContext ) {
251296 return new ConstantScoreQuery (
252297 new SourceConfirmedTextQuery (query , getValueFetcherProvider (searchExecutionContext ), indexAnalyzer )
0 commit comments