32
32
import org .elasticsearch .ElasticsearchGenerationException ;
33
33
import org .elasticsearch .Version ;
34
34
import org .elasticsearch .common .Nullable ;
35
- import org .elasticsearch .common .collect .ImmutableOpenMap ;
36
35
import org .elasticsearch .common .collect .Tuple ;
37
36
import org .elasticsearch .common .compress .CompressedXContent ;
38
37
import org .elasticsearch .common .lucene .search .Queries ;
@@ -92,7 +91,7 @@ public class MapperService extends AbstractIndexComponent implements Closeable {
92
91
private final ReleasableLock mappingWriteLock = new ReleasableLock (mappingLock .writeLock ());
93
92
94
93
private volatile FieldTypeLookup fieldTypes ;
95
- private volatile ImmutableOpenMap <String , ObjectMapper > fullPathObjectMappers = ImmutableOpenMap . of ();
94
+ private volatile Map <String , ObjectMapper > fullPathObjectMappers = new HashMap <> ();
96
95
private boolean hasNested = false ; // updated dynamically to true when a nested object is added
97
96
98
97
private final DocumentMapperParser documentParser ;
@@ -300,8 +299,41 @@ private boolean assertSerialization(DocumentMapper mapper) {
300
299
return true ;
301
300
}
302
301
302
+ private void checkFieldUniqueness (String type , Collection <ObjectMapper > objectMappers , Collection <FieldMapper > fieldMappers ) {
303
+ final Set <String > objectFullNames = new HashSet <>();
304
+ for (ObjectMapper objectMapper : objectMappers ) {
305
+ final String fullPath = objectMapper .fullPath ();
306
+ if (objectFullNames .add (fullPath ) == false ) {
307
+ throw new IllegalArgumentException ("Object mapper [" + fullPath + "] is defined twice in mapping for type [" + type + "]" );
308
+ }
309
+ }
310
+
311
+ if (indexSettings .getIndexVersionCreated ().before (Version .V_3_0_0 )) {
312
+ // Before 3.0 some metadata mappers are also registered under the root object mapper
313
+ // So we avoid false positives by deduplicating mappers
314
+ // given that we check exact equality, this would still catch the case that a mapper
315
+ // is defined under the root object
316
+ Collection <FieldMapper > uniqueFieldMappers = Collections .newSetFromMap (new IdentityHashMap <>());
317
+ uniqueFieldMappers .addAll (fieldMappers );
318
+ fieldMappers = uniqueFieldMappers ;
319
+ }
320
+
321
+ final Set <String > fieldNames = new HashSet <>();
322
+ for (FieldMapper fieldMapper : fieldMappers ) {
323
+ final String name = fieldMapper .name ();
324
+ if (objectFullNames .contains (name )) {
325
+ throw new IllegalArgumentException ("Field [" + name + "] is defined both as an object and a field in [" + type + "]" );
326
+ } else if (fieldNames .add (name ) == false ) {
327
+ throw new IllegalArgumentException ("Field [" + name + "] is defined twice in [" + type + "]" );
328
+ }
329
+ }
330
+ }
331
+
303
332
protected void checkMappersCompatibility (String type , Collection <ObjectMapper > objectMappers , Collection <FieldMapper > fieldMappers , boolean updateAllTypes ) {
304
333
assert mappingLock .isWriteLockedByCurrentThread ();
334
+
335
+ checkFieldUniqueness (type , objectMappers , fieldMappers );
336
+
305
337
for (ObjectMapper newObjectMapper : objectMappers ) {
306
338
ObjectMapper existingObjectMapper = fullPathObjectMappers .get (newObjectMapper .fullPath ());
307
339
if (existingObjectMapper != null ) {
@@ -313,6 +345,13 @@ protected void checkMappersCompatibility(String type, Collection<ObjectMapper> o
313
345
}
314
346
}
315
347
}
348
+
349
+ for (FieldMapper fieldMapper : fieldMappers ) {
350
+ if (fullPathObjectMappers .containsKey (fieldMapper .name ())) {
351
+ throw new IllegalArgumentException ("Field [{}] is defined as a field in mapping [" + fieldMapper .name () + "] but this name is already used for an object in other types" );
352
+ }
353
+ }
354
+
316
355
fieldTypes .checkCompatibility (type , fieldMappers , updateAllTypes );
317
356
}
318
357
@@ -330,14 +369,14 @@ protected Tuple<Collection<ObjectMapper>, Collection<FieldMapper>> checkMappersC
330
369
331
370
protected void addMappers (String type , Collection <ObjectMapper > objectMappers , Collection <FieldMapper > fieldMappers ) {
332
371
assert mappingLock .isWriteLockedByCurrentThread ();
333
- ImmutableOpenMap . Builder <String , ObjectMapper > fullPathObjectMappers = ImmutableOpenMap . builder (this .fullPathObjectMappers );
372
+ Map <String , ObjectMapper > fullPathObjectMappers = new HashMap <> (this .fullPathObjectMappers );
334
373
for (ObjectMapper objectMapper : objectMappers ) {
335
374
fullPathObjectMappers .put (objectMapper .fullPath (), objectMapper );
336
375
if (objectMapper .nested ().isNested ()) {
337
376
hasNested = true ;
338
377
}
339
378
}
340
- this .fullPathObjectMappers = fullPathObjectMappers . build ( );
379
+ this .fullPathObjectMappers = Collections . unmodifiableMap ( fullPathObjectMappers );
341
380
this .fieldTypes = this .fieldTypes .copyAndAddAll (type , fieldMappers );
342
381
}
343
382
0 commit comments