3131import org .elasticsearch .common .collect .Tuple ;
3232import org .elasticsearch .common .document .DocumentField ;
3333import org .elasticsearch .common .lucene .search .Queries ;
34- import org .elasticsearch .common .regex .Regex ;
3534import org .elasticsearch .common .text .Text ;
3635import org .elasticsearch .common .xcontent .XContentHelper ;
3736import org .elasticsearch .common .xcontent .XContentType ;
5554import org .elasticsearch .tasks .TaskCancelledException ;
5655
5756import java .io .IOException ;
58- import java .util .ArrayList ;
57+ import java .util .Collection ;
5958import java .util .Collections ;
6059import java .util .HashMap ;
6160import java .util .HashSet ;
@@ -84,8 +83,7 @@ public void preProcess(SearchContext context) {
8483 @ Override
8584 public void execute (SearchContext context ) {
8685 final FieldsVisitor fieldsVisitor ;
87- Set <String > fieldNames = null ;
88- List <String > fieldNamePatterns = null ;
86+ Map <String , Set <String >> storedToRequestedFields = new HashMap <>();
8987 StoredFieldsContext storedFieldsContext = context .storedFieldsContext ();
9088
9189 if (storedFieldsContext == null ) {
@@ -98,39 +96,36 @@ public void execute(SearchContext context) {
9896 // disable stored fields entirely
9997 fieldsVisitor = null ;
10098 } else {
101- for (String fieldName : context .storedFieldsContext ().fieldNames ()) {
102- if (fieldName .equals (SourceFieldMapper .NAME )) {
99+ for (String fieldNameOrPattern : context .storedFieldsContext ().fieldNames ()) {
100+ if (fieldNameOrPattern .equals (SourceFieldMapper .NAME )) {
103101 FetchSourceContext fetchSourceContext = context .hasFetchSourceContext () ? context .fetchSourceContext ()
104- : FetchSourceContext .FETCH_SOURCE ;
102+ : FetchSourceContext .FETCH_SOURCE ;
105103 context .fetchSourceContext (new FetchSourceContext (true , fetchSourceContext .includes (), fetchSourceContext .excludes ()));
106104 continue ;
107105 }
108- if (Regex .isSimpleMatchPattern (fieldName )) {
109- if (fieldNamePatterns == null ) {
110- fieldNamePatterns = new ArrayList <>();
111- }
112- fieldNamePatterns .add (fieldName );
113- } else {
106+
107+ Collection <String > fieldNames = context .mapperService ().simpleMatchToFullName (fieldNameOrPattern );
108+ for (String fieldName : fieldNames ) {
114109 MappedFieldType fieldType = context .smartNameFieldType (fieldName );
115110 if (fieldType == null ) {
116111 // Only fail if we know it is a object field, missing paths / fields shouldn't fail.
117112 if (context .getObjectMapper (fieldName ) != null ) {
118113 throw new IllegalArgumentException ("field [" + fieldName + "] isn't a leaf field" );
119114 }
115+ } else {
116+ String storedField = fieldType .name ();
117+ Set <String > requestedFields = storedToRequestedFields .computeIfAbsent (
118+ storedField , key -> new HashSet <>());
119+ requestedFields .add (fieldName );
120120 }
121- if (fieldNames == null ) {
122- fieldNames = new HashSet <>();
123- }
124- fieldNames .add (fieldName );
125121 }
126122 }
127123 boolean loadSource = context .sourceRequested ();
128- if (fieldNames == null && fieldNamePatterns == null ) {
124+ if (storedToRequestedFields . isEmpty () ) {
129125 // empty list specified, default to disable _source if no explicit indication
130126 fieldsVisitor = new FieldsVisitor (loadSource );
131127 } else {
132- fieldsVisitor = new CustomFieldsVisitor (fieldNames == null ? Collections .emptySet () : fieldNames ,
133- fieldNamePatterns == null ? Collections .emptyList () : fieldNamePatterns , loadSource );
128+ fieldsVisitor = new CustomFieldsVisitor (storedToRequestedFields .keySet (), loadSource );
134129 }
135130 }
136131
@@ -149,10 +144,11 @@ public void execute(SearchContext context) {
149144 final SearchHit searchHit ;
150145 int rootDocId = findRootDocumentIfNested (context , subReaderContext , subDocId );
151146 if (rootDocId != -1 ) {
152- searchHit = createNestedSearchHit (context , docId , subDocId , rootDocId , fieldNames , fieldNamePatterns ,
153- subReaderContext );
147+ searchHit = createNestedSearchHit (context , docId , subDocId , rootDocId ,
148+ storedToRequestedFields , subReaderContext );
154149 } else {
155- searchHit = createSearchHit (context , fieldsVisitor , docId , subDocId , subReaderContext );
150+ searchHit = createSearchHit (context , fieldsVisitor , docId , subDocId ,
151+ storedToRequestedFields , subReaderContext );
156152 }
157153
158154 hits [index ] = searchHit ;
@@ -190,21 +186,18 @@ private int findRootDocumentIfNested(SearchContext context, LeafReaderContext su
190186 return -1 ;
191187 }
192188
193- private SearchHit createSearchHit (SearchContext context , FieldsVisitor fieldsVisitor , int docId , int subDocId ,
189+ private SearchHit createSearchHit (SearchContext context ,
190+ FieldsVisitor fieldsVisitor ,
191+ int docId ,
192+ int subDocId ,
193+ Map <String , Set <String >> storedToRequestedFields ,
194194 LeafReaderContext subReaderContext ) {
195195 if (fieldsVisitor == null ) {
196196 return new SearchHit (docId );
197197 }
198- loadStoredFields (context , subReaderContext , fieldsVisitor , subDocId );
199- fieldsVisitor .postProcess (context .mapperService ());
200198
201- Map <String , DocumentField > searchFields = null ;
202- if (!fieldsVisitor .fields ().isEmpty ()) {
203- searchFields = new HashMap <>(fieldsVisitor .fields ().size ());
204- for (Map .Entry <String , List <Object >> entry : fieldsVisitor .fields ().entrySet ()) {
205- searchFields .put (entry .getKey (), new DocumentField (entry .getKey (), entry .getValue ()));
206- }
207- }
199+ Map <String , DocumentField > searchFields = getSearchFields (context , fieldsVisitor , subDocId ,
200+ storedToRequestedFields , subReaderContext );
208201
209202 DocumentMapper documentMapper = context .mapperService ().documentMapper (fieldsVisitor .uid ().type ());
210203 Text typeText ;
@@ -223,9 +216,40 @@ private SearchHit createSearchHit(SearchContext context, FieldsVisitor fieldsVis
223216 return searchHit ;
224217 }
225218
226- private SearchHit createNestedSearchHit (SearchContext context , int nestedTopDocId , int nestedSubDocId ,
227- int rootSubDocId , Set <String > fieldNames ,
228- List <String > fieldNamePatterns , LeafReaderContext subReaderContext ) throws IOException {
219+ private Map <String , DocumentField > getSearchFields (SearchContext context ,
220+ FieldsVisitor fieldsVisitor ,
221+ int subDocId ,
222+ Map <String , Set <String >> storedToRequestedFields ,
223+ LeafReaderContext subReaderContext ) {
224+ loadStoredFields (context , subReaderContext , fieldsVisitor , subDocId );
225+ fieldsVisitor .postProcess (context .mapperService ());
226+
227+ if (fieldsVisitor .fields ().isEmpty ()) {
228+ return null ;
229+ }
230+
231+ Map <String , DocumentField > searchFields = new HashMap <>(fieldsVisitor .fields ().size ());
232+ for (Map .Entry <String , List <Object >> entry : fieldsVisitor .fields ().entrySet ()) {
233+ String storedField = entry .getKey ();
234+ List <Object > storedValues = entry .getValue ();
235+
236+ if (storedToRequestedFields .containsKey (storedField )) {
237+ for (String requestedField : storedToRequestedFields .get (storedField )) {
238+ searchFields .put (requestedField , new DocumentField (requestedField , storedValues ));
239+ }
240+ } else {
241+ searchFields .put (storedField , new DocumentField (storedField , storedValues ));
242+ }
243+ }
244+ return searchFields ;
245+ }
246+
247+ private SearchHit createNestedSearchHit (SearchContext context ,
248+ int nestedTopDocId ,
249+ int nestedSubDocId ,
250+ int rootSubDocId ,
251+ Map <String , Set <String >> storedToRequestedFields ,
252+ LeafReaderContext subReaderContext ) throws IOException {
229253 // Also if highlighting is requested on nested documents we need to fetch the _source from the root document,
230254 // otherwise highlighting will attempt to fetch the _source from the nested doc, which will fail,
231255 // because the entire _source is only stored with the root document.
@@ -244,9 +268,13 @@ private SearchHit createNestedSearchHit(SearchContext context, int nestedTopDocI
244268 source = null ;
245269 }
246270
271+ Map <String , DocumentField > searchFields = null ;
272+ if (context .hasStoredFields () && !context .storedFieldsContext ().fieldNames ().isEmpty ()) {
273+ FieldsVisitor nestedFieldsVisitor = new CustomFieldsVisitor (storedToRequestedFields .keySet (), false );
274+ searchFields = getSearchFields (context , nestedFieldsVisitor , nestedSubDocId ,
275+ storedToRequestedFields , subReaderContext );
276+ }
247277
248- Map <String , DocumentField > searchFields =
249- getSearchFields (context , nestedSubDocId , fieldNames , fieldNamePatterns , subReaderContext );
250278 DocumentMapper documentMapper = context .mapperService ().documentMapper (uid .type ());
251279 SourceLookup sourceLookup = context .lookup ().source ();
252280 sourceLookup .setSegmentAndDocument (subReaderContext , nestedSubDocId );
@@ -307,26 +335,6 @@ private SearchHit createNestedSearchHit(SearchContext context, int nestedTopDocI
307335 return new SearchHit (nestedTopDocId , uid .id (), documentMapper .typeText (), nestedIdentity , searchFields );
308336 }
309337
310- private Map <String , DocumentField > getSearchFields (SearchContext context , int nestedSubDocId , Set <String > fieldNames ,
311- List <String > fieldNamePatterns , LeafReaderContext subReaderContext ) {
312- Map <String , DocumentField > searchFields = null ;
313- if (context .hasStoredFields () && !context .storedFieldsContext ().fieldNames ().isEmpty ()) {
314- FieldsVisitor nestedFieldsVisitor = new CustomFieldsVisitor (fieldNames == null ? Collections .emptySet () : fieldNames ,
315- fieldNamePatterns == null ? Collections .emptyList () : fieldNamePatterns , false );
316- if (nestedFieldsVisitor != null ) {
317- loadStoredFields (context , subReaderContext , nestedFieldsVisitor , nestedSubDocId );
318- nestedFieldsVisitor .postProcess (context .mapperService ());
319- if (!nestedFieldsVisitor .fields ().isEmpty ()) {
320- searchFields = new HashMap <>(nestedFieldsVisitor .fields ().size ());
321- for (Map .Entry <String , List <Object >> entry : nestedFieldsVisitor .fields ().entrySet ()) {
322- searchFields .put (entry .getKey (), new DocumentField (entry .getKey (), entry .getValue ()));
323- }
324- }
325- }
326- }
327- return searchFields ;
328- }
329-
330338 private SearchHit .NestedIdentity getInternalNestedIdentity (SearchContext context , int nestedSubDocId ,
331339 LeafReaderContext subReaderContext ,
332340 MapperService mapperService ,
0 commit comments