private void addMappers( Collection<ObjectMapper> objectMappers, Collection<FieldMapper> fieldMappers) { assert mappingLock.isWriteLockedByCurrentThread(); // first ensure we don't have any incompatible new fields mapperService.checkNewMappersCompatibility(objectMappers, fieldMappers, true); // update mappers for this document type MapBuilder<String, ObjectMapper> builder = MapBuilder.newMapBuilder(this.objectMappers); for (ObjectMapper objectMapper : objectMappers) { builder.put(objectMapper.fullPath(), objectMapper); if (objectMapper.nested().isNested()) { hasNestedObjects = true; } } this.objectMappers = builder.immutableMap(); this.fieldMappers = this.fieldMappers.copyAndAllAll(fieldMappers); // finally update for the entire index mapperService.addMappers(objectMappers, fieldMappers); }
// never expose this to the outside world, we need to reparse the doc mapper so we get fresh // instances of field mappers to properly remove existing doc mapper private DocumentMapper merge(DocumentMapper mapper, boolean updateAllTypes) { try (ReleasableLock lock = mappingWriteLock.acquire()) { if (mapper.type().length() == 0) { throw new InvalidTypeNameException("mapping type name is empty"); } if (Version.indexCreated(indexSettings).onOrAfter(Version.V_2_0_0_beta1) && mapper.type().length() > 255) { throw new InvalidTypeNameException( "mapping type name [" + mapper.type() + "] is too long; limit is length 255 but was [" + mapper.type().length() + "]"); } if (mapper.type().charAt(0) == '_') { throw new InvalidTypeNameException( "mapping type name [" + mapper.type() + "] can't start with '_'"); } if (mapper.type().contains("#")) { throw new InvalidTypeNameException( "mapping type name [" + mapper.type() + "] should not include '#' in it"); } if (mapper.type().contains(",")) { throw new InvalidTypeNameException( "mapping type name [" + mapper.type() + "] should not include ',' in it"); } if (Version.indexCreated(indexSettings).onOrAfter(Version.V_2_0_0_beta1) && mapper.type().equals(mapper.parentFieldMapper().type())) { throw new IllegalArgumentException( "The [_parent.type] option can't point to the same type"); } if (typeNameStartsWithIllegalDot(mapper)) { if (Version.indexCreated(indexSettings).onOrAfter(Version.V_2_0_0_beta1)) { throw new IllegalArgumentException( "mapping type name [" + mapper.type() + "] must not start with a '.'"); } else { logger.warn( "Type [{}] starts with a '.', it is recommended not to start a type name with a '.'", mapper.type()); } } // we can add new field/object mappers while the old ones are there // since we get new instances of those, and when we remove, we remove // by instance equality DocumentMapper oldMapper = mappers.get(mapper.type()); if (oldMapper != null) { MergeResult result = oldMapper.merge(mapper.mapping(), false, updateAllTypes); if (result.hasConflicts()) { // TODO: What should we do??? if (logger.isDebugEnabled()) { logger.debug( "merging mapping for type [{}] resulted in conflicts: [{}]", mapper.type(), Arrays.toString(result.buildConflicts())); } } return oldMapper; } else { List<ObjectMapper> newObjectMappers = new ArrayList<>(); List<FieldMapper> newFieldMappers = new ArrayList<>(); for (MetadataFieldMapper metadataMapper : mapper.mapping().metadataMappers) { newFieldMappers.add(metadataMapper); } MapperUtils.collect(mapper.mapping().root, newObjectMappers, newFieldMappers); checkNewMappersCompatibility(newObjectMappers, newFieldMappers, updateAllTypes); addMappers(newObjectMappers, newFieldMappers); for (DocumentTypeListener typeListener : typeListeners) { typeListener.beforeCreate(mapper); } mappers = newMapBuilder(mappers).put(mapper.type(), mapper).map(); if (mapper.parentFieldMapper().active()) { ImmutableSet.Builder<String> parentTypesCopy = ImmutableSet.builder(); parentTypesCopy.addAll(parentTypes); parentTypesCopy.add(mapper.parentFieldMapper().type()); parentTypes = parentTypesCopy.build(); } assert assertSerialization(mapper); return mapper; } } }