Browse Source

Introduce MapperMergeContext (#104512)

Currently, this is basically a noop. This is in preparation for
https://github.com/elastic/elasticsearch/pull/102936, in an effort to
reduce the mechanical changes.
Felix Barnsteiner 1 year ago
parent
commit
f84c015a27

+ 1 - 1
server/src/main/java/org/elasticsearch/index/mapper/DocumentParser.java

@@ -822,7 +822,7 @@ public final class DocumentParser {
         }
 
         @Override
-        public ObjectMapper merge(Mapper mergeWith, MapperBuilderContext mapperBuilderContext) {
+        public ObjectMapper merge(Mapper mergeWith, MapperMergeContext mapperMergeContext) {
             return this;
         }
     }

+ 1 - 1
server/src/main/java/org/elasticsearch/index/mapper/FieldAliasMapper.java

@@ -55,7 +55,7 @@ public final class FieldAliasMapper extends Mapper {
     }
 
     @Override
-    public Mapper merge(Mapper mergeWith, MapperBuilderContext mapperBuilderContext) {
+    public Mapper merge(Mapper mergeWith, MapperMergeContext mapperMergeContext) {
         if ((mergeWith instanceof FieldAliasMapper) == false) {
             throw new IllegalArgumentException(
                 "Cannot merge a field alias mapping [" + name() + "] with a mapping that is not for a field alias."

+ 7 - 7
server/src/main/java/org/elasticsearch/index/mapper/FieldMapper.java

@@ -372,7 +372,7 @@ public abstract class FieldMapper extends Mapper {
     public abstract Builder getMergeBuilder();
 
     @Override
-    public final FieldMapper merge(Mapper mergeWith, MapperBuilderContext mapperBuilderContext) {
+    public final FieldMapper merge(Mapper mergeWith, MapperMergeContext mapperMergeContext) {
         if (mergeWith == this) {
             return this;
         }
@@ -394,9 +394,9 @@ public abstract class FieldMapper extends Mapper {
             return (FieldMapper) mergeWith;
         }
         Conflicts conflicts = new Conflicts(name());
-        builder.merge((FieldMapper) mergeWith, conflicts, mapperBuilderContext);
+        builder.merge((FieldMapper) mergeWith, conflicts, mapperMergeContext);
         conflicts.check();
-        return builder.build(mapperBuilderContext);
+        return builder.build(mapperMergeContext.getMapperBuilderContext());
     }
 
     protected void checkIncomingMergeType(FieldMapper mergeWith) {
@@ -454,11 +454,11 @@ public abstract class FieldMapper extends Mapper {
                 return this;
             }
 
-            public Builder update(FieldMapper toMerge, MapperBuilderContext context) {
+            public Builder update(FieldMapper toMerge, MapperMergeContext context) {
                 if (mapperBuilders.containsKey(toMerge.simpleName()) == false) {
                     add(toMerge);
                 } else {
-                    FieldMapper existing = mapperBuilders.get(toMerge.simpleName()).apply(context);
+                    FieldMapper existing = mapperBuilders.get(toMerge.simpleName()).apply(context.getMapperBuilderContext());
                     add(existing.merge(toMerge, context));
                 }
                 return this;
@@ -1220,11 +1220,11 @@ public abstract class FieldMapper extends Mapper {
             return this;
         }
 
-        protected void merge(FieldMapper in, Conflicts conflicts, MapperBuilderContext mapperBuilderContext) {
+        protected void merge(FieldMapper in, Conflicts conflicts, MapperMergeContext mapperMergeContext) {
             for (Parameter<?> param : getParameters()) {
                 param.merge(in, conflicts);
             }
-            MapperBuilderContext childContext = mapperBuilderContext.createChildContext(in.simpleName());
+            MapperMergeContext childContext = mapperMergeContext.createChildContext(in.simpleName());
             for (FieldMapper newSubField : in.multiFields.mappers) {
                 multiFieldsBuilder.update(newSubField, childContext);
             }

+ 5 - 3
server/src/main/java/org/elasticsearch/index/mapper/Mapper.java

@@ -73,9 +73,11 @@ public abstract class Mapper implements ToXContentFragment, Iterable<Mapper> {
      */
     public abstract String typeName();
 
-    /** Return the merge of {@code mergeWith} into this.
-     *  Both {@code this} and {@code mergeWith} will be left unmodified. */
-    public abstract Mapper merge(Mapper mergeWith, MapperBuilderContext mapperBuilderContext);
+    /**
+     * Return the merge of {@code mergeWith} into this.
+     *  Both {@code this} and {@code mergeWith} will be left unmodified.
+     */
+    public abstract Mapper merge(Mapper mergeWith, MapperMergeContext mapperMergeContext);
 
     /**
      * Validate any cross-field references made by this mapper

+ 52 - 0
server/src/main/java/org/elasticsearch/index/mapper/MapperMergeContext.java

@@ -0,0 +1,52 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0 and the Server Side Public License, v 1; you may not use this file except
+ * in compliance with, at your election, the Elastic License 2.0 or the Server
+ * Side Public License, v 1.
+ */
+
+package org.elasticsearch.index.mapper;
+
+/**
+ * Holds context used when merging mappings.
+ * As the merge process also involves building merged {@link Mapper.Builder}s,
+ * this also contains a {@link MapperBuilderContext}.
+ */
+public final class MapperMergeContext {
+
+    private final MapperBuilderContext mapperBuilderContext;
+
+    /**
+     * The root context, to be used when merging a tree of mappers
+     */
+    public static MapperMergeContext root(boolean isSourceSynthetic, boolean isDataStream) {
+        return new MapperMergeContext(MapperBuilderContext.root(isSourceSynthetic, isDataStream));
+    }
+
+    /**
+     * Creates a new {@link MapperMergeContext} from a {@link MapperBuilderContext}
+     * @param mapperBuilderContext the {@link MapperBuilderContext} for this {@link MapperMergeContext}
+     * @return a new {@link MapperMergeContext}, wrapping the provided {@link MapperBuilderContext}
+     */
+    public static MapperMergeContext from(MapperBuilderContext mapperBuilderContext) {
+        return new MapperMergeContext(mapperBuilderContext);
+    }
+
+    private MapperMergeContext(MapperBuilderContext mapperBuilderContext) {
+        this.mapperBuilderContext = mapperBuilderContext;
+    }
+
+    /**
+     * Creates a new {@link MapperMergeContext} that is a child of this context
+     * @param name the name of the child context
+     * @return a new {@link MapperMergeContext} with this context as its parent
+     */
+    public MapperMergeContext createChildContext(String name) {
+        return new MapperMergeContext(mapperBuilderContext.createChildContext(name));
+    }
+
+    MapperBuilderContext getMapperBuilderContext() {
+        return mapperBuilderContext;
+    }
+}

+ 2 - 2
server/src/main/java/org/elasticsearch/index/mapper/Mapping.java

@@ -136,7 +136,7 @@ public final class Mapping implements ToXContentFragment {
      * @return the resulting merged mapping.
      */
     Mapping merge(Mapping mergeWith, MergeReason reason) {
-        RootObjectMapper mergedRoot = root.merge(mergeWith.root, reason, MapperBuilderContext.root(isSourceSynthetic(), false));
+        RootObjectMapper mergedRoot = root.merge(mergeWith.root, reason, MapperMergeContext.root(isSourceSynthetic(), false));
 
         // When merging metadata fields as part of applying an index template, new field definitions
         // completely overwrite existing ones instead of being merged. This behavior matches how we
@@ -148,7 +148,7 @@ public final class Mapping implements ToXContentFragment {
             if (mergeInto == null || reason == MergeReason.INDEX_TEMPLATE) {
                 merged = metaMergeWith;
             } else {
-                merged = (MetadataFieldMapper) mergeInto.merge(metaMergeWith, MapperBuilderContext.root(isSourceSynthetic(), false));
+                merged = (MetadataFieldMapper) mergeInto.merge(metaMergeWith, MapperMergeContext.root(isSourceSynthetic(), false));
             }
             mergedMetadataMappers.put(merged.getClass(), merged);
         }

+ 6 - 4
server/src/main/java/org/elasticsearch/index/mapper/NestedObjectMapper.java

@@ -207,12 +207,12 @@ public class NestedObjectMapper extends ObjectMapper {
     }
 
     @Override
-    public ObjectMapper merge(Mapper mergeWith, MapperService.MergeReason reason, MapperBuilderContext parentBuilderContext) {
+    public ObjectMapper merge(Mapper mergeWith, MapperService.MergeReason reason, MapperMergeContext parentMergeContext) {
         if ((mergeWith instanceof NestedObjectMapper) == false) {
             MapperErrors.throwNestedMappingConflictError(mergeWith.name());
         }
         NestedObjectMapper mergeWithObject = (NestedObjectMapper) mergeWith;
-        var mergeResult = MergeResult.build(this, mergeWith, reason, parentBuilderContext);
+        var mergeResult = MergeResult.build(this, mergeWith, reason, parentMergeContext);
         Explicit<Boolean> incInParent = this.includeInParent;
         Explicit<Boolean> incInRoot = this.includeInRoot;
         if (reason == MapperService.MergeReason.INDEX_TEMPLATE) {
@@ -230,6 +230,7 @@ public class NestedObjectMapper extends ObjectMapper {
                 throw new MapperException("the [include_in_root] parameter can't be updated on a nested object mapping");
             }
         }
+        MapperBuilderContext parentBuilderContext = parentMergeContext.getMapperBuilderContext();
         if (parentBuilderContext instanceof NestedMapperBuilderContext nc) {
             if (nc.parentIncludedInRoot && incInParent.value()) {
                 incInRoot = Explicit.IMPLICIT_FALSE;
@@ -253,12 +254,13 @@ public class NestedObjectMapper extends ObjectMapper {
     }
 
     @Override
-    protected MapperBuilderContext createChildContext(MapperBuilderContext mapperBuilderContext, String name) {
+    protected MapperMergeContext createChildContext(MapperMergeContext mapperMergeContext, String name) {
+        MapperBuilderContext mapperBuilderContext = mapperMergeContext.getMapperBuilderContext();
         boolean parentIncludedInRoot = this.includeInRoot.value();
         if (mapperBuilderContext instanceof NestedMapperBuilderContext == false) {
             parentIncludedInRoot |= this.includeInParent.value();
         }
-        return new NestedMapperBuilderContext(mapperBuilderContext.buildFullName(name), parentIncludedInRoot);
+        return MapperMergeContext.from(new NestedMapperBuilderContext(mapperBuilderContext.buildFullName(name), parentIncludedInRoot));
     }
 
     @Override

+ 13 - 13
server/src/main/java/org/elasticsearch/index/mapper/ObjectMapper.java

@@ -162,7 +162,7 @@ public class ObjectMapper extends Mapper {
                     // This can also happen due to multiple index templates being merged into a single mappings definition using
                     // XContentHelper#mergeDefaults, again in case some index templates contained mappings for the same field using a
                     // mix of object notation and dot notation.
-                    mapper = existing.merge(mapper, mapperBuilderContext);
+                    mapper = existing.merge(mapper, MapperMergeContext.from(mapperBuilderContext));
                 }
                 mappers.put(mapper.simpleName(), mapper);
             }
@@ -443,8 +443,8 @@ public class ObjectMapper extends Mapper {
     }
 
     @Override
-    public ObjectMapper merge(Mapper mergeWith, MapperBuilderContext mapperBuilderContext) {
-        return merge(mergeWith, MergeReason.MAPPING_UPDATE, mapperBuilderContext);
+    public ObjectMapper merge(Mapper mergeWith, MapperMergeContext mapperMergeContext) {
+        return merge(mergeWith, MergeReason.MAPPING_UPDATE, mapperMergeContext);
     }
 
     @Override
@@ -454,12 +454,12 @@ public class ObjectMapper extends Mapper {
         }
     }
 
-    protected MapperBuilderContext createChildContext(MapperBuilderContext mapperBuilderContext, String name) {
-        return mapperBuilderContext.createChildContext(name);
+    protected MapperMergeContext createChildContext(MapperMergeContext mapperMergeContext, String name) {
+        return mapperMergeContext.createChildContext(name);
     }
 
-    public ObjectMapper merge(Mapper mergeWith, MergeReason reason, MapperBuilderContext parentBuilderContext) {
-        var mergeResult = MergeResult.build(this, mergeWith, reason, parentBuilderContext);
+    public ObjectMapper merge(Mapper mergeWith, MergeReason reason, MapperMergeContext parentMergeContext) {
+        var mergeResult = MergeResult.build(this, mergeWith, reason, parentMergeContext);
         return new ObjectMapper(
             simpleName(),
             fullPath,
@@ -481,7 +481,7 @@ public class ObjectMapper extends Mapper {
             ObjectMapper existing,
             Mapper mergeWith,
             MergeReason reason,
-            MapperBuilderContext parentBuilderContext
+            MapperMergeContext parentMergeContext
         ) {
             if ((mergeWith instanceof ObjectMapper) == false) {
                 MapperErrors.throwObjectMappingConflictError(mergeWith.name());
@@ -517,8 +517,8 @@ public class ObjectMapper extends Mapper {
             } else {
                 subObjects = existing.subobjects;
             }
-            MapperBuilderContext objectBuilderContext = existing.createChildContext(parentBuilderContext, existing.simpleName());
-            Map<String, Mapper> mergedMappers = buildMergedMappers(existing, mergeWith, reason, objectBuilderContext);
+            MapperMergeContext objectMergeContext = existing.createChildContext(parentMergeContext, existing.simpleName());
+            Map<String, Mapper> mergedMappers = buildMergedMappers(existing, mergeWith, reason, objectMergeContext);
             return new MergeResult(
                 enabled,
                 subObjects,
@@ -531,7 +531,7 @@ public class ObjectMapper extends Mapper {
             ObjectMapper existing,
             Mapper mergeWith,
             MergeReason reason,
-            MapperBuilderContext objectBuilderContext
+            MapperMergeContext objectMergeContext
         ) {
             Map<String, Mapper> mergedMappers = null;
             for (Mapper mergeWithMapper : mergeWith) {
@@ -541,7 +541,7 @@ public class ObjectMapper extends Mapper {
                 if (mergeIntoMapper == null) {
                     merged = mergeWithMapper;
                 } else if (mergeIntoMapper instanceof ObjectMapper objectMapper) {
-                    merged = objectMapper.merge(mergeWithMapper, reason, objectBuilderContext);
+                    merged = objectMapper.merge(mergeWithMapper, reason, objectMergeContext);
                 } else {
                     assert mergeIntoMapper instanceof FieldMapper || mergeIntoMapper instanceof FieldAliasMapper;
                     if (mergeWithMapper instanceof NestedObjectMapper) {
@@ -555,7 +555,7 @@ public class ObjectMapper extends Mapper {
                     if (reason == MergeReason.INDEX_TEMPLATE) {
                         merged = mergeWithMapper;
                     } else {
-                        merged = mergeIntoMapper.merge(mergeWithMapper, objectBuilderContext);
+                        merged = mergeIntoMapper.merge(mergeWithMapper, objectMergeContext);
                     }
                 }
                 if (mergedMappers == null) {

+ 2 - 2
server/src/main/java/org/elasticsearch/index/mapper/PlaceHolderFieldMapper.java

@@ -63,10 +63,10 @@ public class PlaceHolderFieldMapper extends FieldMapper {
         }
 
         @Override
-        protected void merge(FieldMapper in, Conflicts conflicts, MapperBuilderContext mapperBuilderContext) {
+        protected void merge(FieldMapper in, Conflicts conflicts, MapperMergeContext mapperMergeContext) {
             assert in instanceof PlaceHolderFieldMapper;
             unknownParams.putAll(((PlaceHolderFieldMapper) in).unknownParams);
-            super.merge(in, conflicts, mapperBuilderContext);
+            super.merge(in, conflicts, mapperMergeContext);
         }
 
         @Override

+ 5 - 5
server/src/main/java/org/elasticsearch/index/mapper/RootObjectMapper.java

@@ -192,14 +192,14 @@ public class RootObjectMapper extends ObjectMapper {
     }
 
     @Override
-    protected MapperBuilderContext createChildContext(MapperBuilderContext mapperBuilderContext, String name) {
-        assert Objects.equals(mapperBuilderContext.buildFullName("foo"), "foo");
-        return mapperBuilderContext;
+    protected MapperMergeContext createChildContext(MapperMergeContext mapperMergeContext, String name) {
+        assert Objects.equals(mapperMergeContext.getMapperBuilderContext().buildFullName("foo"), "foo");
+        return mapperMergeContext;
     }
 
     @Override
-    public RootObjectMapper merge(Mapper mergeWith, MergeReason reason, MapperBuilderContext parentBuilderContext) {
-        final var mergeResult = MergeResult.build(this, mergeWith, reason, parentBuilderContext);
+    public RootObjectMapper merge(Mapper mergeWith, MergeReason reason, MapperMergeContext parentMergeContext) {
+        final var mergeResult = MergeResult.build(this, mergeWith, reason, parentMergeContext);
         final Explicit<Boolean> numericDetection;
         RootObjectMapper mergeWithObject = (RootObjectMapper) mergeWith;
         if (mergeWithObject.numericDetection.explicit()) {

+ 2 - 2
server/src/test/java/org/elasticsearch/index/mapper/NestedObjectMapperTests.java

@@ -1508,14 +1508,14 @@ public class NestedObjectMapperTests extends MapperServiceTestCase {
 
         MapperException e = expectThrows(
             MapperException.class,
-            () -> firstMapper.merge(secondMapper, MapperBuilderContext.root(false, false))
+            () -> firstMapper.merge(secondMapper, MapperMergeContext.root(false, false))
         );
         assertThat(e.getMessage(), containsString("[include_in_parent] parameter can't be updated on a nested object mapping"));
 
         NestedObjectMapper result = (NestedObjectMapper) firstMapper.merge(
             secondMapper,
             MapperService.MergeReason.INDEX_TEMPLATE,
-            MapperBuilderContext.root(false, false)
+            MapperMergeContext.root(false, false)
         );
         assertFalse(result.isIncludeInParent());
         assertTrue(result.isIncludeInRoot());

+ 12 - 12
server/src/test/java/org/elasticsearch/index/mapper/ObjectMapperMergeTests.java

@@ -41,7 +41,7 @@ public final class ObjectMapperMergeTests extends ESTestCase {
         ObjectMapper mergeWith = createMapping(false, true, true, true);
 
         // WHEN merging mappings
-        final ObjectMapper merged = rootObjectMapper.merge(mergeWith, MapperBuilderContext.root(false, false));
+        final ObjectMapper merged = rootObjectMapper.merge(mergeWith, MapperMergeContext.root(false, false));
 
         // THEN "baz" new field is added to merged mapping
         final ObjectMapper mergedFoo = (ObjectMapper) merged.getMapper("foo");
@@ -63,7 +63,7 @@ public final class ObjectMapperMergeTests extends ESTestCase {
         // THEN a MapperException is thrown with an excepted message
         MapperException e = expectThrows(
             MapperException.class,
-            () -> rootObjectMapper.merge(mergeWith, MapperBuilderContext.root(false, false))
+            () -> rootObjectMapper.merge(mergeWith, MapperMergeContext.root(false, false))
         );
         assertEquals("the [enabled] parameter can't be updated for the object mapping [foo]", e.getMessage());
     }
@@ -75,7 +75,7 @@ public final class ObjectMapperMergeTests extends ESTestCase {
             new ObjectMapper.Builder("disabled", Explicit.IMPLICIT_TRUE)
         ).build(MapperBuilderContext.root(false, false));
 
-        RootObjectMapper merged = (RootObjectMapper) rootObjectMapper.merge(mergeWith, MapperBuilderContext.root(false, false));
+        RootObjectMapper merged = (RootObjectMapper) rootObjectMapper.merge(mergeWith, MapperMergeContext.root(false, false));
         assertFalse(((ObjectMapper) merged.getMapper("disabled")).isEnabled());
     }
 
@@ -84,14 +84,14 @@ public final class ObjectMapperMergeTests extends ESTestCase {
 
         MapperException e = expectThrows(
             MapperException.class,
-            () -> rootObjectMapper.merge(mergeWith, MapperBuilderContext.root(false, false))
+            () -> rootObjectMapper.merge(mergeWith, MapperMergeContext.root(false, false))
         );
         assertEquals("the [enabled] parameter can't be updated for the object mapping [disabled]", e.getMessage());
 
         ObjectMapper result = rootObjectMapper.merge(
             mergeWith,
             MapperService.MergeReason.INDEX_TEMPLATE,
-            MapperBuilderContext.root(false, false)
+            MapperMergeContext.root(false, false)
         );
         assertTrue(result.isEnabled());
     }
@@ -106,14 +106,14 @@ public final class ObjectMapperMergeTests extends ESTestCase {
 
         MapperException e = expectThrows(
             MapperException.class,
-            () -> firstMapper.merge(secondMapper, MapperBuilderContext.root(false, false))
+            () -> firstMapper.merge(secondMapper, MapperMergeContext.root(false, false))
         );
         assertEquals("the [enabled] parameter can't be updated for the object mapping [" + type + "]", e.getMessage());
 
         ObjectMapper result = firstMapper.merge(
             secondMapper,
             MapperService.MergeReason.INDEX_TEMPLATE,
-            MapperBuilderContext.root(false, false)
+            MapperMergeContext.root(false, false)
         );
         assertFalse(result.isEnabled());
     }
@@ -128,7 +128,7 @@ public final class ObjectMapperMergeTests extends ESTestCase {
             Collections.singletonMap("test", new TestRuntimeField("test", "long"))
         ).build(MapperBuilderContext.root(false, false));
 
-        RootObjectMapper merged = (RootObjectMapper) rootObjectMapper.merge(mergeWith, MapperBuilderContext.root(false, false));
+        RootObjectMapper merged = (RootObjectMapper) rootObjectMapper.merge(mergeWith, MapperMergeContext.root(false, false));
         assertFalse(merged.isEnabled());
         assertEquals(1, merged.runtimeFields().size());
         assertEquals("test", merged.runtimeFields().iterator().next().name());
@@ -138,7 +138,7 @@ public final class ObjectMapperMergeTests extends ESTestCase {
         RootObjectMapper mergeInto = createRootSubobjectFalseLeafWithDots();
         RootObjectMapper mergeWith = createRootSubobjectFalseLeafWithDots();
 
-        final ObjectMapper merged = mergeInto.merge(mergeWith, MapperBuilderContext.root(false, false));
+        final ObjectMapper merged = mergeInto.merge(mergeWith, MapperMergeContext.root(false, false));
 
         final KeywordFieldMapper keywordFieldMapper = (KeywordFieldMapper) merged.getMapper("host.name");
         assertEquals("host.name", keywordFieldMapper.name());
@@ -153,7 +153,7 @@ public final class ObjectMapperMergeTests extends ESTestCase {
             createObjectSubobjectsFalseLeafWithDots()
         ).build(MapperBuilderContext.root(false, false));
 
-        final ObjectMapper merged = mergeInto.merge(mergeWith, MapperBuilderContext.root(false, false));
+        final ObjectMapper merged = mergeInto.merge(mergeWith, MapperMergeContext.root(false, false));
 
         ObjectMapper foo = (ObjectMapper) merged.getMapper("foo");
         ObjectMapper metrics = (ObjectMapper) foo.getMapper("metrics");
@@ -168,7 +168,7 @@ public final class ObjectMapperMergeTests extends ESTestCase {
         RootObjectMapper mergeWith = new RootObjectMapper.Builder("_doc", Explicit.IMPLICIT_TRUE).add(createTextKeywordMultiField("text"))
             .build(MapperBuilderContext.root(false, false));
 
-        final ObjectMapper merged = mergeInto.merge(mergeWith, MapperBuilderContext.root(false, false));
+        final ObjectMapper merged = mergeInto.merge(mergeWith, MapperMergeContext.root(false, false));
 
         TextFieldMapper text = (TextFieldMapper) merged.getMapper("text");
         assertEquals("text", text.name());
@@ -186,7 +186,7 @@ public final class ObjectMapperMergeTests extends ESTestCase {
             createObjectSubobjectsFalseLeafWithMultiField()
         ).build(MapperBuilderContext.root(false, false));
 
-        final ObjectMapper merged = mergeInto.merge(mergeWith, MapperBuilderContext.root(false, false));
+        final ObjectMapper merged = mergeInto.merge(mergeWith, MapperMergeContext.root(false, false));
 
         ObjectMapper foo = (ObjectMapper) merged.getMapper("foo");
         ObjectMapper metrics = (ObjectMapper) foo.getMapper("metrics");

+ 8 - 8
server/src/test/java/org/elasticsearch/index/mapper/ParametrizedMapperTests.java

@@ -345,7 +345,7 @@ public class ParametrizedMapperTests extends MapperServiceTestCase {
             {"type":"test_mapper","fixed":true,"fixed2":true,"required":"value"}""");
         IllegalArgumentException e = expectThrows(
             IllegalArgumentException.class,
-            () -> mapper.merge(badMerge, MapperBuilderContext.root(false, false))
+            () -> mapper.merge(badMerge, MapperMergeContext.root(false, false))
         );
         String expectedError = """
             Mapper for [field] conflicts with existing mapper:
@@ -358,7 +358,7 @@ public class ParametrizedMapperTests extends MapperServiceTestCase {
         // TODO: should we have to include 'fixed' here? Or should updates take as 'defaults' the existing values?
         TestMapper goodMerge = fromMapping("""
             {"type":"test_mapper","fixed":false,"variable":"updated","required":"value"}""");
-        TestMapper merged = (TestMapper) mapper.merge(goodMerge, MapperBuilderContext.root(false, false));
+        TestMapper merged = (TestMapper) mapper.merge(goodMerge, MapperMergeContext.root(false, false));
 
         assertEquals("{\"field\":" + mapping + "}", Strings.toString(mapper)); // original mapping is unaffected
         assertEquals("""
@@ -376,7 +376,7 @@ public class ParametrizedMapperTests extends MapperServiceTestCase {
         String addSubField = """
             {"type":"test_mapper","variable":"foo","required":"value","fields":{"sub2":{"type":"keyword"}}}""";
         TestMapper toMerge = fromMapping(addSubField);
-        TestMapper merged = (TestMapper) mapper.merge(toMerge, MapperBuilderContext.root(false, false));
+        TestMapper merged = (TestMapper) mapper.merge(toMerge, MapperMergeContext.root(false, false));
         assertEquals(XContentHelper.stripWhitespace("""
             {
               "field": {
@@ -399,7 +399,7 @@ public class ParametrizedMapperTests extends MapperServiceTestCase {
         TestMapper badToMerge = fromMapping(badSubField);
         IllegalArgumentException e = expectThrows(
             IllegalArgumentException.class,
-            () -> merged.merge(badToMerge, MapperBuilderContext.root(false, false))
+            () -> merged.merge(badToMerge, MapperMergeContext.root(false, false))
         );
         assertEquals("mapper [field.sub2] cannot be changed from type [keyword] to [binary]", e.getMessage());
     }
@@ -415,13 +415,13 @@ public class ParametrizedMapperTests extends MapperServiceTestCase {
 
         TestMapper toMerge = fromMapping("""
             {"type":"test_mapper","variable":"updated","required":"value","copy_to":["foo","bar"]}""");
-        TestMapper merged = (TestMapper) mapper.merge(toMerge, MapperBuilderContext.root(false, false));
+        TestMapper merged = (TestMapper) mapper.merge(toMerge, MapperMergeContext.root(false, false));
         assertEquals("""
             {"field":{"type":"test_mapper","variable":"updated","required":"value","copy_to":["foo","bar"]}}""", Strings.toString(merged));
 
         TestMapper removeCopyTo = fromMapping("""
             {"type":"test_mapper","variable":"updated","required":"value"}""");
-        TestMapper noCopyTo = (TestMapper) merged.merge(removeCopyTo, MapperBuilderContext.root(false, false));
+        TestMapper noCopyTo = (TestMapper) merged.merge(removeCopyTo, MapperMergeContext.root(false, false));
         assertEquals("""
             {"field":{"type":"test_mapper","variable":"updated","required":"value"}}""", Strings.toString(noCopyTo));
     }
@@ -487,7 +487,7 @@ public class ParametrizedMapperTests extends MapperServiceTestCase {
         TestMapper toMerge = fromMapping(conflict);
         IllegalArgumentException e = expectThrows(
             IllegalArgumentException.class,
-            () -> mapper.merge(toMerge, MapperBuilderContext.root(false, false))
+            () -> mapper.merge(toMerge, MapperMergeContext.root(false, false))
         );
         assertEquals(
             "Mapper for [field] conflicts with existing mapper:\n"
@@ -576,7 +576,7 @@ public class ParametrizedMapperTests extends MapperServiceTestCase {
 
         TestMapper original = mapper;
         TestMapper toMerge = fromMapping(mapping);
-        e = expectThrows(IllegalArgumentException.class, () -> original.merge(toMerge, MapperBuilderContext.root(false, false)));
+        e = expectThrows(IllegalArgumentException.class, () -> original.merge(toMerge, MapperMergeContext.root(false, false)));
         assertEquals(
             "Mapper for [field] conflicts with existing mapper:\n" + "\tCannot update parameter [analyzer] from [default] to [_standard]",
             e.getMessage()