2121
2222import org .apache .lucene .document .Field ;
2323import org .apache .lucene .index .IndexableField ;
24+ import org .apache .lucene .search .Query ;
2425import org .elasticsearch .ElasticsearchParseException ;
2526import org .elasticsearch .Version ;
2627import org .elasticsearch .common .Strings ;
2930import org .elasticsearch .common .time .DateFormatter ;
3031import org .elasticsearch .common .xcontent .LoggingDeprecationHandler ;
3132import org .elasticsearch .common .xcontent .NamedXContentRegistry ;
33+ import org .elasticsearch .common .xcontent .XContentBuilder ;
3234import org .elasticsearch .common .xcontent .XContentHelper ;
3335import org .elasticsearch .common .xcontent .XContentParser ;
3436import org .elasticsearch .common .xcontent .XContentType ;
3537import org .elasticsearch .index .mapper .DynamicTemplate .XContentFieldType ;
38+ import org .elasticsearch .index .query .QueryShardContext ;
39+ import org .elasticsearch .search .lookup .SearchLookup ;
3640
3741import java .io .IOException ;
3842import java .time .format .DateTimeParseException ;
3943import java .util .ArrayList ;
4044import java .util .Collections ;
45+ import java .util .Comparator ;
4146import java .util .Iterator ;
4247import java .util .List ;
4348import java .util .Objects ;
@@ -224,7 +229,7 @@ static Mapping createDynamicUpdate(Mapping mapping, DocumentMapper docMapper, Li
224229 // We build a mapping by first sorting the mappers, so that all mappers containing a common prefix
225230 // will be processed in a contiguous block. When the prefix is no longer seen, we pop the extra elements
226231 // off the stack, merging them upwards into the existing mappers.
227- Collections .sort (dynamicMappers , (Mapper o1 , Mapper o2 ) -> o1 . name (). compareTo ( o2 . name () ));
232+ dynamicMappers .sort (Comparator . comparing (Mapper :: name ));
228233 Iterator <Mapper > dynamicMapperItr = dynamicMappers .iterator ();
229234 List <ObjectMapper > parentMappers = new ArrayList <>();
230235 Mapper firstUpdate = dynamicMapperItr .next ();
@@ -829,14 +834,14 @@ private static Tuple<Integer, ObjectMapper> getDynamicParentMapper(ParseContext
829834 int pathsAdded = 0 ;
830835 ObjectMapper parent = mapper ;
831836 for (int i = 0 ; i < paths .length -1 ; i ++) {
832- String currentPath = context .path ().pathAsText (paths [i ]);
833- Mapper existingFieldMapper = context .docMapper ().mappers ().getMapper (currentPath );
834- if (existingFieldMapper != null ) {
835- throw new MapperParsingException (
837+ String currentPath = context .path ().pathAsText (paths [i ]);
838+ Mapper existingFieldMapper = context .docMapper ().mappers ().getMapper (currentPath );
839+ if (existingFieldMapper != null ) {
840+ throw new MapperParsingException (
836841 "Could not dynamically add mapping for field [{}]. Existing mapping for [{}] must be of type object but found [{}]." ,
837842 null , String .join ("." , paths ), currentPath , existingFieldMapper .typeName ());
838- }
839- mapper = context .docMapper ().mappers ().objectMappers ().get (currentPath );
843+ }
844+ mapper = context .docMapper ().mappers ().objectMappers ().get (currentPath );
840845 if (mapper == null ) {
841846 // One mapping is missing, check if we are allowed to create a dynamic one.
842847 ObjectMapper .Dynamic dynamic = dynamicOrDefault (parent , context );
@@ -905,7 +910,7 @@ private static Mapper getMapper(final ParseContext context, ObjectMapper objectM
905910
906911 for (int i = 0 ; i < subfields .length - 1 ; ++i ) {
907912 mapper = objectMapper .getMapper (subfields [i ]);
908- if (mapper == null || ( mapper instanceof ObjectMapper ) == false ) {
913+ if (mapper instanceof ObjectMapper == false ) {
909914 return null ;
910915 }
911916 objectMapper = (ObjectMapper )mapper ;
@@ -915,6 +920,93 @@ private static Mapper getMapper(final ParseContext context, ObjectMapper objectM
915920 + mapper .name () + "]" );
916921 }
917922 }
918- return objectMapper .getMapper (subfields [subfields .length - 1 ]);
923+ String leafName = subfields [subfields .length - 1 ];
924+ mapper = objectMapper .getMapper (leafName );
925+ if (mapper != null ) {
926+ return mapper ;
927+ }
928+ //concrete fields take the precedence over runtime fields when parsing documents, though when a field is defined as runtime field
929+ //only, and not under properties, it is ignored when it is sent as part of _source
930+ RuntimeFieldType runtimeFieldType = context .docMapper ().mapping ().root .getRuntimeFieldType (fieldPath );
931+ if (runtimeFieldType != null ) {
932+ return new NoOpFieldMapper (leafName , runtimeFieldType );
933+ }
934+ return null ;
935+ }
936+
937+ private static class NoOpFieldMapper extends FieldMapper {
938+ NoOpFieldMapper (String simpleName , RuntimeFieldType runtimeField ) {
939+ super (simpleName , new MappedFieldType (runtimeField .name (), false , false , false , TextSearchInfo .NONE , Collections .emptyMap ()) {
940+ @ Override
941+ public ValueFetcher valueFetcher (QueryShardContext context , SearchLookup searchLookup , String format ) {
942+ throw new UnsupportedOperationException ();
943+ }
944+
945+ @ Override
946+ public String typeName () {
947+ throw new UnsupportedOperationException ();
948+ }
949+
950+ @ Override
951+ public Query termQuery (Object value , QueryShardContext context ) {
952+ throw new UnsupportedOperationException ();
953+ }
954+ }, MultiFields .empty (), CopyTo .empty ());
955+ }
956+
957+ @ Override
958+ protected void parseCreateField (ParseContext context ) throws IOException {
959+ //field defined as runtime field, don't index anything
960+ }
961+
962+ @ Override
963+ public String name () {
964+ throw new UnsupportedOperationException ();
965+ }
966+
967+ @ Override
968+ public String typeName () {
969+ throw new UnsupportedOperationException ();
970+ }
971+
972+ @ Override
973+ public MappedFieldType fieldType () {
974+ throw new UnsupportedOperationException ();
975+ }
976+
977+ @ Override
978+ public MultiFields multiFields () {
979+ throw new UnsupportedOperationException ();
980+ }
981+
982+ @ Override
983+ public Iterator <Mapper > iterator () {
984+ throw new UnsupportedOperationException ();
985+ }
986+
987+ @ Override
988+ protected void doValidate (MappingLookup mappers ) {
989+ throw new UnsupportedOperationException ();
990+ }
991+
992+ @ Override
993+ protected void checkIncomingMergeType (FieldMapper mergeWith ) {
994+ throw new UnsupportedOperationException ();
995+ }
996+
997+ @ Override
998+ public Builder getMergeBuilder () {
999+ throw new UnsupportedOperationException ();
1000+ }
1001+
1002+ @ Override
1003+ public XContentBuilder toXContent (XContentBuilder builder , Params params ) throws IOException {
1004+ throw new UnsupportedOperationException ();
1005+ }
1006+
1007+ @ Override
1008+ protected String contentType () {
1009+ throw new UnsupportedOperationException ();
1010+ }
9191011 }
9201012}
0 commit comments