3535
3636import  java .io .IOException ;
3737import  java .util .ArrayList ;
38- import  java .util .Collection ;
3938import  java .util .Collections ;
4039import  java .util .HashMap ;
41- import  java .util .HashSet ;
4240import  java .util .Iterator ;
4341import  java .util .LinkedList ;
4442import  java .util .List ;
4543import  java .util .Map ;
4644import  java .util .Optional ;
47- import  java .util .Set ;
4845import  java .util .function .Consumer ;
4946
5047import  static  org .elasticsearch .index .mapper .vectors .DenseVectorFieldMapper .MAX_DIMS_COUNT ;
@@ -148,9 +145,6 @@ private void internalParseDocument(MetadataFieldMapper[] metadataFieldsMappers,
148145
149146            executeIndexTimeScripts (context );
150147
151-             // Record additional entries for {@link IgnoredSourceFieldMapper} before calling #postParse, so that they get stored. 
152-             addIgnoredSourceMissingValues (context );
153- 
154148            for  (MetadataFieldMapper  metadataMapper  : metadataFieldsMappers ) {
155149                metadataMapper .postParse (context );
156150            }
@@ -159,128 +153,6 @@ private void internalParseDocument(MetadataFieldMapper[] metadataFieldsMappers,
159153        }
160154    }
161155
162-     private  void  addIgnoredSourceMissingValues (DocumentParserContext  context ) throws  IOException  {
163-         Collection <IgnoredSourceFieldMapper .NameValue > ignoredFieldsMissingValues  = context .getIgnoredFieldsMissingValues ();
164-         if  (ignoredFieldsMissingValues .isEmpty ()) {
165-             return ;
166-         }
167- 
168-         // Clean up any conflicting ignored values, to avoid double-printing them as array elements in synthetic source. 
169-         Map <String , IgnoredSourceFieldMapper .NameValue > fields  = new  HashMap <>(ignoredFieldsMissingValues .size ());
170-         for  (var  field  : ignoredFieldsMissingValues ) {
171-             fields .put (field .name (), field );
172-         }
173-         context .deduplicateIgnoredFieldValues (fields .keySet ());
174- 
175-         assert  context .mappingLookup ().isSourceSynthetic ();
176-         try  (
177-             XContentParser  parser  = XContentHelper .createParser (
178-                 parserConfiguration ,
179-                 context .sourceToParse ().source (),
180-                 context .sourceToParse ().getXContentType ()
181-             )
182-         ) {
183-             DocumentParserContext  newContext  = new  RootDocumentParserContext (
184-                 context .mappingLookup (),
185-                 mappingParserContext ,
186-                 context .sourceToParse (),
187-                 parser 
188-             );
189-             var  nameValues  = parseDocForMissingValues (newContext , fields );
190-             for  (var  nameValue  : nameValues ) {
191-                 context .addIgnoredField (nameValue );
192-             }
193-         }
194-     }
195- 
196-     /** 
197-      * Simplified parsing version for retrieving the source of a given set of fields. 
198-      */ 
199-     private  static  List <IgnoredSourceFieldMapper .NameValue > parseDocForMissingValues (
200-         DocumentParserContext  context ,
201-         Map <String , IgnoredSourceFieldMapper .NameValue > fields 
202-     ) throws  IOException  {
203-         // Generate all possible parent names for the given fields. 
204-         // This is used to skip processing objects that can't generate missing values. 
205-         Set <String > parentNames  = getPossibleParentNames (fields .keySet ());
206-         List <IgnoredSourceFieldMapper .NameValue > result  = new  ArrayList <>();
207- 
208-         XContentParser  parser  = context .parser ();
209-         XContentParser .Token  currentToken  = parser .nextToken ();
210-         List <String > path  = new  ArrayList <>();
211-         List <Boolean > isObjectInPath  = new  ArrayList <>();  // Tracks if path components correspond to an object or an array. 
212-         String  fieldName  = null ;
213-         while  (currentToken  != null ) {
214-             while  (currentToken  != XContentParser .Token .FIELD_NAME ) {
215-                 if  (fieldName  != null 
216-                     && (currentToken  == XContentParser .Token .START_OBJECT  || currentToken  == XContentParser .Token .START_ARRAY )) {
217-                     if  (parentNames .contains (getCurrentPath (path , fieldName )) == false ) {
218-                         // No missing value under this parsing subtree, skip it. 
219-                         parser .skipChildren ();
220-                     } else  {
221-                         path .add (fieldName );
222-                         isObjectInPath .add (currentToken  == XContentParser .Token .START_OBJECT );
223-                     }
224-                     fieldName  = null ;
225-                 } else  if  (currentToken  == XContentParser .Token .END_OBJECT  || currentToken  == XContentParser .Token .END_ARRAY ) {
226-                     // Remove the path, if the scope type matches the one when the path was added. 
227-                     if  (isObjectInPath .isEmpty () == false 
228-                         && (isObjectInPath .get (isObjectInPath .size () - 1 ) && currentToken  == XContentParser .Token .END_OBJECT 
229-                             || isObjectInPath .get (isObjectInPath .size () - 1 ) == false  && currentToken  == XContentParser .Token .END_ARRAY )) {
230-                         path .remove (path .size () - 1 );
231-                         isObjectInPath .remove (isObjectInPath .size () - 1 );
232-                     }
233-                     fieldName  = null ;
234-                 }
235-                 currentToken  = parser .nextToken ();
236-                 if  (currentToken  == null ) {
237-                     return  result ;
238-                 }
239-             }
240-             fieldName  = parser .currentName ();
241-             String  fullName  = getCurrentPath (path , fieldName );
242-             var  leaf  = fields .get (fullName );  // There may be multiple matches for array elements, don't use #remove. 
243-             if  (leaf  != null ) {
244-                 parser .nextToken ();  // Advance the parser to the value to be read. 
245-                 result .add (leaf .cloneWithValue (context .encodeFlattenedToken ()));
246-                 fieldName  = null ;
247-             }
248-             currentToken  = parser .nextToken ();
249-         }
250-         return  result ;
251-     }
252- 
253-     private  static  String  getCurrentPath (List <String > path , String  fieldName ) {
254-         assert  fieldName  != null ;
255-         return  path .isEmpty () ? fieldName  : String .join ("." , path ) + "."  + fieldName ;
256-     }
257- 
258-     /** 
259-      * Generates all possible parent object names for the given full names. 
260-      * For instance, for input ['path.to.foo', 'another.path.to.bar'], it returns: 
261-      * [ 'path', 'path.to', 'another', 'another.path', 'another.path.to' ] 
262-      */ 
263-     private  static  Set <String > getPossibleParentNames (Set <String > fullPaths ) {
264-         if  (fullPaths .isEmpty ()) {
265-             return  Collections .emptySet ();
266-         }
267-         Set <String > paths  = new  HashSet <>();
268-         for  (String  fullPath  : fullPaths ) {
269-             String [] split  = fullPath .split ("\\ ." );
270-             if  (split .length  < 2 ) {
271-                 continue ;
272-             }
273-             StringBuilder  builder  = new  StringBuilder (split [0 ]);
274-             paths .add (builder .toString ());
275-             for  (int  i  = 1 ; i  < split .length  - 1 ; i ++) {
276-                 builder .append ("." );
277-                 builder .append (split [i ]);
278-                 paths .add (builder .toString ());
279-             }
280-         }
281-         return  paths ;
282-     }
283- 
284156    private  static  void  executeIndexTimeScripts (DocumentParserContext  context ) {
285157        List <FieldMapper > indexTimeScriptMappers  = context .mappingLookup ().indexTimeScriptMappers ();
286158        if  (indexTimeScriptMappers .isEmpty ()) {
@@ -426,7 +298,10 @@ static void parseObjectOrNested(DocumentParserContext context) throws IOExceptio
426298            throwOnConcreteValue (context .parent (), currentFieldName , context );
427299        }
428300
429-         if  (context .canAddIgnoredField () && getSourceKeepMode (context , context .parent ().sourceKeepMode ()) == Mapper .SourceKeepMode .ALL ) {
301+         var  sourceKeepMode  = getSourceKeepMode (context , context .parent ().sourceKeepMode ());
302+         if  (context .canAddIgnoredField ()
303+             && (sourceKeepMode  == Mapper .SourceKeepMode .ALL 
304+                 || (sourceKeepMode  == Mapper .SourceKeepMode .ARRAYS  && context .inArrayScope ()))) {
430305            context  = context .addIgnoredFieldFromContext (
431306                new  IgnoredSourceFieldMapper .NameValue (
432307                    context .parent ().fullPath (),
@@ -571,9 +446,11 @@ static void parseObjectOrField(DocumentParserContext context, Mapper mapper) thr
571446                parseObjectOrNested (context .createFlattenContext (currentFieldName ));
572447                context .path ().add (currentFieldName );
573448            } else  {
449+                 var  sourceKeepMode  = getSourceKeepMode (context , fieldMapper .sourceKeepMode ());
574450                if  (context .canAddIgnoredField ()
575451                    && (fieldMapper .syntheticSourceMode () == FieldMapper .SyntheticSourceMode .FALLBACK 
576-                         || getSourceKeepMode (context , fieldMapper .sourceKeepMode ()) == Mapper .SourceKeepMode .ALL 
452+                         || sourceKeepMode  == Mapper .SourceKeepMode .ALL 
453+                         || (sourceKeepMode  == Mapper .SourceKeepMode .ARRAYS  && context .inArrayScope ())
577454                        || (context .isWithinCopyTo () == false  && context .isCopyToDestinationField (mapper .fullPath ())))) {
578455                    context  = context .addIgnoredFieldFromContext (
579456                        IgnoredSourceFieldMapper .NameValue .fromContext (context , fieldMapper .fullPath (), null )
@@ -810,8 +687,8 @@ private static void parseNonDynamicArray(
810687            boolean  objectWithFallbackSyntheticSource  = false ;
811688            if  (mapper  instanceof  ObjectMapper  objectMapper ) {
812689                mode  = getSourceKeepMode (context , objectMapper .sourceKeepMode ());
813-                 objectWithFallbackSyntheticSource  = ( mode  == Mapper .SourceKeepMode .ALL 
814-                     || (mode  == Mapper .SourceKeepMode .ARRAYS  && objectMapper  instanceof  NestedObjectMapper  == false )) ;
690+                 objectWithFallbackSyntheticSource  = mode  == Mapper .SourceKeepMode .ALL 
691+                     || (mode  == Mapper .SourceKeepMode .ARRAYS  && objectMapper  instanceof  NestedObjectMapper  == false );
815692            }
816693            boolean  fieldWithFallbackSyntheticSource  = false ;
817694            boolean  fieldWithStoredArraySource  = false ;
0 commit comments