@@ -92,13 +92,15 @@ public void resolveAsMergedMapping(
9292
9393    // public for testing only 
9494    public  static  IndexResolution  mergedMappings (String  indexPattern , FieldCapabilitiesResponse  fieldCapsResponse ) {
95-         var  numberOfIndices  = fieldCapsResponse .getIndexResponses ().size ();
9695        assert  ThreadPool .assertCurrentThreadPool (ThreadPool .Names .SEARCH_COORDINATION ); // too expensive to run this on a transport worker 
96+         var  numberOfIndices  = fieldCapsResponse .getIndexResponses ().size ();
9797        if  (fieldCapsResponse .getIndexResponses ().isEmpty ()) {
9898            return  IndexResolution .notFound (indexPattern );
9999        }
100100
101-         Map <String , List <IndexFieldCapabilities >> fieldsCaps  = collectFieldCaps (fieldCapsResponse );
101+         var  collectedFieldCaps  = collectFieldCaps (fieldCapsResponse );
102+         Map <String , IndexFieldCapabilitiesWithSourceHash > fieldsCaps  = collectedFieldCaps .fieldsCaps ;
103+         Map <String , Integer > indexMappingHashDuplicates  = collectedFieldCaps .indexMappingHashDuplicates ;
102104
103105        // Build hierarchical fields - it's easier to do it in sorted order so the object fields come first. 
104106        // TODO flattened is simpler - could we get away with that? 
@@ -130,7 +132,8 @@ public static IndexResolution mergedMappings(String indexPattern, FieldCapabilit
130132            }
131133            // TODO we're careful to make isAlias match IndexResolver - but do we use it? 
132134
133-             List <IndexFieldCapabilities > fcs  = fieldsCaps .get (fullName );
135+             var  fieldCap  = fieldsCaps .get (fullName );
136+             List <IndexFieldCapabilities > fcs  = fieldCap .fieldCapabilities ;
134137            EsField  field  = firstUnsupportedParent  == null 
135138                ? createField (fieldCapsResponse , name , fullName , fcs , isAlias )
136139                : new  UnsupportedEsField (
@@ -140,8 +143,7 @@ public static IndexResolution mergedMappings(String indexPattern, FieldCapabilit
140143                    new  HashMap <>()
141144                );
142145            fields .put (name , field );
143- 
144-             var  isPartiallyUnmapped  = fcs .size () < numberOfIndices ;
146+             var  isPartiallyUnmapped  = fcs .size () + indexMappingHashDuplicates .getOrDefault (fieldCap .indexMappingHash , 0 ) < numberOfIndices ;
145147            if  (isPartiallyUnmapped ) {
146148                partiallyUnmappedFields .add (fullName );
147149            }
@@ -162,23 +164,46 @@ public static IndexResolution mergedMappings(String indexPattern, FieldCapabilit
162164        return  IndexResolution .valid (index , concreteIndices .keySet (), failures );
163165    }
164166
165-     private  static  Map <String , List <IndexFieldCapabilities >> collectFieldCaps (FieldCapabilitiesResponse  fieldCapsResponse ) {
166-         Set <String > seenHashes  = new  HashSet <>();
167-         Map <String , List <IndexFieldCapabilities >> fieldsCaps  = new  HashMap <>();
167+     private  record  IndexFieldCapabilitiesWithSourceHash (List <IndexFieldCapabilities > fieldCapabilities , String  indexMappingHash ) {}
168+ 
169+     private  record  CollectedFieldCaps (
170+         Map <String , IndexFieldCapabilitiesWithSourceHash > fieldsCaps ,
171+         // The map won't contain entries without duplicates, i.e., it's number of occurrences - 1. 
172+         Map <String , Integer > indexMappingHashDuplicates 
173+     ) {}
174+ 
175+     private  static  CollectedFieldCaps  collectFieldCaps (FieldCapabilitiesResponse  fieldCapsResponse ) {
176+         Map <String , Integer > indexMappingHashToDuplicateCount  = new  HashMap <>();
177+         Map <String , IndexFieldCapabilitiesWithSourceHash > fieldsCaps  = new  HashMap <>();
178+ 
168179        for  (FieldCapabilitiesIndexResponse  response  : fieldCapsResponse .getIndexResponses ()) {
169-             if  (seenHashes . add (response .getIndexMappingHash ())  == false ) {
180+             if  (indexMappingHashToDuplicateCount . compute (response .getIndexMappingHash (), ( k ,  v ) ->  v   == null  ?  1  :  v  +  1 ) >  1 ) {
170181                continue ;
171182            }
172183            for  (IndexFieldCapabilities  fc  : response .get ().values ()) {
173184                if  (fc .isMetadatafield ()) {
174185                    // ESQL builds the metadata fields if they are asked for without using the resolution. 
175186                    continue ;
176187                }
177-                 List <IndexFieldCapabilities > all  = fieldsCaps .computeIfAbsent (fc .name (), (_key ) -> new  ArrayList <>());
188+                 List <IndexFieldCapabilities > all  = fieldsCaps .computeIfAbsent (
189+                     fc .name (),
190+                     (_key ) -> new  IndexFieldCapabilitiesWithSourceHash (new  ArrayList <>(), response .getIndexMappingHash ())
191+                 ).fieldCapabilities ;
178192                all .add (fc );
179193            }
180194        }
181-         return  fieldsCaps ;
195+ 
196+         var  iterator  = indexMappingHashToDuplicateCount .entrySet ().iterator ();
197+         while  (iterator .hasNext ()) {
198+             var  next  = iterator .next ();
199+             if  (next .getValue () <= 1 ) {
200+                 iterator .remove ();
201+             } else  {
202+                 next .setValue (next .getValue () - 1 );
203+             }
204+         }
205+ 
206+         return  new  CollectedFieldCaps (fieldsCaps , indexMappingHashToDuplicateCount );
182207    }
183208
184209    private  static  EsField  createField (
0 commit comments