Merge pull request #15539 from jpountz/fix/immutable_document_mapper

Make mapping updates more robust.
This commit is contained in:
Adrien Grand 2015-12-23 09:55:42 +01:00
commit a2072fe927
47 changed files with 694 additions and 665 deletions

View File

@ -259,9 +259,8 @@ public class MetaDataMappingService extends AbstractComponent {
} else {
newMapper = indexService.mapperService().parse(request.type(), mappingUpdateSource, existingMapper == null);
if (existingMapper != null) {
// first, simulate
// this will just throw exceptions in case of problems
existingMapper.merge(newMapper.mapping(), true, request.updateAllTypes());
// first, simulate: just call merge and ignore the result
existingMapper.merge(newMapper.mapping(), request.updateAllTypes());
} else {
// TODO: can we find a better place for this validation?
// The reason this validation is here is that the mapper service doesn't learn about

View File

@ -23,36 +23,24 @@ import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.DelegatingAnalyzerWrapper;
import org.elasticsearch.common.collect.CopyOnWriteHashMap;
import java.util.AbstractMap;
import java.util.Map;
import java.util.stream.Stream;
/**
*
*/
public final class FieldNameAnalyzer extends DelegatingAnalyzerWrapper {
private final CopyOnWriteHashMap<String, Analyzer> analyzers;
private final Analyzer defaultAnalyzer;
private final Map<String, Analyzer> analyzers;
public FieldNameAnalyzer(Analyzer defaultAnalyzer) {
this(new CopyOnWriteHashMap<>(), defaultAnalyzer);
}
public FieldNameAnalyzer(Map<String, Analyzer> analyzers, Analyzer defaultAnalyzer) {
public FieldNameAnalyzer(Map<String, Analyzer> analyzers) {
super(Analyzer.PER_FIELD_REUSE_STRATEGY);
this.analyzers = CopyOnWriteHashMap.copyOf(analyzers);
this.defaultAnalyzer = defaultAnalyzer;
}
public Map<String, Analyzer> analyzers() {
return analyzers;
}
public Analyzer defaultAnalyzer() {
return defaultAnalyzer;
}
@Override
protected Analyzer getWrappedAnalyzer(String fieldName) {
Analyzer analyzer = analyzers.get(fieldName);
@ -63,18 +51,4 @@ public final class FieldNameAnalyzer extends DelegatingAnalyzerWrapper {
// Fields need to be explicitly added
throw new IllegalArgumentException("Field [" + fieldName + "] has no associated analyzer");
}
/**
* Return a new instance that contains the union of this and of the provided analyzers.
*/
public FieldNameAnalyzer copyAndAddAll(Stream<? extends Map.Entry<String, Analyzer>> mappers) {
CopyOnWriteHashMap<String, Analyzer> result = analyzers.copyAndPutAll(mappers.map((e) -> {
if (e.getValue() == null) {
return new AbstractMap.SimpleImmutableEntry<>(e.getKey(), defaultAnalyzer);
}
return e;
}));
return new FieldNameAnalyzer(result, defaultAnalyzer);
}
}

View File

@ -20,15 +20,15 @@
package org.elasticsearch.index.mapper;
import org.apache.lucene.analysis.Analyzer;
import org.elasticsearch.common.collect.CopyOnWriteHashMap;
import org.elasticsearch.common.regex.Regex;
import org.elasticsearch.index.analysis.AnalysisService;
import org.elasticsearch.index.analysis.FieldNameAnalyzer;
import java.util.AbstractMap;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
/**
@ -37,44 +37,38 @@ import java.util.Set;
public final class DocumentFieldMappers implements Iterable<FieldMapper> {
/** Full field name to mapper */
private final CopyOnWriteHashMap<String, FieldMapper> fieldMappers;
private final Map<String, FieldMapper> fieldMappers;
private final FieldNameAnalyzer indexAnalyzer;
private final FieldNameAnalyzer searchAnalyzer;
private final FieldNameAnalyzer searchQuoteAnalyzer;
public DocumentFieldMappers(AnalysisService analysisService) {
this(new CopyOnWriteHashMap<String, FieldMapper>(),
new FieldNameAnalyzer(analysisService.defaultIndexAnalyzer()),
new FieldNameAnalyzer(analysisService.defaultSearchAnalyzer()),
new FieldNameAnalyzer(analysisService.defaultSearchQuoteAnalyzer()));
}
private DocumentFieldMappers(CopyOnWriteHashMap<String, FieldMapper> fieldMappers, FieldNameAnalyzer indexAnalyzer, FieldNameAnalyzer searchAnalyzer, FieldNameAnalyzer searchQuoteAnalyzer) {
this.fieldMappers = fieldMappers;
this.indexAnalyzer = indexAnalyzer;
this.searchAnalyzer = searchAnalyzer;
this.searchQuoteAnalyzer = searchQuoteAnalyzer;
}
public DocumentFieldMappers copyAndAllAll(Collection<FieldMapper> newMappers) {
CopyOnWriteHashMap<String, FieldMapper> map = this.fieldMappers;
for (FieldMapper fieldMapper : newMappers) {
map = map.copyAndPut(fieldMapper.fieldType().names().fullName(), fieldMapper);
private static void put(Map<String, Analyzer> analyzers, String key, Analyzer value, Analyzer defaultValue) {
if (value == null) {
value = defaultValue;
}
FieldNameAnalyzer indexAnalyzer = this.indexAnalyzer.copyAndAddAll(newMappers.stream().map((input) ->
new AbstractMap.SimpleImmutableEntry<>(input.fieldType().names().indexName(), (Analyzer)input.fieldType().indexAnalyzer())
));
FieldNameAnalyzer searchAnalyzer = this.searchAnalyzer.copyAndAddAll(newMappers.stream().map((input) ->
new AbstractMap.SimpleImmutableEntry<>(input.fieldType().names().indexName(), (Analyzer)input.fieldType().searchAnalyzer())
));
FieldNameAnalyzer searchQuoteAnalyzer = this.searchQuoteAnalyzer.copyAndAddAll(newMappers.stream().map((input) ->
new AbstractMap.SimpleImmutableEntry<>(input.fieldType().names().indexName(), (Analyzer) input.fieldType().searchQuoteAnalyzer())
));
return new DocumentFieldMappers(map,indexAnalyzer,searchAnalyzer,searchQuoteAnalyzer);
analyzers.put(key, value);
}
/** Returns the mapper for the given field */
public DocumentFieldMappers(Collection<FieldMapper> mappers, Analyzer defaultIndex, Analyzer defaultSearch, Analyzer defaultSearchQuote) {
Map<String, FieldMapper> fieldMappers = new HashMap<>();
Map<String, Analyzer> indexAnalyzers = new HashMap<>();
Map<String, Analyzer> searchAnalyzers = new HashMap<>();
Map<String, Analyzer> searchQuoteAnalyzers = new HashMap<>();
for (FieldMapper mapper : mappers) {
fieldMappers.put(mapper.name(), mapper);
MappedFieldType fieldType = mapper.fieldType();
put(indexAnalyzers, fieldType.names().indexName(), fieldType.indexAnalyzer(), defaultIndex);
put(searchAnalyzers, fieldType.names().indexName(), fieldType.searchAnalyzer(), defaultSearch);
put(searchQuoteAnalyzers, fieldType.names().indexName(), fieldType.searchQuoteAnalyzer(), defaultSearchQuote);
}
this.fieldMappers = Collections.unmodifiableMap(fieldMappers);
this.indexAnalyzer = new FieldNameAnalyzer(indexAnalyzers);
this.searchAnalyzer = new FieldNameAnalyzer(searchAnalyzers);
this.searchQuoteAnalyzer = new FieldNameAnalyzer(searchQuoteAnalyzers);
}
/** Returns the mapper for the given field */
public FieldMapper getMapper(String field) {
return fieldMappers.get(field);
}
@ -112,14 +106,6 @@ public final class DocumentFieldMappers implements Iterable<FieldMapper> {
return this.indexAnalyzer;
}
/**
* A smart analyzer used for indexing that takes into account specific analyzers configured
* per {@link FieldMapper} with a custom default analyzer for no explicit field analyzer.
*/
public Analyzer indexAnalyzer(Analyzer defaultAnalyzer) {
return new FieldNameAnalyzer(indexAnalyzer.analyzers(), defaultAnalyzer);
}
/**
* A smart analyzer used for searching that takes into account specific analyzers configured
* per {@link FieldMapper}.

View File

@ -24,16 +24,15 @@ import org.apache.lucene.search.Query;
import org.apache.lucene.search.Scorer;
import org.apache.lucene.search.Weight;
import org.elasticsearch.ElasticsearchGenerationException;
import org.elasticsearch.Version;
import org.elasticsearch.common.Nullable;
import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.compress.CompressedXContent;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.text.Text;
import org.elasticsearch.common.util.concurrent.ReleasableLock;
import org.elasticsearch.common.xcontent.ToXContent;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.IndexSettings;
import org.elasticsearch.index.analysis.AnalysisService;
import org.elasticsearch.index.mapper.MetadataFieldMapper.TypeParser;
import org.elasticsearch.index.mapper.internal.AllFieldMapper;
import org.elasticsearch.index.mapper.internal.IdFieldMapper;
@ -51,15 +50,12 @@ import org.elasticsearch.search.internal.SearchContext;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import static java.util.Collections.emptyMap;
@ -72,16 +68,14 @@ public class DocumentMapper implements ToXContent {
private Map<Class<? extends MetadataFieldMapper>, MetadataFieldMapper> metadataMappers = new LinkedHashMap<>();
private final Settings indexSettings;
private final RootObjectMapper rootObjectMapper;
private Map<String, Object> meta = emptyMap();
private final Mapper.BuilderContext builderContext;
public Builder(Settings indexSettings, RootObjectMapper.Builder builder, MapperService mapperService) {
this.indexSettings = indexSettings;
public Builder(RootObjectMapper.Builder builder, MapperService mapperService) {
final Settings indexSettings = mapperService.getIndexSettings().getSettings();
this.builderContext = new Mapper.BuilderContext(indexSettings, new ContentPath(1));
this.rootObjectMapper = builder.build(builderContext);
@ -104,9 +98,14 @@ public class DocumentMapper implements ToXContent {
return this;
}
public DocumentMapper build(MapperService mapperService, DocumentMapperParser docMapperParser) {
public DocumentMapper build(MapperService mapperService) {
Objects.requireNonNull(rootObjectMapper, "Mapper builder must have the root object mapper set");
return new DocumentMapper(mapperService, indexSettings, docMapperParser, rootObjectMapper, meta, metadataMappers, mapperService.mappingLock);
Mapping mapping = new Mapping(
mapperService.getIndexSettings().getIndexVersionCreated(),
rootObjectMapper,
metadataMappers.values().toArray(new MetadataFieldMapper[metadataMappers.values().size()]),
meta);
return new DocumentMapper(mapperService, mapping);
}
}
@ -115,38 +114,25 @@ public class DocumentMapper implements ToXContent {
private final String type;
private final Text typeText;
private volatile CompressedXContent mappingSource;
private final CompressedXContent mappingSource;
private volatile Mapping mapping;
private final Mapping mapping;
private final DocumentParser documentParser;
private volatile DocumentFieldMappers fieldMappers;
private final DocumentFieldMappers fieldMappers;
private volatile Map<String, ObjectMapper> objectMappers = Collections.emptyMap();
private final Map<String, ObjectMapper> objectMappers;
private boolean hasNestedObjects = false;
private final boolean hasNestedObjects;
private final ReleasableLock mappingWriteLock;
private final ReentrantReadWriteLock mappingLock;
public DocumentMapper(MapperService mapperService, @Nullable Settings indexSettings, DocumentMapperParser docMapperParser,
RootObjectMapper rootObjectMapper,
Map<String, Object> meta,
Map<Class<? extends MetadataFieldMapper>, MetadataFieldMapper> metadataMappers,
ReentrantReadWriteLock mappingLock) {
public DocumentMapper(MapperService mapperService, Mapping mapping) {
this.mapperService = mapperService;
this.type = rootObjectMapper.name();
this.type = mapping.root().name();
this.typeText = new Text(this.type);
this.mapping = new Mapping(
Version.indexCreated(indexSettings),
rootObjectMapper,
metadataMappers.values().toArray(new MetadataFieldMapper[metadataMappers.values().size()]),
meta);
this.documentParser = new DocumentParser(indexSettings, docMapperParser, this, new ReleasableLock(mappingLock.readLock()));
this.mappingWriteLock = new ReleasableLock(mappingLock.writeLock());
this.mappingLock = mappingLock;
final IndexSettings indexSettings = mapperService.getIndexSettings();
this.mapping = mapping;
this.documentParser = new DocumentParser(indexSettings, mapperService.documentMapperParser(), this);
if (metadataMapper(ParentFieldMapper.class).active()) {
// mark the routing field mapper as required
@ -163,7 +149,11 @@ public class DocumentMapper implements ToXContent {
}
MapperUtils.collect(this.mapping.root, newObjectMappers, newFieldMappers);
this.fieldMappers = new DocumentFieldMappers(docMapperParser.analysisService).copyAndAllAll(newFieldMappers);
final AnalysisService analysisService = mapperService.analysisService();
this.fieldMappers = new DocumentFieldMappers(newFieldMappers,
analysisService.defaultIndexAnalyzer(),
analysisService.defaultSearchAnalyzer(),
analysisService.defaultSearchQuoteAnalyzer());
Map<String, ObjectMapper> builder = new HashMap<>();
for (ObjectMapper objectMapper : newObjectMappers) {
@ -173,14 +163,20 @@ public class DocumentMapper implements ToXContent {
}
}
boolean hasNestedObjects = false;
this.objectMappers = Collections.unmodifiableMap(builder);
for (ObjectMapper objectMapper : newObjectMappers) {
if (objectMapper.nested().isNested()) {
hasNestedObjects = true;
}
}
this.hasNestedObjects = hasNestedObjects;
refreshSource();
try {
mappingSource = new CompressedXContent(this, XContentType.JSON, ToXContent.EMPTY_PARAMS);
} catch (Exception e) {
throw new ElasticsearchGenerationException("failed to serialize source for type [" + type + "]", e);
}
}
public Mapping mapping() {
@ -334,46 +330,17 @@ public class DocumentMapper implements ToXContent {
return mapperService.getParentTypes().contains(type);
}
private void addMappers(Collection<ObjectMapper> objectMappers, Collection<FieldMapper> fieldMappers, boolean updateAllTypes) {
assert mappingLock.isWriteLockedByCurrentThread();
// update mappers for this document type
Map<String, ObjectMapper> builder = new HashMap<>(this.objectMappers);
for (ObjectMapper objectMapper : objectMappers) {
builder.put(objectMapper.fullPath(), objectMapper);
if (objectMapper.nested().isNested()) {
hasNestedObjects = true;
}
}
this.objectMappers = Collections.unmodifiableMap(builder);
this.fieldMappers = this.fieldMappers.copyAndAllAll(fieldMappers);
// finally update for the entire index
mapperService.addMappers(type, objectMappers, fieldMappers);
public DocumentMapper merge(Mapping mapping, boolean updateAllTypes) {
Mapping merged = this.mapping.merge(mapping, updateAllTypes);
return new DocumentMapper(mapperService, merged);
}
public void merge(Mapping mapping, boolean simulate, boolean updateAllTypes) {
try (ReleasableLock lock = mappingWriteLock.acquire()) {
mapperService.checkMappersCompatibility(type, mapping, updateAllTypes);
// do the merge even if simulate == false so that we get exceptions
Mapping merged = this.mapping.merge(mapping, updateAllTypes);
if (simulate == false) {
this.mapping = merged;
Collection<ObjectMapper> objectMappers = new ArrayList<>();
Collection<FieldMapper> fieldMappers = new ArrayList<>(Arrays.asList(merged.metadataMappers));
MapperUtils.collect(merged.root, objectMappers, fieldMappers);
addMappers(objectMappers, fieldMappers, updateAllTypes);
refreshSource();
}
}
}
private void refreshSource() throws ElasticsearchGenerationException {
try {
mappingSource = new CompressedXContent(this, XContentType.JSON, ToXContent.EMPTY_PARAMS);
} catch (Exception e) {
throw new ElasticsearchGenerationException("failed to serialize source for type [" + type + "]", e);
}
/**
* Recursively update sub field types.
*/
public DocumentMapper updateFieldType(Map<String, MappedFieldType> fullNameToFieldType) {
Mapping updated = this.mapping.updateFieldType(fullNameToFieldType);
return new DocumentMapper(mapperService, updated);
}
public void close() {

View File

@ -27,7 +27,6 @@ import org.elasticsearch.common.collect.Tuple;
import org.elasticsearch.common.compress.CompressedXContent;
import org.elasticsearch.common.logging.ESLogger;
import org.elasticsearch.common.logging.Loggers;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.common.xcontent.XContentHelper;
import org.elasticsearch.common.xcontent.XContentParser;
@ -46,7 +45,6 @@ import static org.elasticsearch.index.mapper.MapperBuilders.doc;
public class DocumentMapperParser {
private final Settings indexSettings;
final MapperService mapperService;
final AnalysisService analysisService;
private static final ESLogger logger = Loggers.getLogger(DocumentMapperParser.class);
@ -62,8 +60,7 @@ public class DocumentMapperParser {
public DocumentMapperParser(IndexSettings indexSettings, MapperService mapperService, AnalysisService analysisService,
SimilarityService similarityService, MapperRegistry mapperRegistry) {
this.indexSettings = indexSettings.getSettings();
this.parseFieldMatcher = new ParseFieldMatcher(this.indexSettings);
this.parseFieldMatcher = new ParseFieldMatcher(indexSettings.getSettings());
this.mapperService = mapperService;
this.analysisService = analysisService;
this.similarityService = similarityService;
@ -110,7 +107,7 @@ public class DocumentMapperParser {
Mapper.TypeParser.ParserContext parserContext = parserContext(type);
// parse RootObjectMapper
DocumentMapper.Builder docBuilder = doc(indexSettings, (RootObjectMapper.Builder) rootObjectTypeParser.parse(type, mapping, parserContext), mapperService);
DocumentMapper.Builder docBuilder = doc((RootObjectMapper.Builder) rootObjectTypeParser.parse(type, mapping, parserContext), mapperService);
Iterator<Map.Entry<String, Object>> iterator = mapping.entrySet().iterator();
// parse DocumentMapper
while(iterator.hasNext()) {
@ -137,7 +134,7 @@ public class DocumentMapperParser {
checkNoRemainingFields(mapping, parserContext.indexVersionCreated(), "Root mapping definition has unsupported parameters: ");
return docBuilder.build(mapperService, this);
return docBuilder.build(mapperService);
}
public static void checkNoRemainingFields(String fieldName, Map<String, Object> fieldNodeMap, Version indexVersionCreated) {

View File

@ -26,10 +26,9 @@ import org.apache.lucene.util.CloseableThreadLocal;
import org.elasticsearch.Version;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.joda.FormatDateTimeFormatter;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.util.concurrent.ReleasableLock;
import org.elasticsearch.common.xcontent.XContentHelper;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.index.IndexSettings;
import org.elasticsearch.index.mapper.core.DateFieldMapper.DateFieldType;
import org.elasticsearch.index.mapper.core.NumberFieldMapper;
import org.elasticsearch.index.mapper.core.StringFieldMapper;
@ -53,29 +52,21 @@ class DocumentParser implements Closeable {
private CloseableThreadLocal<ParseContext.InternalParseContext> cache = new CloseableThreadLocal<ParseContext.InternalParseContext>() {
@Override
protected ParseContext.InternalParseContext initialValue() {
return new ParseContext.InternalParseContext(indexSettings, docMapperParser, docMapper, new ContentPath(0));
return new ParseContext.InternalParseContext(indexSettings.getSettings(), docMapperParser, docMapper, new ContentPath(0));
}
};
private final Settings indexSettings;
private final IndexSettings indexSettings;
private final DocumentMapperParser docMapperParser;
private final DocumentMapper docMapper;
private final ReleasableLock parseLock;
public DocumentParser(Settings indexSettings, DocumentMapperParser docMapperParser, DocumentMapper docMapper, ReleasableLock parseLock) {
public DocumentParser(IndexSettings indexSettings, DocumentMapperParser docMapperParser, DocumentMapper docMapper) {
this.indexSettings = indexSettings;
this.docMapperParser = docMapperParser;
this.docMapper = docMapper;
this.parseLock = parseLock;
}
public ParsedDocument parseDocument(SourceToParse source) throws MapperParsingException {
try (ReleasableLock lock = parseLock.acquire()){
return innerParseDocument(source);
}
}
private ParsedDocument innerParseDocument(SourceToParse source) throws MapperParsingException {
if (docMapper.type().equals(MapperService.DEFAULT_MAPPING)) {
throw new IllegalArgumentException("It is forbidden to index into the default mapping [" + MapperService.DEFAULT_MAPPING + "]");
}
@ -132,7 +123,7 @@ class DocumentParser implements Closeable {
// try to parse the next token, this should be null if the object is ended properly
// but will throw a JSON exception if the extra tokens is not valid JSON (this will be handled by the catch)
if (Version.indexCreated(indexSettings).onOrAfter(Version.V_2_0_0_beta1)
if (indexSettings.getIndexVersionCreated().onOrAfter(Version.V_2_0_0_beta1)
&& source.parser() == null && parser != null) {
// only check for end of tokens if we created the parser here
token = parser.nextToken();

View File

@ -44,6 +44,7 @@ import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.stream.StreamSupport;
public abstract class FieldMapper extends Mapper implements Cloneable {
@ -267,7 +268,7 @@ public abstract class FieldMapper extends Mapper implements Cloneable {
}
}
protected MappedFieldTypeReference fieldTypeRef;
protected MappedFieldType fieldType;
protected final MappedFieldType defaultFieldType;
protected MultiFields multiFields;
protected CopyTo copyTo;
@ -277,7 +278,8 @@ public abstract class FieldMapper extends Mapper implements Cloneable {
super(simpleName);
assert indexSettings != null;
this.indexCreatedBefore2x = Version.indexCreated(indexSettings).before(Version.V_2_0_0_beta1);
this.fieldTypeRef = new MappedFieldTypeReference(fieldType); // the reference ctor freezes the field type
fieldType.freeze();
this.fieldType = fieldType;
defaultFieldType.freeze();
this.defaultFieldType = defaultFieldType;
this.multiFields = multiFields;
@ -290,23 +292,7 @@ public abstract class FieldMapper extends Mapper implements Cloneable {
}
public MappedFieldType fieldType() {
return fieldTypeRef.get();
}
/** Returns a reference to the MappedFieldType for this mapper. */
public MappedFieldTypeReference fieldTypeReference() {
return fieldTypeRef;
}
/**
* Updates the reference to this field's MappedFieldType.
* Implementations should assert equality of the underlying field type
*/
public void setFieldTypeReference(MappedFieldTypeReference ref) {
if (ref.get().equals(fieldType()) == false) {
throw new IllegalStateException("Cannot overwrite field type reference to unequal reference");
}
this.fieldTypeRef = ref;
return fieldType;
}
/**
@ -350,10 +336,8 @@ public abstract class FieldMapper extends Mapper implements Cloneable {
return false;
}
@Override
public Iterator<Mapper> iterator() {
if (multiFields == null) {
return Collections.emptyIterator();
}
return multiFields.iterator();
}
@ -389,12 +373,26 @@ public abstract class FieldMapper extends Mapper implements Cloneable {
multiFields = multiFields.merge(fieldMergeWith.multiFields);
// apply changeable values
MappedFieldType fieldType = fieldMergeWith.fieldType().clone();
fieldType.freeze();
fieldTypeRef.set(fieldType);
this.fieldType = fieldMergeWith.fieldType;
this.copyTo = fieldMergeWith.copyTo;
}
@Override
public FieldMapper updateFieldType(Map<String, MappedFieldType> fullNameToFieldType) {
final MappedFieldType newFieldType = fullNameToFieldType.get(fieldType.names().fullName());
if (newFieldType == null) {
throw new IllegalStateException();
}
MultiFields updatedMultiFields = multiFields.updateFieldType(fullNameToFieldType);
if (fieldType == newFieldType && multiFields == updatedMultiFields) {
return this; // no change
}
FieldMapper updated = clone();
updated.fieldType = newFieldType;
updated.multiFields = updatedMultiFields;
return updated;
}
@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
builder.startObject(simpleName());
@ -619,6 +617,27 @@ public abstract class FieldMapper extends Mapper implements Cloneable {
return new MultiFields(mappers);
}
public MultiFields updateFieldType(Map<String, MappedFieldType> fullNameToFieldType) {
ImmutableOpenMap.Builder<String, FieldMapper> newMappersBuilder = null;
for (ObjectCursor<FieldMapper> cursor : mappers.values()) {
FieldMapper updated = cursor.value.updateFieldType(fullNameToFieldType);
if (updated != cursor.value) {
if (newMappersBuilder == null) {
newMappersBuilder = ImmutableOpenMap.builder(mappers);
}
newMappersBuilder.put(updated.simpleName(), updated);
}
}
if (newMappersBuilder == null) {
return this;
}
ImmutableOpenMap<String, FieldMapper> mappers = newMappersBuilder.build();
return new MultiFields(mappers);
}
public Iterator<Mapper> iterator() {
return StreamSupport.stream(mappers.values().spliterator(), false).map((p) -> (Mapper)p.value).iterator();
}

View File

@ -37,16 +37,16 @@ import java.util.Set;
class FieldTypeLookup implements Iterable<MappedFieldType> {
/** Full field name to field type */
private final CopyOnWriteHashMap<String, MappedFieldTypeReference> fullNameToFieldType;
final CopyOnWriteHashMap<String, MappedFieldType> fullNameToFieldType;
/** Full field name to types containing a mapping for this full name. */
private final CopyOnWriteHashMap<String, Set<String>> fullNameToTypes;
final CopyOnWriteHashMap<String, Set<String>> fullNameToTypes;
/** Index field name to field type */
private final CopyOnWriteHashMap<String, MappedFieldTypeReference> indexNameToFieldType;
final CopyOnWriteHashMap<String, MappedFieldType> indexNameToFieldType;
/** Index field name to types containing a mapping for this index name. */
private final CopyOnWriteHashMap<String, Set<String>> indexNameToTypes;
final CopyOnWriteHashMap<String, Set<String>> indexNameToTypes;
/** Create a new empty instance. */
public FieldTypeLookup() {
@ -57,9 +57,9 @@ class FieldTypeLookup implements Iterable<MappedFieldType> {
}
private FieldTypeLookup(
CopyOnWriteHashMap<String, MappedFieldTypeReference> fullName,
CopyOnWriteHashMap<String, MappedFieldType> fullName,
CopyOnWriteHashMap<String, Set<String>> fullNameToTypes,
CopyOnWriteHashMap<String, MappedFieldTypeReference> indexName,
CopyOnWriteHashMap<String, MappedFieldType> indexName,
CopyOnWriteHashMap<String, Set<String>> indexNameToTypes) {
this.fullNameToFieldType = fullName;
this.fullNameToTypes = fullNameToTypes;
@ -89,43 +89,35 @@ class FieldTypeLookup implements Iterable<MappedFieldType> {
* from the provided fields. If a field already exists, the field type will be updated
* to use the new mappers field type.
*/
public FieldTypeLookup copyAndAddAll(String type, Collection<FieldMapper> newFieldMappers) {
public FieldTypeLookup copyAndAddAll(String type, Collection<FieldMapper> fieldMappers, boolean updateAllTypes) {
Objects.requireNonNull(type, "type must not be null");
if (MapperService.DEFAULT_MAPPING.equals(type)) {
throw new IllegalArgumentException("Default mappings should not be added to the lookup");
}
CopyOnWriteHashMap<String, MappedFieldTypeReference> fullName = this.fullNameToFieldType;
CopyOnWriteHashMap<String, MappedFieldType> fullName = this.fullNameToFieldType;
CopyOnWriteHashMap<String, Set<String>> fullNameToTypes = this.fullNameToTypes;
CopyOnWriteHashMap<String, MappedFieldTypeReference> indexName = this.indexNameToFieldType;
CopyOnWriteHashMap<String, MappedFieldType> indexName = this.indexNameToFieldType;
CopyOnWriteHashMap<String, Set<String>> indexNameToTypes = this.indexNameToTypes;
for (FieldMapper fieldMapper : newFieldMappers) {
for (FieldMapper fieldMapper : fieldMappers) {
MappedFieldType fieldType = fieldMapper.fieldType();
MappedFieldTypeReference fullNameRef = fullName.get(fieldType.names().fullName());
MappedFieldTypeReference indexNameRef = indexName.get(fieldType.names().indexName());
if (fullNameRef == null && indexNameRef == null) {
// new field, just use the ref from this field mapper
fullName = fullName.copyAndPut(fieldType.names().fullName(), fieldMapper.fieldTypeReference());
indexName = indexName.copyAndPut(fieldType.names().indexName(), fieldMapper.fieldTypeReference());
} else if (fullNameRef == null) {
// this index name already exists, so copy over the reference
fullName = fullName.copyAndPut(fieldType.names().fullName(), indexNameRef);
indexNameRef.set(fieldMapper.fieldType()); // field type is updated, since modifiable settings may have changed
fieldMapper.setFieldTypeReference(indexNameRef);
} else if (indexNameRef == null) {
// this full name already exists, so copy over the reference
indexName = indexName.copyAndPut(fieldType.names().indexName(), fullNameRef);
fullNameRef.set(fieldMapper.fieldType()); // field type is updated, since modifiable settings may have changed
fieldMapper.setFieldTypeReference(fullNameRef);
} else if (fullNameRef == indexNameRef) {
// the field already exists, so replace the reference in this mapper with the pre-existing one
fullNameRef.set(fieldMapper.fieldType()); // field type is updated, since modifiable settings may have changed
fieldMapper.setFieldTypeReference(fullNameRef);
} else {
MappedFieldType fullNameFieldType = fullName.get(fieldType.names().fullName());
MappedFieldType indexNameFieldType = indexName.get(fieldType.names().indexName());
if (fullNameFieldType != null && indexNameFieldType != null && fullNameFieldType != indexNameFieldType) {
// this new field bridges between two existing field names (a full and index name), which we cannot support
throw new IllegalStateException("insane mappings found. field " + fieldType.names().fullName() + " maps across types to field " + fieldType.names().indexName());
}
// is the update even legal?
checkCompatibility(type, fieldMapper, updateAllTypes);
if (fieldType != fullNameFieldType || fieldType != indexNameFieldType) {
fullName = fullName.copyAndPut(fieldType.names().fullName(), fieldMapper.fieldType());
indexName = indexName.copyAndPut(fieldType.names().indexName(), fieldMapper.fieldType());
}
fullNameToTypes = addType(fullNameToTypes, fieldType.names().fullName(), type);
indexNameToTypes = addType(indexNameToTypes, fieldType.names().indexName(), type);
}
@ -145,42 +137,38 @@ class FieldTypeLookup implements Iterable<MappedFieldType> {
}
/**
* Checks if the given mappers' field types are compatible with existing field types.
* If any are not compatible, an IllegalArgumentException is thrown.
* Checks if the given field type is compatible with an existing field type.
* An IllegalArgumentException is thrown in case of incompatibility.
* If updateAllTypes is true, only basic compatibility is checked.
*/
public void checkCompatibility(String type, Collection<FieldMapper> fieldMappers, boolean updateAllTypes) {
for (FieldMapper fieldMapper : fieldMappers) {
MappedFieldTypeReference ref = fullNameToFieldType.get(fieldMapper.fieldType().names().fullName());
if (ref != null) {
List<String> conflicts = new ArrayList<>();
final Set<String> types = fullNameToTypes.get(fieldMapper.fieldType().names().fullName());
boolean strict = beStrict(type, types, updateAllTypes);
ref.get().checkCompatibility(fieldMapper.fieldType(), conflicts, strict);
if (conflicts.isEmpty() == false) {
throw new IllegalArgumentException("Mapper for [" + fieldMapper.fieldType().names().fullName() + "] conflicts with existing mapping in other types:\n" + conflicts.toString());
}
private void checkCompatibility(String type, FieldMapper fieldMapper, boolean updateAllTypes) {
MappedFieldType fieldType = fullNameToFieldType.get(fieldMapper.fieldType().names().fullName());
if (fieldType != null) {
List<String> conflicts = new ArrayList<>();
final Set<String> types = fullNameToTypes.get(fieldMapper.fieldType().names().fullName());
boolean strict = beStrict(type, types, updateAllTypes);
fieldType.checkCompatibility(fieldMapper.fieldType(), conflicts, strict);
if (conflicts.isEmpty() == false) {
throw new IllegalArgumentException("Mapper for [" + fieldMapper.fieldType().names().fullName() + "] conflicts with existing mapping in other types:\n" + conflicts.toString());
}
}
// field type for the index name must be compatible too
MappedFieldTypeReference indexNameRef = indexNameToFieldType.get(fieldMapper.fieldType().names().indexName());
if (indexNameRef != null) {
List<String> conflicts = new ArrayList<>();
final Set<String> types = indexNameToTypes.get(fieldMapper.fieldType().names().indexName());
boolean strict = beStrict(type, types, updateAllTypes);
indexNameRef.get().checkCompatibility(fieldMapper.fieldType(), conflicts, strict);
if (conflicts.isEmpty() == false) {
throw new IllegalArgumentException("Mapper for [" + fieldMapper.fieldType().names().fullName() + "] conflicts with mapping with the same index name in other types" + conflicts.toString());
}
// field type for the index name must be compatible too
fieldType = indexNameToFieldType.get(fieldMapper.fieldType().names().indexName());
if (fieldType != null) {
List<String> conflicts = new ArrayList<>();
final Set<String> types = indexNameToTypes.get(fieldMapper.fieldType().names().indexName());
boolean strict = beStrict(type, types, updateAllTypes);
fieldType.checkCompatibility(fieldMapper.fieldType(), conflicts, strict);
if (conflicts.isEmpty() == false) {
throw new IllegalArgumentException("Mapper for [" + fieldMapper.fieldType().names().fullName() + "] conflicts with mapping with the same index name in other types" + conflicts.toString());
}
}
}
/** Returns the field for the given field */
public MappedFieldType get(String field) {
MappedFieldTypeReference ref = fullNameToFieldType.get(field);
if (ref == null) return null;
return ref.get();
return fullNameToFieldType.get(field);
}
/** Get the set of types that have a mapping for the given field. */
@ -194,9 +182,7 @@ class FieldTypeLookup implements Iterable<MappedFieldType> {
/** Returns the field type for the given index name */
public MappedFieldType getByIndexName(String field) {
MappedFieldTypeReference ref = indexNameToFieldType.get(field);
if (ref == null) return null;
return ref.get();
return indexNameToFieldType.get(field);
}
/** Get the set of types that have a mapping for the given field. */
@ -238,7 +224,8 @@ class FieldTypeLookup implements Iterable<MappedFieldType> {
return fields;
}
@Override
public Iterator<MappedFieldType> iterator() {
return fullNameToFieldType.values().stream().map((p) -> p.get()).iterator();
return fullNameToFieldType.values().iterator();
}
}

View File

@ -1,41 +0,0 @@
/*
* Licensed to Elasticsearch under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.elasticsearch.index.mapper;
/**
* A container for a {@link MappedFieldType} which can be updated and is reference counted.
*/
public class MappedFieldTypeReference {
private MappedFieldType fieldType; // the current field type this reference points to
public MappedFieldTypeReference(MappedFieldType fieldType) {
fieldType.freeze(); // ensure frozen
this.fieldType = fieldType;
}
public MappedFieldType get() {
return fieldType;
}
public void set(MappedFieldType fieldType) {
fieldType.freeze(); // ensure frozen
this.fieldType = fieldType;
}
}

View File

@ -177,4 +177,11 @@ public abstract class Mapper implements ToXContent, Iterable<Mapper> {
/** Return the merge of {@code mergeWith} into this.
* Both {@code this} and {@code mergeWith} will be left unmodified. */
public abstract Mapper merge(Mapper mergeWith, boolean updateAllTypes);
/**
* Update the field type of this mapper. This is necessary because some mapping updates
* can modify mappings across several types. This method must return a copy of the mapper
* so that the current mapper is not modified.
*/
public abstract Mapper updateFieldType(Map<String, MappedFieldType> fullNameToFieldType);
}

View File

@ -19,7 +19,6 @@
package org.elasticsearch.index.mapper;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.index.mapper.core.BinaryFieldMapper;
import org.elasticsearch.index.mapper.core.BooleanFieldMapper;
import org.elasticsearch.index.mapper.core.ByteFieldMapper;
@ -41,8 +40,8 @@ public final class MapperBuilders {
private MapperBuilders() {}
public static DocumentMapper.Builder doc(Settings settings, RootObjectMapper.Builder objectBuilder, MapperService mapperService) {
return new DocumentMapper.Builder(settings, objectBuilder, mapperService);
public static DocumentMapper.Builder doc(RootObjectMapper.Builder objectBuilder, MapperService mapperService) {
return new DocumentMapper.Builder(objectBuilder, mapperService);
}
public static RootObjectMapper.Builder rootObject(String name) {

View File

@ -35,11 +35,9 @@ import org.apache.lucene.util.BytesRef;
import org.elasticsearch.ElasticsearchGenerationException;
import org.elasticsearch.Version;
import org.elasticsearch.common.Nullable;
import org.elasticsearch.common.collect.Tuple;
import org.elasticsearch.common.compress.CompressedXContent;
import org.elasticsearch.common.lucene.search.Queries;
import org.elasticsearch.common.regex.Regex;
import org.elasticsearch.common.util.concurrent.ReleasableLock;
import org.elasticsearch.index.AbstractIndexComponent;
import org.elasticsearch.index.IndexSettings;
import org.elasticsearch.index.analysis.AnalysisService;
@ -65,7 +63,6 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.function.Function;
import java.util.stream.Collectors;
@ -98,12 +95,6 @@ public class MapperService extends AbstractIndexComponent implements Closeable {
private volatile Map<String, DocumentMapper> mappers = emptyMap();
// A lock for mappings: modifications (put mapping) need to be performed
// under the write lock and read operations (document parsing) need to be
// performed under the read lock
final ReentrantReadWriteLock mappingLock = new ReentrantReadWriteLock();
private final ReleasableLock mappingWriteLock = new ReleasableLock(mappingLock.writeLock());
private volatile FieldTypeLookup fieldTypes;
private volatile Map<String, ObjectMapper> fullPathObjectMappers = new HashMap<>();
private boolean hasNested = false; // updated dynamically to true when a nested object is added
@ -216,7 +207,7 @@ public class MapperService extends AbstractIndexComponent implements Closeable {
DocumentMapper mapper = documentParser.parse(type, mappingSource);
// still add it as a document mapper so we have it registered and, for example, persisted back into
// the cluster meta data if needed, or checked for existence
try (ReleasableLock lock = mappingWriteLock.acquire()) {
synchronized (this) {
mappers = newMapBuilder(mappers).put(type, mapper).map();
}
try {
@ -226,7 +217,7 @@ public class MapperService extends AbstractIndexComponent implements Closeable {
}
return mapper;
} else {
try (ReleasableLock lock = mappingWriteLock.acquire()) {
synchronized (this) {
// only apply the default mapping if we don't have the type yet
applyDefault &= mappers.containsKey(type) == false;
return merge(parse(type, mappingSource, applyDefault), updateAllTypes);
@ -234,9 +225,7 @@ public class MapperService extends AbstractIndexComponent implements Closeable {
}
}
// 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) {
private synchronized DocumentMapper merge(DocumentMapper mapper, boolean updateAllTypes) {
if (mapper.type().length() == 0) {
throw new InvalidTypeNameException("mapping type name is empty");
}
@ -262,34 +251,89 @@ public class MapperService extends AbstractIndexComponent implements Closeable {
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
// 1. compute the merged DocumentMapper
DocumentMapper oldMapper = mappers.get(mapper.type());
DocumentMapper newMapper;
if (oldMapper != null) {
oldMapper.merge(mapper.mapping(), false, updateAllTypes);
return oldMapper;
newMapper = oldMapper.merge(mapper.mapping(), updateAllTypes);
} else {
Tuple<Collection<ObjectMapper>, Collection<FieldMapper>> newMappers = checkMappersCompatibility(
mapper.type(), mapper.mapping(), updateAllTypes);
Collection<ObjectMapper> newObjectMappers = newMappers.v1();
Collection<FieldMapper> newFieldMappers = newMappers.v2();
addMappers(mapper.type(), newObjectMappers, newFieldMappers);
newMapper = mapper;
}
// 2. check basic sanity of the new mapping
List<ObjectMapper> objectMappers = new ArrayList<>();
List<FieldMapper> fieldMappers = new ArrayList<>();
Collections.addAll(fieldMappers, newMapper.mapping().metadataMappers);
MapperUtils.collect(newMapper.mapping().root(), objectMappers, fieldMappers);
checkFieldUniqueness(newMapper.type(), objectMappers, fieldMappers);
checkObjectsCompatibility(newMapper.type(), objectMappers, fieldMappers, updateAllTypes);
// 3. update lookup data-structures
// this will in particular make sure that the merged fields are compatible with other types
FieldTypeLookup fieldTypes = this.fieldTypes.copyAndAddAll(newMapper.type(), fieldMappers, updateAllTypes);
boolean hasNested = this.hasNested;
Map<String, ObjectMapper> fullPathObjectMappers = new HashMap<>(this.fullPathObjectMappers);
for (ObjectMapper objectMapper : objectMappers) {
fullPathObjectMappers.put(objectMapper.fullPath(), objectMapper);
if (objectMapper.nested().isNested()) {
hasNested = true;
}
}
fullPathObjectMappers = Collections.unmodifiableMap(fullPathObjectMappers);
Set<String> parentTypes = this.parentTypes;
if (oldMapper == null && newMapper.parentFieldMapper().active()) {
parentTypes = new HashSet<>(parentTypes.size() + 1);
parentTypes.addAll(this.parentTypes);
parentTypes.add(mapper.parentFieldMapper().type());
parentTypes = Collections.unmodifiableSet(parentTypes);
}
Map<String, DocumentMapper> mappers = new HashMap<>(this.mappers);
mappers.put(newMapper.type(), newMapper);
for (Map.Entry<String, DocumentMapper> entry : mappers.entrySet()) {
if (entry.getKey().equals(DEFAULT_MAPPING)) {
continue;
}
DocumentMapper m = entry.getValue();
// apply changes to the field types back
m = m.updateFieldType(fieldTypes.fullNameToFieldType);
entry.setValue(m);
}
mappers = Collections.unmodifiableMap(mappers);
// 4. commit the change
this.mappers = mappers;
this.fieldTypes = fieldTypes;
this.hasNested = hasNested;
this.fullPathObjectMappers = fullPathObjectMappers;
this.parentTypes = parentTypes;
// 5. send notifications about the change
if (oldMapper == null) {
// means the mapping was created
for (DocumentTypeListener typeListener : typeListeners) {
typeListener.beforeCreate(mapper);
}
mappers = newMapBuilder(mappers).put(mapper.type(), mapper).map();
if (mapper.parentFieldMapper().active()) {
Set<String> newParentTypes = new HashSet<>(parentTypes.size() + 1);
newParentTypes.addAll(parentTypes);
newParentTypes.add(mapper.parentFieldMapper().type());
parentTypes = unmodifiableSet(newParentTypes);
}
assert assertSerialization(mapper);
return mapper;
}
assert assertSerialization(newMapper);
assert assertMappersShareSameFieldType();
return newMapper;
}
private boolean assertMappersShareSameFieldType() {
for (DocumentMapper mapper : docMappers(false)) {
List<FieldMapper> fieldMappers = new ArrayList<>();
Collections.addAll(fieldMappers, mapper.mapping().metadataMappers);
MapperUtils.collect(mapper.root(), new ArrayList<ObjectMapper>(), fieldMappers);
for (FieldMapper fieldMapper : fieldMappers) {
assert fieldMapper.fieldType() == fieldTypes.get(fieldMapper.name()) : fieldMapper.name();
}
}
return true;
}
private boolean typeNameStartsWithIllegalDot(DocumentMapper mapper) {
@ -339,8 +383,8 @@ public class MapperService extends AbstractIndexComponent implements Closeable {
}
}
protected void checkMappersCompatibility(String type, Collection<ObjectMapper> objectMappers, Collection<FieldMapper> fieldMappers, boolean updateAllTypes) {
assert mappingLock.isWriteLockedByCurrentThread();
private void checkObjectsCompatibility(String type, Collection<ObjectMapper> objectMappers, Collection<FieldMapper> fieldMappers, boolean updateAllTypes) {
assert Thread.holdsLock(this);
checkFieldUniqueness(type, objectMappers, fieldMappers);
@ -358,31 +402,6 @@ public class MapperService extends AbstractIndexComponent implements Closeable {
throw new IllegalArgumentException("Field [" + fieldMapper.name() + "] is defined as a field in mapping [" + type + "] but this name is already used for an object in other types");
}
}
fieldTypes.checkCompatibility(type, fieldMappers, updateAllTypes);
}
protected Tuple<Collection<ObjectMapper>, Collection<FieldMapper>> checkMappersCompatibility(
String type, Mapping mapping, boolean updateAllTypes) {
List<ObjectMapper> objectMappers = new ArrayList<>();
List<FieldMapper> fieldMappers = new ArrayList<>();
Collections.addAll(fieldMappers, mapping.metadataMappers);
MapperUtils.collect(mapping.root, objectMappers, fieldMappers);
checkMappersCompatibility(type, objectMappers, fieldMappers, updateAllTypes);
return new Tuple<>(objectMappers, fieldMappers);
}
protected void addMappers(String type, Collection<ObjectMapper> objectMappers, Collection<FieldMapper> fieldMappers) {
assert mappingLock.isWriteLockedByCurrentThread();
Map<String, ObjectMapper> fullPathObjectMappers = new HashMap<>(this.fullPathObjectMappers);
for (ObjectMapper objectMapper : objectMappers) {
fullPathObjectMappers.put(objectMapper.fullPath(), objectMapper);
if (objectMapper.nested().isNested()) {
hasNested = true;
}
}
this.fullPathObjectMappers = Collections.unmodifiableMap(fullPathObjectMappers);
this.fieldTypes = this.fieldTypes.copyAndAddAll(type, fieldMappers);
}
public DocumentMapper parse(String mappingType, CompressedXContent mappingSource, boolean applyDefault) throws MapperParsingException {

View File

@ -93,7 +93,7 @@ public final class Mapping implements ToXContent {
return (T) metadataMappersMap.get(clazz);
}
/** @see DocumentMapper#merge(Mapping, boolean, boolean) */
/** @see DocumentMapper#merge(Mapping, boolean) */
public Mapping merge(Mapping mergeWith, boolean updateAllTypes) {
RootObjectMapper mergedRoot = root.merge(mergeWith.root, updateAllTypes);
Map<Class<? extends MetadataFieldMapper>, MetadataFieldMapper> mergedMetaDataMappers = new HashMap<>(metadataMappersMap);
@ -110,6 +110,18 @@ public final class Mapping implements ToXContent {
return new Mapping(indexCreated, mergedRoot, mergedMetaDataMappers.values().toArray(new MetadataFieldMapper[0]), mergeWith.meta);
}
/**
* Recursively update sub field types.
*/
public Mapping updateFieldType(Map<String, MappedFieldType> fullNameToFieldType) {
final MetadataFieldMapper[] updatedMeta = Arrays.copyOf(metadataMappers, metadataMappers.length);
for (int i = 0; i < updatedMeta.length; ++i) {
updatedMeta[i] = (MetadataFieldMapper) updatedMeta[i].updateFieldType(fullNameToFieldType);
}
RootObjectMapper updatedRoot = root.updateFieldType(fullNameToFieldType);
return new Mapping(indexCreated, updatedRoot, updatedMeta, meta);
}
@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
root.toXContent(builder, params, new ToXContent() {

View File

@ -346,11 +346,11 @@ public abstract class BaseGeoPointFieldMapper extends FieldMapper implements Arr
}
}
protected final DoubleFieldMapper latMapper;
protected DoubleFieldMapper latMapper;
protected final DoubleFieldMapper lonMapper;
protected DoubleFieldMapper lonMapper;
protected final StringFieldMapper geoHashMapper;
protected StringFieldMapper geoHashMapper;
protected Explicit<Boolean> ignoreMalformed;
@ -504,4 +504,25 @@ public abstract class BaseGeoPointFieldMapper extends FieldMapper implements Arr
builder.field(Names.IGNORE_MALFORMED, ignoreMalformed.value());
}
}
@Override
public FieldMapper updateFieldType(Map<String, MappedFieldType> fullNameToFieldType) {
BaseGeoPointFieldMapper updated = (BaseGeoPointFieldMapper) super.updateFieldType(fullNameToFieldType);
StringFieldMapper geoUpdated = geoHashMapper == null ? null : (StringFieldMapper) geoHashMapper.updateFieldType(fullNameToFieldType);
DoubleFieldMapper latUpdated = latMapper == null ? null : (DoubleFieldMapper) latMapper.updateFieldType(fullNameToFieldType);
DoubleFieldMapper lonUpdated = lonMapper == null ? null : (DoubleFieldMapper) lonMapper.updateFieldType(fullNameToFieldType);
if (updated == this
&& geoUpdated == geoHashMapper
&& latUpdated == latMapper
&& lonUpdated == lonMapper) {
return this;
}
if (updated == this) {
updated = (BaseGeoPointFieldMapper) updated.clone();
}
updated.geoHashMapper = geoUpdated;
updated.latMapper = latUpdated;
updated.lonMapper = lonUpdated;
return updated;
}
}

View File

@ -216,7 +216,7 @@ public class FieldNamesFieldMapper extends MetadataFieldMapper {
FieldNamesFieldType newFieldType = fieldType().clone();
newFieldType.setEnabled(false);
newFieldType.freeze();
fieldTypeRef.set(newFieldType);
this.fieldType = newFieldType;
}
}

View File

@ -95,8 +95,8 @@ public class TimestampFieldMapper extends MetadataFieldMapper {
private boolean explicitStore = false;
private Boolean ignoreMissing = null;
public Builder(MappedFieldType existing) {
super(Defaults.NAME, existing == null ? Defaults.FIELD_TYPE : existing, Defaults.FIELD_TYPE);
public Builder(MappedFieldType existing, Settings settings) {
super(Defaults.NAME, existing == null ? Defaults.FIELD_TYPE : existing, chooseFieldType(settings, null));
if (existing != null) {
// if there is an existing type, always use that store value (only matters for < 2.0)
explicitStore = true;
@ -167,7 +167,7 @@ public class TimestampFieldMapper extends MetadataFieldMapper {
public static class TypeParser implements MetadataFieldMapper.TypeParser {
@Override
public MetadataFieldMapper.Builder parse(String name, Map<String, Object> node, ParserContext parserContext) throws MapperParsingException {
Builder builder = new Builder(parserContext.mapperService().fullName(NAME));
Builder builder = new Builder(parserContext.mapperService().fullName(NAME), parserContext.mapperService().getIndexSettings().getSettings());
if (parserContext.indexVersionCreated().before(Version.V_2_0_0_beta1)) {
parseField(builder, builder.name, node, parserContext);
}
@ -260,7 +260,7 @@ public class TimestampFieldMapper extends MetadataFieldMapper {
private final Boolean ignoreMissing;
private TimestampFieldMapper(Settings indexSettings, MappedFieldType existing) {
this(chooseFieldType(indexSettings, existing).clone(), chooseFieldType(indexSettings, null), Defaults.ENABLED, Defaults.PATH, Defaults.DEFAULT_TIMESTAMP, null, indexSettings);
this(chooseFieldType(indexSettings, existing).clone(), chooseFieldType(indexSettings, null).clone(), Defaults.ENABLED, Defaults.PATH, Defaults.DEFAULT_TIMESTAMP, null, indexSettings);
}
private TimestampFieldMapper(MappedFieldType fieldType, MappedFieldType defaultFieldType, EnabledAttributeMapper enabledState, String path,

View File

@ -31,6 +31,7 @@ import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.ToXContent;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.index.mapper.DocumentMapperParser;
import org.elasticsearch.index.mapper.MappedFieldType;
import org.elasticsearch.index.mapper.Mapper;
import org.elasticsearch.index.mapper.MapperParsingException;
import org.elasticsearch.index.mapper.MetadataFieldMapper;
@ -493,6 +494,28 @@ public class ObjectMapper extends Mapper implements AllFieldMapper.IncludeInAll,
}
}
@Override
public ObjectMapper updateFieldType(Map<String, MappedFieldType> fullNameToFieldType) {
List<Mapper> updatedMappers = null;
for (Mapper mapper : this) {
Mapper updated = mapper.updateFieldType(fullNameToFieldType);
if (mapper != updated) {
if (updatedMappers == null) {
updatedMappers = new ArrayList<>();
}
updatedMappers.add(updated);
}
}
if (updatedMappers == null) {
return this;
}
ObjectMapper updated = clone();
for (Mapper updatedMapper : updatedMappers) {
updated.putMapper(updatedMapper);
}
return updated;
}
@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
toXContent(builder, params, null);

View File

@ -27,6 +27,7 @@ import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.ToXContent;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.index.mapper.ContentPath;
import org.elasticsearch.index.mapper.MappedFieldType;
import org.elasticsearch.index.mapper.Mapper;
import org.elasticsearch.index.mapper.MapperParsingException;
import org.elasticsearch.index.mapper.ParseContext;
@ -295,6 +296,11 @@ public class RootObjectMapper extends ObjectMapper {
this.dynamicTemplates = mergedTemplates.toArray(new DynamicTemplate[mergedTemplates.size()]);
}
@Override
public RootObjectMapper updateFieldType(Map<String, MappedFieldType> fullNameToFieldType) {
return (RootObjectMapper) super.updateFieldType(fullNameToFieldType);
}
@Override
protected void doXContent(XContentBuilder builder, ToXContent.Params params) throws IOException {
if (dynamicDateTimeFormatters != Defaults.DYNAMIC_DATE_TIME_FORMATTERS) {

View File

@ -1931,9 +1931,8 @@ public class InternalEngineTests extends ESTestCase {
SimilarityService similarityService = new SimilarityService(indexSettings, Collections.emptyMap());
MapperRegistry mapperRegistry = new IndicesModule().getMapperRegistry();
MapperService mapperService = new MapperService(indexSettings, analysisService, similarityService, mapperRegistry);
DocumentMapper.Builder b = new DocumentMapper.Builder(settings, rootBuilder, mapperService);
DocumentMapperParser parser = mapperService.documentMapperParser();
this.docMapper = b.build(mapperService, parser);
DocumentMapper.Builder b = new DocumentMapper.Builder(rootBuilder, mapperService);
this.docMapper = b.build(mapperService);
}
@Override

View File

@ -0,0 +1,144 @@
/*
* Licensed to Elasticsearch under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.elasticsearch.index.mapper;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.TokenStream;
import org.apache.lucene.analysis.Tokenizer;
import org.apache.lucene.analysis.tokenattributes.CharTermAttribute;
import org.apache.lucene.document.Field;
import org.apache.lucene.util.LuceneTestCase;
import org.elasticsearch.Version;
import org.elasticsearch.cluster.metadata.IndexMetaData;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.index.analysis.NamedAnalyzer;
import java.io.IOException;
import java.io.StringReader;
import java.util.Arrays;
import java.util.List;
public class DocumentFieldMapperTests extends LuceneTestCase {
private static class FakeAnalyzer extends Analyzer {
private final String output;
public FakeAnalyzer(String output) {
this.output = output;
}
@Override
protected TokenStreamComponents createComponents(String fieldName) {
Tokenizer tokenizer = new Tokenizer() {
boolean incremented = false;
CharTermAttribute term = addAttribute(CharTermAttribute.class);
@Override
public boolean incrementToken() throws IOException {
if (incremented) {
return false;
}
term.setLength(0).append(output);
incremented = true;
return true;
}
};
return new TokenStreamComponents(tokenizer);
}
}
static class FakeFieldType extends MappedFieldType {
public FakeFieldType() {
super();
}
FakeFieldType(FakeFieldType other) {
super(other);
}
@Override
public MappedFieldType clone() {
return new FakeFieldType(this);
}
@Override
public String typeName() {
return "fake";
}
}
static class FakeFieldMapper extends FieldMapper {
private static final Settings SETTINGS = Settings.builder().put(IndexMetaData.SETTING_VERSION_CREATED, Version.CURRENT).build();
public FakeFieldMapper(String simpleName, MappedFieldType fieldType) {
super(simpleName, fieldType.clone(), fieldType.clone(), SETTINGS, null, null);
}
@Override
protected void parseCreateField(ParseContext context, List<Field> fields) throws IOException {
}
@Override
protected String contentType() {
return null;
}
}
public void testAnalyzers() throws IOException {
FakeFieldType fieldType1 = new FakeFieldType();
fieldType1.setNames(new MappedFieldType.Names("field1"));
fieldType1.setIndexAnalyzer(new NamedAnalyzer("foo", new FakeAnalyzer("index")));
fieldType1.setSearchAnalyzer(new NamedAnalyzer("bar", new FakeAnalyzer("search")));
fieldType1.setSearchQuoteAnalyzer(new NamedAnalyzer("baz", new FakeAnalyzer("search_quote")));
FieldMapper fieldMapper1 = new FakeFieldMapper("field1", fieldType1);
FakeFieldType fieldType2 = new FakeFieldType();
fieldType2.setNames(new MappedFieldType.Names("field2"));
FieldMapper fieldMapper2 = new FakeFieldMapper("field2", fieldType2);
Analyzer defaultIndex = new FakeAnalyzer("default_index");
Analyzer defaultSearch = new FakeAnalyzer("default_search");
Analyzer defaultSearchQuote = new FakeAnalyzer("default_search_quote");
DocumentFieldMappers documentFieldMappers = new DocumentFieldMappers(Arrays.asList(fieldMapper1, fieldMapper2), defaultIndex, defaultSearch, defaultSearchQuote);
assertAnalyzes(documentFieldMappers.indexAnalyzer(), "field1", "index");
assertAnalyzes(documentFieldMappers.searchAnalyzer(), "field1", "search");
assertAnalyzes(documentFieldMappers.searchQuoteAnalyzer(), "field1", "search_quote");
assertAnalyzes(documentFieldMappers.indexAnalyzer(), "field2", "default_index");
assertAnalyzes(documentFieldMappers.searchAnalyzer(), "field2", "default_search");
assertAnalyzes(documentFieldMappers.searchQuoteAnalyzer(), "field2", "default_search_quote");
}
private void assertAnalyzes(Analyzer analyzer, String field, String output) throws IOException {
try (TokenStream tok = analyzer.tokenStream(field, new StringReader(""))) {
CharTermAttribute term = tok.addAttribute(CharTermAttribute.class);
assertTrue(tok.incrementToken());
assertEquals(output, term.toString());
}
}
}

View File

@ -31,6 +31,8 @@ import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import static org.hamcrest.Matchers.containsString;
public class FieldTypeLookupTests extends ESTestCase {
public void testEmpty() {
@ -53,7 +55,7 @@ public class FieldTypeLookupTests extends ESTestCase {
public void testDefaultMapping() {
FieldTypeLookup lookup = new FieldTypeLookup();
try {
lookup.copyAndAddAll(MapperService.DEFAULT_MAPPING, Collections.emptyList());
lookup.copyAndAddAll(MapperService.DEFAULT_MAPPING, Collections.emptyList(), randomBoolean());
fail();
} catch (IllegalArgumentException expected) {
assertEquals("Default mappings should not be added to the lookup", expected.getMessage());
@ -63,7 +65,7 @@ public class FieldTypeLookupTests extends ESTestCase {
public void testAddNewField() {
FieldTypeLookup lookup = new FieldTypeLookup();
FakeFieldMapper f = new FakeFieldMapper("foo", "bar");
FieldTypeLookup lookup2 = lookup.copyAndAddAll("type", newList(f));
FieldTypeLookup lookup2 = lookup.copyAndAddAll("type", newList(f), randomBoolean());
assertNull(lookup.get("foo"));
assertNull(lookup.get("bar"));
assertNull(lookup.getByIndexName("foo"));
@ -85,94 +87,77 @@ public class FieldTypeLookupTests extends ESTestCase {
public void testAddExistingField() {
FakeFieldMapper f = new FakeFieldMapper("foo", "foo");
MappedFieldType originalFieldType = f.fieldType();
FakeFieldMapper f2 = new FakeFieldMapper("foo", "foo");
FieldTypeLookup lookup = new FieldTypeLookup();
lookup = lookup.copyAndAddAll("type1", newList(f));
FieldTypeLookup lookup2 = lookup.copyAndAddAll("type2", newList(f2));
lookup = lookup.copyAndAddAll("type1", newList(f), randomBoolean());
FieldTypeLookup lookup2 = lookup.copyAndAddAll("type2", newList(f2), randomBoolean());
assertNotSame(originalFieldType, f.fieldType());
assertSame(f.fieldType(), f2.fieldType());
assertSame(f.fieldType(), lookup2.get("foo"));
assertSame(f.fieldType(), lookup2.getByIndexName("foo"));
assertSame(f2.fieldType(), lookup2.get("foo"));
assertSame(f2.fieldType(), lookup2.getByIndexName("foo"));
assertEquals(1, size(lookup2.iterator()));
}
public void testAddExistingIndexName() {
FakeFieldMapper f = new FakeFieldMapper("foo", "foo");
FakeFieldMapper f2 = new FakeFieldMapper("bar", "foo");
MappedFieldType originalFieldType = f.fieldType();
FieldTypeLookup lookup = new FieldTypeLookup();
lookup = lookup.copyAndAddAll("type1", newList(f));
FieldTypeLookup lookup2 = lookup.copyAndAddAll("type2", newList(f2));
lookup = lookup.copyAndAddAll("type1", newList(f), randomBoolean());
FieldTypeLookup lookup2 = lookup.copyAndAddAll("type2", newList(f2), randomBoolean());
assertNotSame(originalFieldType, f.fieldType());
assertSame(f.fieldType(), f2.fieldType());
assertSame(f.fieldType(), lookup2.get("foo"));
assertSame(f.fieldType(), lookup2.get("bar"));
assertSame(f.fieldType(), lookup2.getByIndexName("foo"));
assertSame(f2.fieldType(), lookup2.get("bar"));
assertSame(f2.fieldType(), lookup2.getByIndexName("foo"));
assertEquals(2, size(lookup2.iterator()));
}
public void testAddExistingFullName() {
FakeFieldMapper f = new FakeFieldMapper("foo", "foo");
FakeFieldMapper f2 = new FakeFieldMapper("foo", "bar");
MappedFieldType originalFieldType = f.fieldType();
FieldTypeLookup lookup = new FieldTypeLookup();
lookup = lookup.copyAndAddAll("type1", newList(f));
FieldTypeLookup lookup2 = lookup.copyAndAddAll("type2", newList(f2));
assertNotSame(originalFieldType, f.fieldType());
assertSame(f.fieldType(), f2.fieldType());
assertSame(f.fieldType(), lookup2.get("foo"));
assertSame(f.fieldType(), lookup2.getByIndexName("foo"));
assertSame(f.fieldType(), lookup2.getByIndexName("bar"));
assertEquals(1, size(lookup2.iterator()));
try {
lookup.copyAndAddAll("type2", newList(f2), randomBoolean());
} catch (IllegalArgumentException e) {
assertThat(e.getMessage(), containsString("mapper [foo] has different [index_name]"));
}
}
public void testAddExistingBridgeName() {
FakeFieldMapper f = new FakeFieldMapper("foo", "foo");
FakeFieldMapper f2 = new FakeFieldMapper("bar", "bar");
FieldTypeLookup lookup = new FieldTypeLookup();
lookup = lookup.copyAndAddAll("type1", newList(f, f2));
lookup = lookup.copyAndAddAll("type1", newList(f, f2), randomBoolean());
try {
FakeFieldMapper f3 = new FakeFieldMapper("foo", "bar");
lookup.copyAndAddAll("type2", newList(f3));
lookup.copyAndAddAll("type2", newList(f3), randomBoolean());
} catch (IllegalStateException e) {
assertTrue(e.getMessage().contains("insane mappings"));
}
try {
FakeFieldMapper f3 = new FakeFieldMapper("bar", "foo");
lookup.copyAndAddAll("type2", newList(f3));
lookup.copyAndAddAll("type2", newList(f3), randomBoolean());
} catch (IllegalStateException e) {
assertTrue(e.getMessage().contains("insane mappings"));
}
}
public void testCheckCompatibilityNewField() {
FakeFieldMapper f1 = new FakeFieldMapper("foo", "bar");
FieldTypeLookup lookup = new FieldTypeLookup();
lookup.checkCompatibility("type", newList(f1), false);
}
public void testCheckCompatibilityMismatchedTypes() {
FieldMapper f1 = new FakeFieldMapper("foo", "bar");
FieldTypeLookup lookup = new FieldTypeLookup();
lookup = lookup.copyAndAddAll("type", newList(f1));
lookup = lookup.copyAndAddAll("type", newList(f1), randomBoolean());
MappedFieldType ft2 = FakeFieldMapper.makeOtherFieldType("foo", "foo");
FieldMapper f2 = new FakeFieldMapper("foo", ft2);
try {
lookup.checkCompatibility("type2", newList(f2), false);
lookup.copyAndAddAll("type2", newList(f2), false);
fail("expected type mismatch");
} catch (IllegalArgumentException e) {
assertTrue(e.getMessage().contains("cannot be changed from type [faketype] to [otherfaketype]"));
}
// fails even if updateAllTypes == true
try {
lookup.checkCompatibility("type2", newList(f2), true);
lookup.copyAndAddAll("type2", newList(f2), true);
fail("expected type mismatch");
} catch (IllegalArgumentException e) {
assertTrue(e.getMessage().contains("cannot be changed from type [faketype] to [otherfaketype]"));
@ -182,33 +167,33 @@ public class FieldTypeLookupTests extends ESTestCase {
public void testCheckCompatibilityConflict() {
FieldMapper f1 = new FakeFieldMapper("foo", "bar");
FieldTypeLookup lookup = new FieldTypeLookup();
lookup = lookup.copyAndAddAll("type", newList(f1));
lookup = lookup.copyAndAddAll("type", newList(f1), randomBoolean());
MappedFieldType ft2 = FakeFieldMapper.makeFieldType("foo", "bar");
ft2.setBoost(2.0f);
FieldMapper f2 = new FakeFieldMapper("foo", ft2);
try {
// different type
lookup.checkCompatibility("type2", newList(f2), false);
lookup.copyAndAddAll("type2", newList(f2), false);
fail("expected conflict");
} catch (IllegalArgumentException e) {
assertTrue(e.getMessage().contains("to update [boost] across all types"));
}
lookup.checkCompatibility("type", newList(f2), false); // boost is updateable, so ok since we are implicitly updating all types
lookup.checkCompatibility("type2", newList(f2), true); // boost is updateable, so ok if forcing
lookup.copyAndAddAll("type", newList(f2), false); // boost is updateable, so ok since we are implicitly updating all types
lookup.copyAndAddAll("type2", newList(f2), true); // boost is updateable, so ok if forcing
// now with a non changeable setting
MappedFieldType ft3 = FakeFieldMapper.makeFieldType("foo", "bar");
ft3.setStored(true);
FieldMapper f3 = new FakeFieldMapper("foo", ft3);
try {
lookup.checkCompatibility("type2", newList(f3), false);
lookup.copyAndAddAll("type2", newList(f3), false);
fail("expected conflict");
} catch (IllegalArgumentException e) {
assertTrue(e.getMessage().contains("has different [store] values"));
}
// even with updateAllTypes == true, incompatible
try {
lookup.checkCompatibility("type2", newList(f3), true);
lookup.copyAndAddAll("type2", newList(f3), true);
fail("expected conflict");
} catch (IllegalArgumentException e) {
assertTrue(e.getMessage().contains("has different [store] values"));
@ -219,7 +204,7 @@ public class FieldTypeLookupTests extends ESTestCase {
FakeFieldMapper f1 = new FakeFieldMapper("foo", "baz");
FakeFieldMapper f2 = new FakeFieldMapper("bar", "boo");
FieldTypeLookup lookup = new FieldTypeLookup();
lookup = lookup.copyAndAddAll("type", newList(f1, f2));
lookup = lookup.copyAndAddAll("type", newList(f1, f2), randomBoolean());
Collection<String> names = lookup.simpleMatchToIndexNames("b*");
assertTrue(names.contains("baz"));
assertTrue(names.contains("boo"));
@ -229,7 +214,7 @@ public class FieldTypeLookupTests extends ESTestCase {
FakeFieldMapper f1 = new FakeFieldMapper("foo", "baz");
FakeFieldMapper f2 = new FakeFieldMapper("bar", "boo");
FieldTypeLookup lookup = new FieldTypeLookup();
lookup = lookup.copyAndAddAll("type", newList(f1, f2));
lookup = lookup.copyAndAddAll("type", newList(f1, f2), randomBoolean());
Collection<String> names = lookup.simpleMatchToFullName("b*");
assertTrue(names.contains("foo"));
assertTrue(names.contains("bar"));
@ -238,7 +223,7 @@ public class FieldTypeLookupTests extends ESTestCase {
public void testIteratorImmutable() {
FakeFieldMapper f1 = new FakeFieldMapper("foo", "bar");
FieldTypeLookup lookup = new FieldTypeLookup();
lookup = lookup.copyAndAddAll("type", newList(f1));
lookup = lookup.copyAndAddAll("type", newList(f1), randomBoolean());
try {
Iterator<MappedFieldType> itr = lookup.iterator();

View File

@ -44,6 +44,7 @@ public class CamelCaseFieldNameTests extends ESSingleNodeTestCase {
assertNotNull(doc.dynamicMappingsUpdate());
client().admin().indices().preparePutMapping("test").setType("type").setSource(doc.dynamicMappingsUpdate().toString()).get();
documentMapper = index.mapperService().documentMapper("type");
assertNotNull(documentMapper.mappers().getMapper("thisIsCamelCase"));
assertNull(documentMapper.mappers().getMapper("this_is_camel_case"));

View File

@ -32,6 +32,7 @@ import org.elasticsearch.index.mapper.DocumentMapper;
import org.elasticsearch.index.mapper.DocumentMapperParser;
import org.elasticsearch.index.mapper.FieldMapper;
import org.elasticsearch.index.mapper.MapperParsingException;
import org.elasticsearch.index.mapper.MapperService;
import org.elasticsearch.index.mapper.ParseContext;
import org.elasticsearch.index.mapper.ParseContext.Document;
import org.elasticsearch.index.mapper.ParsedDocument;
@ -39,6 +40,7 @@ import org.elasticsearch.index.mapper.core.LongFieldMapper;
import org.elasticsearch.index.mapper.core.StringFieldMapper;
import org.elasticsearch.test.ESSingleNodeTestCase;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
@ -127,6 +129,7 @@ public class CopyToMapperTests extends ESSingleNodeTestCase {
assertNotNull(parsedDoc.dynamicMappingsUpdate());
client().admin().indices().preparePutMapping("test").setType("type1").setSource(parsedDoc.dynamicMappingsUpdate().toString()).get();
docMapper = index.mapperService().documentMapper("type1");
fieldMapper = docMapper.mappers().getMapper("new_field");
assertThat(fieldMapper, instanceOf(LongFieldMapper.class));
}
@ -308,27 +311,15 @@ public class CopyToMapperTests extends ESSingleNodeTestCase {
.endObject().endObject().endObject().string();
DocumentMapperParser parser = createIndex("test").mapperService().documentMapperParser();
DocumentMapper docMapperBefore = parser.parse("type1", new CompressedXContent(mappingBefore));
MapperService mapperService = createIndex("test").mapperService();
DocumentMapper docMapperBefore = mapperService.merge("type1", new CompressedXContent(mappingBefore), true, false);
List<String> fields = docMapperBefore.mappers().getMapper("copy_test").copyTo().copyToFields();
assertEquals(Arrays.asList("foo", "bar"), docMapperBefore.mappers().getMapper("copy_test").copyTo().copyToFields());
assertThat(fields.size(), equalTo(2));
assertThat(fields.get(0), equalTo("foo"));
assertThat(fields.get(1), equalTo("bar"));
DocumentMapper docMapperAfter = mapperService.merge("type1", new CompressedXContent(mappingAfter), false, false);
DocumentMapper docMapperAfter = parser.parse("type1", new CompressedXContent(mappingAfter));
docMapperBefore.merge(docMapperAfter.mapping(), true, false);
docMapperBefore.merge(docMapperAfter.mapping(), false, false);
fields = docMapperBefore.mappers().getMapper("copy_test").copyTo().copyToFields();
assertThat(fields.size(), equalTo(2));
assertThat(fields.get(0), equalTo("baz"));
assertThat(fields.get(1), equalTo("bar"));
assertEquals(Arrays.asList("baz", "bar"), docMapperAfter.mappers().getMapper("copy_test").copyTo().copyToFields());
assertEquals(Arrays.asList("foo", "bar"), docMapperBefore.mappers().getMapper("copy_test").copyTo().copyToFields());
}
public void testCopyToNestedField() throws Exception {

View File

@ -28,6 +28,7 @@ import org.elasticsearch.common.compress.CompressedXContent;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.index.mapper.DocumentMapper;
import org.elasticsearch.index.mapper.DocumentMapperParser;
import org.elasticsearch.index.mapper.MapperService;
import org.elasticsearch.test.ESSingleNodeTestCase;
import java.io.IOException;
@ -50,8 +51,8 @@ public class TokenCountFieldMapperTests extends ESSingleNodeTestCase {
.endObject()
.endObject()
.endObject().endObject().string();
DocumentMapperParser parser = createIndex("test").mapperService().documentMapperParser();
DocumentMapper stage1 = parser.parse("person", new CompressedXContent(stage1Mapping));
MapperService mapperService = createIndex("test").mapperService();
DocumentMapper stage1 = mapperService.merge("person", new CompressedXContent(stage1Mapping), true, false);
String stage2Mapping = XContentFactory.jsonBuilder().startObject()
.startObject("person")
@ -62,15 +63,12 @@ public class TokenCountFieldMapperTests extends ESSingleNodeTestCase {
.endObject()
.endObject()
.endObject().endObject().string();
DocumentMapper stage2 = parser.parse("person", new CompressedXContent(stage2Mapping));
DocumentMapper stage2 = mapperService.merge("person", new CompressedXContent(stage2Mapping), false, false);
stage1.merge(stage2.mapping(), true, false);
// Just simulated so merge hasn't happened yet
// previous mapper has not been modified
assertThat(((TokenCountFieldMapper) stage1.mappers().smartNameFieldMapper("tc")).analyzer(), equalTo("keyword"));
stage1.merge(stage2.mapping(), false, false);
// Just simulated so merge hasn't happened yet
assertThat(((TokenCountFieldMapper) stage1.mappers().smartNameFieldMapper("tc")).analyzer(), equalTo("standard"));
// but the new one has the change
assertThat(((TokenCountFieldMapper) stage2.mappers().smartNameFieldMapper("tc")).analyzer(), equalTo("standard"));
}
public void testCountPositions() throws IOException {

View File

@ -80,7 +80,9 @@ public class SimpleDateMappingTests extends ESSingleNodeTestCase {
.startObject("properties").endObject()
.endObject().endObject().string();
DocumentMapper defaultMapper = mapper("test", "type", mapping);
IndexService index = createIndex("test");
client().admin().indices().preparePutMapping("test").setType("type").setSource(mapping).get();
DocumentMapper defaultMapper = index.mapperService().documentMapper("type");
ParsedDocument doc = defaultMapper.parse("test", "type", "1", XContentFactory.jsonBuilder()
.startObject()
@ -94,6 +96,7 @@ public class SimpleDateMappingTests extends ESSingleNodeTestCase {
assertNotNull(doc.dynamicMappingsUpdate());
client().admin().indices().preparePutMapping("test").setType("type").setSource(doc.dynamicMappingsUpdate().toString()).get();
defaultMapper = index.mapperService().documentMapper("type");
FieldMapper fieldMapper = defaultMapper.mappers().smartNameFieldMapper("date_field1");
assertThat(fieldMapper, instanceOf(DateFieldMapper.class));
DateFieldMapper dateFieldMapper = (DateFieldMapper)fieldMapper;
@ -384,7 +387,7 @@ public class SimpleDateMappingTests extends ESSingleNodeTestCase {
Map<String, String> config = getConfigurationViaXContent(initialDateFieldMapper);
assertThat(config.get("format"), is("EEE MMM dd HH:mm:ss.S Z yyyy||EEE MMM dd HH:mm:ss.SSS Z yyyy"));
defaultMapper.merge(mergeMapper.mapping(), false, false);
defaultMapper = defaultMapper.merge(mergeMapper.mapping(), false);
assertThat(defaultMapper.mappers().getMapper("field"), is(instanceOf(DateFieldMapper.class)));

View File

@ -44,6 +44,7 @@ public class GenericStoreDynamicTemplateTests extends ESSingleNodeTestCase {
byte[] json = copyToBytesFromClasspath("/org/elasticsearch/index/mapper/dynamictemplate/genericstore/test-data.json");
ParsedDocument parsedDoc = docMapper.parse("test", "person", "1", new BytesArray(json));
client().admin().indices().preparePutMapping("test").setType("person").setSource(parsedDoc.dynamicMappingsUpdate().toString()).get();
docMapper = index.mapperService().documentMapper("person");
Document doc = parsedDoc.rootDoc();
IndexableField f = doc.getField("name");

View File

@ -44,6 +44,7 @@ public class PathMatchDynamicTemplateTests extends ESSingleNodeTestCase {
byte[] json = copyToBytesFromClasspath("/org/elasticsearch/index/mapper/dynamictemplate/pathmatch/test-data.json");
ParsedDocument parsedDoc = docMapper.parse("test", "person", "1", new BytesArray(json));
client().admin().indices().preparePutMapping("test").setType("person").setSource(parsedDoc.dynamicMappingsUpdate().toString()).get();
docMapper = index.mapperService().documentMapper("person");
Document doc = parsedDoc.rootDoc();
IndexableField f = doc.getField("name");

View File

@ -55,6 +55,7 @@ public class SimpleDynamicTemplatesTests extends ESSingleNodeTestCase {
ParsedDocument parsedDoc = docMapper.parse("test", "person", "1", builder.bytes());
client().admin().indices().preparePutMapping("test").setType("person").setSource(parsedDoc.dynamicMappingsUpdate().toString()).get();
docMapper = index.mapperService().documentMapper("person");
DocumentFieldMappers mappers = docMapper.mappers();
assertThat(mappers.smartNameFieldMapper("s"), Matchers.notNullValue());
@ -74,6 +75,7 @@ public class SimpleDynamicTemplatesTests extends ESSingleNodeTestCase {
byte[] json = copyToBytesFromClasspath("/org/elasticsearch/index/mapper/dynamictemplate/simple/test-data.json");
ParsedDocument parsedDoc = docMapper.parse("test", "person", "1", new BytesArray(json));
client().admin().indices().preparePutMapping("test").setType("person").setSource(parsedDoc.dynamicMappingsUpdate().toString()).get();
docMapper = index.mapperService().documentMapper("person");
Document doc = parsedDoc.rootDoc();
IndexableField f = doc.getField("name");
@ -130,6 +132,7 @@ public class SimpleDynamicTemplatesTests extends ESSingleNodeTestCase {
byte[] json = copyToBytesFromClasspath("/org/elasticsearch/index/mapper/dynamictemplate/simple/test-data.json");
ParsedDocument parsedDoc = docMapper.parse("test", "person", "1", new BytesArray(json));
client().admin().indices().preparePutMapping("test").setType("person").setSource(parsedDoc.dynamicMappingsUpdate().toString()).get();
docMapper = index.mapperService().documentMapper("person");
Document doc = parsedDoc.rootDoc();
IndexableField f = doc.getField("name");

View File

@ -35,6 +35,7 @@ import org.elasticsearch.index.mapper.MapperParsingException;
import org.elasticsearch.index.mapper.ParseContext;
import org.elasticsearch.index.mapper.core.BinaryFieldMapper;
import org.elasticsearch.index.mapper.core.BooleanFieldMapper;
import org.elasticsearch.index.mapper.core.StringFieldMapper;
import org.elasticsearch.index.mapper.geo.BaseGeoPointFieldMapper;
import org.elasticsearch.index.mapper.geo.GeoPointFieldMapper;
import org.elasticsearch.index.mapper.geo.GeoPointFieldMapperLegacy;
@ -160,11 +161,11 @@ public class ExternalMapper extends FieldMapper {
private final String generatedValue;
private final String mapperName;
private final BinaryFieldMapper binMapper;
private final BooleanFieldMapper boolMapper;
private final BaseGeoPointFieldMapper pointMapper;
private final GeoShapeFieldMapper shapeMapper;
private final FieldMapper stringMapper;
private BinaryFieldMapper binMapper;
private BooleanFieldMapper boolMapper;
private BaseGeoPointFieldMapper pointMapper;
private GeoShapeFieldMapper shapeMapper;
private FieldMapper stringMapper;
public ExternalMapper(String simpleName, MappedFieldType fieldType,
String generatedValue, String mapperName,
@ -216,6 +217,36 @@ public class ExternalMapper extends FieldMapper {
// ignore this for now
}
@Override
public FieldMapper updateFieldType(Map<String, MappedFieldType> fullNameToFieldType) {
ExternalMapper update = (ExternalMapper) super.updateFieldType(fullNameToFieldType);
MultiFields multiFieldsUpdate = multiFields.updateFieldType(fullNameToFieldType);
BinaryFieldMapper binMapperUpdate = (BinaryFieldMapper) binMapper.updateFieldType(fullNameToFieldType);
BooleanFieldMapper boolMapperUpdate = (BooleanFieldMapper) boolMapper.updateFieldType(fullNameToFieldType);
GeoPointFieldMapper pointMapperUpdate = (GeoPointFieldMapper) pointMapper.updateFieldType(fullNameToFieldType);
GeoShapeFieldMapper shapeMapperUpdate = (GeoShapeFieldMapper) shapeMapper.updateFieldType(fullNameToFieldType);
StringFieldMapper stringMapperUpdate = (StringFieldMapper) stringMapper.updateFieldType(fullNameToFieldType);
if (update == this
&& multiFieldsUpdate == multiFields
&& binMapperUpdate == binMapper
&& boolMapperUpdate == boolMapper
&& pointMapperUpdate == pointMapper
&& shapeMapperUpdate == shapeMapper
&& stringMapperUpdate == stringMapper) {
return this;
}
if (update == this) {
update = (ExternalMapper) clone();
}
update.multiFields = multiFieldsUpdate;
update.binMapper = binMapperUpdate;
update.boolMapper = boolMapperUpdate;
update.pointMapper = pointMapperUpdate;
update.shapeMapper = shapeMapperUpdate;
update.stringMapper = stringMapperUpdate;
return update;
}
@Override
public Iterator<Mapper> iterator() {
return Iterators.concat(super.iterator(), Arrays.asList(binMapper, boolMapper, pointMapper, shapeMapper, stringMapper).iterator());

View File

@ -53,23 +53,11 @@ public class ExternalMetadataMapper extends MetadataFieldMapper {
super(FIELD_NAME, FIELD_TYPE, FIELD_TYPE, indexSettings);
}
@Override
public String name() {
return CONTENT_TYPE;
}
@Override
protected void parseCreateField(ParseContext context, List<Field> fields) throws IOException {
// handled in post parse
}
@Override
public void doMerge(Mapper mergeWith, boolean updateAllTypes) {
if (!(mergeWith instanceof ExternalMetadataMapper)) {
throw new IllegalArgumentException("Trying to merge " + mergeWith + " with " + this);
}
}
@Override
public Iterator<Mapper> iterator() {
return Collections.emptyIterator();
@ -97,7 +85,7 @@ public class ExternalMetadataMapper extends MetadataFieldMapper {
public static class Builder extends MetadataFieldMapper.Builder<Builder, ExternalMetadataMapper> {
protected Builder() {
super(CONTENT_TYPE, FIELD_TYPE, FIELD_TYPE);
super(FIELD_NAME, FIELD_TYPE, FIELD_TYPE);
}
@Override

View File

@ -376,7 +376,7 @@ public class GeoShapeFieldMapperTests extends ESSingleNodeTestCase {
.field("precision", "1m").field("tree_levels", 8).field("distance_error_pct", 0.01).field("orientation", "ccw")
.endObject().endObject().endObject().endObject().string();
MapperService mapperService = createIndex("test").mapperService();
DocumentMapper stage1 = mapperService.merge("type", new CompressedXContent(stage1Mapping), true, false);
DocumentMapper docMapper = mapperService.merge("type", new CompressedXContent(stage1Mapping), true, false);
String stage2Mapping = XContentFactory.jsonBuilder().startObject().startObject("type")
.startObject("properties").startObject("shape").field("type", "geo_shape").field("tree", "quadtree")
.field("strategy", "term").field("precision", "1km").field("tree_levels", 26).field("distance_error_pct", 26)
@ -392,7 +392,7 @@ public class GeoShapeFieldMapperTests extends ESSingleNodeTestCase {
}
// verify nothing changed
FieldMapper fieldMapper = stage1.mappers().getMapper("shape");
FieldMapper fieldMapper = docMapper.mappers().getMapper("shape");
assertThat(fieldMapper, instanceOf(GeoShapeFieldMapper.class));
GeoShapeFieldMapper geoShapeFieldMapper = (GeoShapeFieldMapper) fieldMapper;
@ -408,9 +408,9 @@ public class GeoShapeFieldMapperTests extends ESSingleNodeTestCase {
stage2Mapping = XContentFactory.jsonBuilder().startObject().startObject("type")
.startObject("properties").startObject("shape").field("type", "geo_shape").field("precision", "1m")
.field("tree_levels", 8).field("distance_error_pct", 0.001).field("orientation", "cw").endObject().endObject().endObject().endObject().string();
mapperService.merge("type", new CompressedXContent(stage2Mapping), false, false);
docMapper = mapperService.merge("type", new CompressedXContent(stage2Mapping), false, false);
fieldMapper = stage1.mappers().getMapper("shape");
fieldMapper = docMapper.mappers().getMapper("shape");
assertThat(fieldMapper, instanceOf(GeoShapeFieldMapper.class));
geoShapeFieldMapper = (GeoShapeFieldMapper) fieldMapper;

View File

@ -25,7 +25,7 @@ import org.elasticsearch.common.compress.CompressedXContent;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.index.mapper.DocumentMapper;
import org.elasticsearch.index.mapper.DocumentMapperParser;
import org.elasticsearch.index.mapper.MapperService;
import org.elasticsearch.index.mapper.ParsedDocument;
import org.elasticsearch.index.mapper.internal.IndexFieldMapper;
import org.elasticsearch.test.ESSingleNodeTestCase;
@ -94,33 +94,16 @@ public class IndexTypeMapperTests extends ESSingleNodeTestCase {
String mappingWithIndexEnabled = XContentFactory.jsonBuilder().startObject().startObject("type")
.startObject("_index").field("enabled", true).endObject()
.endObject().endObject().string();
DocumentMapperParser parser = createIndex("test", bwcSettings).mapperService().documentMapperParser();
DocumentMapper mapperEnabled = parser.parse("type", new CompressedXContent(mappingWithIndexEnabled));
MapperService mapperService = createIndex("test", bwcSettings).mapperService();
DocumentMapper mapperEnabled = mapperService.merge("type", new CompressedXContent(mappingWithIndexEnabled), true, false);
assertThat(mapperEnabled.IndexFieldMapper().enabled(), is(true));
String mappingWithIndexDisabled = XContentFactory.jsonBuilder().startObject().startObject("type")
.startObject("_index").field("enabled", false).endObject()
.endObject().endObject().string();
DocumentMapper mapperDisabled = parser.parse("type", new CompressedXContent(mappingWithIndexDisabled));
DocumentMapper merged = mapperService.merge("type", new CompressedXContent(mappingWithIndexDisabled), false, false);
mapperEnabled.merge(mapperDisabled.mapping(), false, false);
assertThat(mapperEnabled.IndexFieldMapper().enabled(), is(false));
}
public void testThatDisablingWorksWhenMergingBackcompat() throws Exception {
String enabledMapping = XContentFactory.jsonBuilder().startObject().startObject("type")
.startObject("_index").field("enabled", true).endObject()
.endObject().endObject().string();
DocumentMapperParser parser = createIndex("test", bwcSettings).mapperService().documentMapperParser();
DocumentMapper enabledMapper = parser.parse("type", new CompressedXContent(enabledMapping));
String disabledMapping = XContentFactory.jsonBuilder().startObject().startObject("type")
.startObject("_index").field("enabled", false).endObject()
.endObject().endObject().string();
DocumentMapper disabledMapper = parser.parse("type", new CompressedXContent(disabledMapping));
enabledMapper.merge(disabledMapper.mapping(), false, false);
assertThat(enabledMapper.indexMapper().enabled(), is(false));
assertThat(merged.IndexFieldMapper().enabled(), is(false));
}
public void testCustomSettingsBackcompat() throws Exception {

View File

@ -187,15 +187,13 @@ public class FieldNamesFieldMapperTests extends ESSingleNodeTestCase {
String disabledMapping = XContentFactory.jsonBuilder().startObject().startObject("type")
.startObject("_field_names").field("enabled", false).endObject()
.endObject().endObject().string();
DocumentMapperParser parser = createIndex("test").mapperService().documentMapperParser();
MapperService mapperService = createIndex("test").mapperService();
DocumentMapper mapperEnabled = parser.parse("type", new CompressedXContent(enabledMapping));
DocumentMapper mapperDisabled = parser.parse("type", new CompressedXContent(disabledMapping));
mapperEnabled.merge(mapperDisabled.mapping(), false, false);
assertFalse(mapperEnabled.metadataMapper(FieldNamesFieldMapper.class).fieldType().isEnabled());
DocumentMapper mapperEnabled = mapperService.merge("type", new CompressedXContent(enabledMapping), true, false);
DocumentMapper mapperDisabled = mapperService.merge("type", new CompressedXContent(disabledMapping), false, false);
assertFalse(mapperDisabled.metadataMapper(FieldNamesFieldMapper.class).fieldType().isEnabled());
mapperEnabled = parser.parse("type", new CompressedXContent(enabledMapping));
mapperDisabled.merge(mapperEnabled.mapping(), false, false);
mapperEnabled = mapperService.merge("type", new CompressedXContent(enabledMapping), false, false);
assertTrue(mapperEnabled.metadataMapper(FieldNamesFieldMapper.class).fieldType().isEnabled());
}

View File

@ -59,6 +59,7 @@ public class DoubleIndexingDocTests extends ESSingleNodeTestCase {
.bytes());
assertNotNull(doc.dynamicMappingsUpdate());
client().admin().indices().preparePutMapping("test").setType("type").setSource(doc.dynamicMappingsUpdate().toString()).get();
mapper = index.mapperService().documentMapper("type");
writer.addDocument(doc.rootDoc());
writer.addDocument(doc.rootDoc());

View File

@ -59,15 +59,13 @@ public class TestMergeMapperTests extends ESSingleNodeTestCase {
.endObject().endObject().endObject().string();
DocumentMapper stage2 = parser.parse("person", new CompressedXContent(stage2Mapping));
stage1.merge(stage2.mapping(), true, false);
// since we are simulating, we should not have the age mapping
DocumentMapper merged = stage1.merge(stage2.mapping(), false);
// stage1 mapping should not have been modified
assertThat(stage1.mappers().smartNameFieldMapper("age"), nullValue());
assertThat(stage1.mappers().smartNameFieldMapper("obj1.prop1"), nullValue());
// now merge, don't simulate
stage1.merge(stage2.mapping(), false, false);
// but we have the age in
assertThat(stage1.mappers().smartNameFieldMapper("age"), notNullValue());
assertThat(stage1.mappers().smartNameFieldMapper("obj1.prop1"), notNullValue());
// but merged should
assertThat(merged.mappers().smartNameFieldMapper("age"), notNullValue());
assertThat(merged.mappers().smartNameFieldMapper("obj1.prop1"), notNullValue());
}
public void testMergeObjectDynamic() throws Exception {
@ -80,8 +78,8 @@ public class TestMergeMapperTests extends ESSingleNodeTestCase {
DocumentMapper withDynamicMapper = parser.parse("type1", new CompressedXContent(withDynamicMapping));
assertThat(withDynamicMapper.root().dynamic(), equalTo(ObjectMapper.Dynamic.FALSE));
mapper.merge(withDynamicMapper.mapping(), false, false);
assertThat(mapper.root().dynamic(), equalTo(ObjectMapper.Dynamic.FALSE));
DocumentMapper merged = mapper.merge(withDynamicMapper.mapping(), false);
assertThat(merged.root().dynamic(), equalTo(ObjectMapper.Dynamic.FALSE));
}
public void testMergeObjectAndNested() throws Exception {
@ -96,14 +94,14 @@ public class TestMergeMapperTests extends ESSingleNodeTestCase {
DocumentMapper nestedMapper = parser.parse("type1", new CompressedXContent(nestedMapping));
try {
objectMapper.merge(nestedMapper.mapping(), true, false);
objectMapper.merge(nestedMapper.mapping(), false);
fail();
} catch (IllegalArgumentException e) {
assertThat(e.getMessage(), containsString("object mapping [obj] can't be changed from non-nested to nested"));
}
try {
nestedMapper.merge(objectMapper.mapping(), true, false);
nestedMapper.merge(objectMapper.mapping(), false);
fail();
} catch (IllegalArgumentException e) {
assertThat(e.getMessage(), containsString("object mapping [obj] can't be changed from nested to non-nested"));
@ -123,13 +121,13 @@ public class TestMergeMapperTests extends ESSingleNodeTestCase {
DocumentMapper changed = parser.parse("type", new CompressedXContent(mapping2));
assertThat(((NamedAnalyzer) existing.mappers().getMapper("field").fieldType().searchAnalyzer()).name(), equalTo("whitespace"));
existing.merge(changed.mapping(), false, false);
DocumentMapper merged = existing.merge(changed.mapping(), false);
assertThat(((NamedAnalyzer) existing.mappers().getMapper("field").fieldType().searchAnalyzer()).name(), equalTo("keyword"));
assertThat(((NamedAnalyzer) merged.mappers().getMapper("field").fieldType().searchAnalyzer()).name(), equalTo("keyword"));
}
public void testChangeSearchAnalyzerToDefault() throws Exception {
DocumentMapperParser parser = createIndex("test").mapperService().documentMapperParser();
MapperService mapperService = createIndex("test").mapperService();
String mapping1 = XContentFactory.jsonBuilder().startObject().startObject("type")
.startObject("properties").startObject("field").field("type", "string").field("analyzer", "standard").field("search_analyzer", "whitespace").endObject().endObject()
.endObject().endObject().string();
@ -137,14 +135,13 @@ public class TestMergeMapperTests extends ESSingleNodeTestCase {
.startObject("properties").startObject("field").field("type", "string").field("analyzer", "standard").field("ignore_above", 14).endObject().endObject()
.endObject().endObject().string();
DocumentMapper existing = parser.parse("type", new CompressedXContent(mapping1));
DocumentMapper changed = parser.parse("type", new CompressedXContent(mapping2));
DocumentMapper existing = mapperService.merge("type", new CompressedXContent(mapping1), true, false);
DocumentMapper merged = mapperService.merge("type", new CompressedXContent(mapping2), false, false);
assertThat(((NamedAnalyzer) existing.mappers().getMapper("field").fieldType().searchAnalyzer()).name(), equalTo("whitespace"));
existing.merge(changed.mapping(), false, false);
assertThat(((NamedAnalyzer) existing.mappers().getMapper("field").fieldType().searchAnalyzer()).name(), equalTo("standard"));
assertThat(((StringFieldMapper) (existing.mappers().getMapper("field"))).getIgnoreAbove(), equalTo(14));
assertThat(((NamedAnalyzer) merged.mappers().getMapper("field").fieldType().searchAnalyzer()).name(), equalTo("standard"));
assertThat(((StringFieldMapper) (merged.mappers().getMapper("field"))).getIgnoreAbove(), equalTo(14));
}
public void testConcurrentMergeTest() throws Throwable {

View File

@ -150,19 +150,17 @@ public class MultiFieldTests extends ESSingleNodeTestCase {
public void testBuildThenParse() throws Exception {
IndexService indexService = createIndex("test");
Settings settings = indexService.getIndexSettings().getSettings();
DocumentMapperParser mapperParser = indexService.mapperService().documentMapperParser();
DocumentMapper builderDocMapper = doc(settings, rootObject("person").add(
DocumentMapper builderDocMapper = doc(rootObject("person").add(
stringField("name").store(true)
.addMultiField(stringField("indexed").index(true).tokenized(true))
.addMultiField(stringField("not_indexed").index(false).store(true))
), indexService.mapperService()).build(indexService.mapperService(), mapperParser);
), indexService.mapperService()).build(indexService.mapperService());
String builtMapping = builderDocMapper.mappingSource().string();
// System.out.println(builtMapping);
// reparse it
DocumentMapper docMapper = mapperParser.parse("person", new CompressedXContent(builtMapping));
DocumentMapper docMapper = indexService.mapperService().documentMapperParser().parse("person", new CompressedXContent(builtMapping));
BytesReference json = new BytesArray(copyToBytesFromClasspath("/org/elasticsearch/index/mapper/multifield/test-data.json"));

View File

@ -25,7 +25,6 @@ import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.compress.CompressedXContent;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.index.mapper.DocumentMapper;
import org.elasticsearch.index.mapper.DocumentMapperParser;
import org.elasticsearch.index.mapper.MapperService;
import org.elasticsearch.index.mapper.ParseContext.Document;
import org.elasticsearch.test.ESSingleNodeTestCase;
@ -41,9 +40,9 @@ import static org.hamcrest.Matchers.nullValue;
public class JavaMultiFieldMergeTests extends ESSingleNodeTestCase {
public void testMergeMultiField() throws Exception {
String mapping = copyToStringFromClasspath("/org/elasticsearch/index/mapper/multifield/merge/test-mapping1.json");
DocumentMapperParser parser = createIndex("test").mapperService().documentMapperParser();
MapperService mapperService = createIndex("test").mapperService();
DocumentMapper docMapper = parser.parse("person", new CompressedXContent(mapping));
DocumentMapper docMapper = mapperService.merge("person", new CompressedXContent(mapping), true, false);
assertNotSame(IndexOptions.NONE, docMapper.mappers().getMapper("name").fieldType().indexOptions());
assertThat(docMapper.mappers().getMapper("name.indexed"), nullValue());
@ -56,11 +55,7 @@ public class JavaMultiFieldMergeTests extends ESSingleNodeTestCase {
assertThat(f, nullValue());
mapping = copyToStringFromClasspath("/org/elasticsearch/index/mapper/multifield/merge/test-mapping2.json");
DocumentMapper docMapper2 = parser.parse("person", new CompressedXContent(mapping));
docMapper.merge(docMapper2.mapping(), true, false);
docMapper.merge(docMapper2.mapping(), false, false);
docMapper = mapperService.merge("person", new CompressedXContent(mapping), false, false);
assertNotSame(IndexOptions.NONE, docMapper.mappers().getMapper("name").fieldType().indexOptions());
@ -77,11 +72,7 @@ public class JavaMultiFieldMergeTests extends ESSingleNodeTestCase {
assertThat(f, notNullValue());
mapping = copyToStringFromClasspath("/org/elasticsearch/index/mapper/multifield/merge/test-mapping3.json");
DocumentMapper docMapper3 = parser.parse("person", new CompressedXContent(mapping));
docMapper.merge(docMapper3.mapping(), true, false);
docMapper.merge(docMapper3.mapping(), false, false);
docMapper = mapperService.merge("person", new CompressedXContent(mapping), false, false);
assertNotSame(IndexOptions.NONE, docMapper.mappers().getMapper("name").fieldType().indexOptions());
@ -92,11 +83,7 @@ public class JavaMultiFieldMergeTests extends ESSingleNodeTestCase {
assertThat(docMapper.mappers().getMapper("name.not_indexed3"), nullValue());
mapping = copyToStringFromClasspath("/org/elasticsearch/index/mapper/multifield/merge/test-mapping4.json");
DocumentMapper docMapper4 = parser.parse("person", new CompressedXContent(mapping));
docMapper.merge(docMapper4.mapping(), true, false);
docMapper.merge(docMapper4.mapping(), false, false);
docMapper = mapperService.merge("person", new CompressedXContent(mapping), false, false);
assertNotSame(IndexOptions.NONE, docMapper.mappers().getMapper("name").fieldType().indexOptions());
@ -125,7 +112,7 @@ public class JavaMultiFieldMergeTests extends ESSingleNodeTestCase {
mapping = copyToStringFromClasspath("/org/elasticsearch/index/mapper/multifield/merge/upgrade1.json");
mapperService.merge("person", new CompressedXContent(mapping), false, false);
docMapper = mapperService.merge("person", new CompressedXContent(mapping), false, false);
assertNotSame(IndexOptions.NONE, docMapper.mappers().getMapper("name").fieldType().indexOptions());
@ -142,7 +129,7 @@ public class JavaMultiFieldMergeTests extends ESSingleNodeTestCase {
assertThat(f, notNullValue());
mapping = copyToStringFromClasspath("/org/elasticsearch/index/mapper/multifield/merge/upgrade2.json");
mapperService.merge("person", new CompressedXContent(mapping), false, false);
docMapper = mapperService.merge("person", new CompressedXContent(mapping), false, false);
assertNotSame(IndexOptions.NONE, docMapper.mappers().getMapper("name").fieldType().indexOptions());

View File

@ -74,6 +74,7 @@ public class SimpleNumericTests extends ESSingleNodeTestCase {
assertNotNull(doc.dynamicMappingsUpdate());
client().admin().indices().preparePutMapping("test").setType("type").setSource(doc.dynamicMappingsUpdate().toString()).get();
defaultMapper = index.mapperService().documentMapper("type");
FieldMapper mapper = defaultMapper.mappers().smartNameFieldMapper("s_long");
assertThat(mapper, instanceOf(LongFieldMapper.class));
@ -98,6 +99,7 @@ public class SimpleNumericTests extends ESSingleNodeTestCase {
assertNotNull(doc.dynamicMappingsUpdate());
assertAcked(client().admin().indices().preparePutMapping("test").setType("type").setSource(doc.dynamicMappingsUpdate().toString()).get());
defaultMapper = index.mapperService().documentMapper("type");
FieldMapper mapper = defaultMapper.mappers().smartNameFieldMapper("s_long");
assertThat(mapper, instanceOf(StringFieldMapper.class));

View File

@ -22,7 +22,6 @@ package org.elasticsearch.index.mapper.simple;
import org.elasticsearch.common.bytes.BytesArray;
import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.compress.CompressedXContent;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.index.IndexService;
import org.elasticsearch.index.mapper.DocumentMapper;
@ -48,12 +47,10 @@ import static org.hamcrest.Matchers.equalTo;
public class SimpleMapperTests extends ESSingleNodeTestCase {
public void testSimpleMapper() throws Exception {
IndexService indexService = createIndex("test");
Settings settings = indexService.getIndexSettings().getSettings();
DocumentMapperParser mapperParser = indexService.mapperService().documentMapperParser();
DocumentMapper docMapper = doc(settings,
DocumentMapper docMapper = doc(
rootObject("person")
.add(object("name").add(stringField("first").store(true).index(false))),
indexService.mapperService()).build(indexService.mapperService(), mapperParser);
indexService.mapperService()).build(indexService.mapperService());
BytesReference json = new BytesArray(copyToBytesFromClasspath("/org/elasticsearch/index/mapper/simple/test1.json"));
Document doc = docMapper.parse("test", "person", "1", json).rootDoc();
@ -110,12 +107,10 @@ public class SimpleMapperTests extends ESSingleNodeTestCase {
public void testNoDocumentSent() throws Exception {
IndexService indexService = createIndex("test");
Settings settings = indexService.getIndexSettings().getSettings();
DocumentMapperParser mapperParser = indexService.mapperService().documentMapperParser();
DocumentMapper docMapper = doc(settings,
DocumentMapper docMapper = doc(
rootObject("person")
.add(object("name").add(stringField("first").store(true).index(false))),
indexService.mapperService()).build(indexService.mapperService(), mapperParser);
indexService.mapperService()).build(indexService.mapperService());
BytesReference json = new BytesArray("".getBytes(StandardCharsets.UTF_8));
try {

View File

@ -196,10 +196,10 @@ public class DefaultSourceMappingTests extends ESSingleNodeTestCase {
DocumentMapper docMapper = parser.parse("type", new CompressedXContent(mapping1));
docMapper = parser.parse("type", docMapper.mappingSource());
if (conflicts.length == 0) {
docMapper.merge(parser.parse("type", new CompressedXContent(mapping2)).mapping(), true, false);
docMapper.merge(parser.parse("type", new CompressedXContent(mapping2)).mapping(), false);
} else {
try {
docMapper.merge(parser.parse("type", new CompressedXContent(mapping2)).mapping(), true, false);
docMapper.merge(parser.parse("type", new CompressedXContent(mapping2)).mapping(), false);
fail();
} catch (IllegalArgumentException e) {
for (String conflict : conflicts) {

View File

@ -40,6 +40,7 @@ import org.elasticsearch.index.mapper.DocumentMapperParser;
import org.elasticsearch.index.mapper.FieldMapper;
import org.elasticsearch.index.mapper.Mapper.BuilderContext;
import org.elasticsearch.index.mapper.MapperParsingException;
import org.elasticsearch.index.mapper.MapperService;
import org.elasticsearch.index.mapper.ParseContext.Document;
import org.elasticsearch.index.mapper.ParsedDocument;
import org.elasticsearch.index.mapper.core.StringFieldMapper;
@ -478,7 +479,8 @@ public class SimpleStringMappingTests extends ESSingleNodeTestCase {
.startObject("properties").startObject("field").field("type", "string").endObject().endObject()
.endObject().endObject().string();
DocumentMapper defaultMapper = indexService.mapperService().merge("type", new CompressedXContent(mapping), true, false);
MapperService mapperService = indexService.mapperService();
DocumentMapper defaultMapper = mapperService.merge("type", new CompressedXContent(mapping), true, false);
ParsedDocument doc = defaultMapper.parse("test", "type", "1", XContentFactory.jsonBuilder()
.startObject()
@ -492,7 +494,7 @@ public class SimpleStringMappingTests extends ESSingleNodeTestCase {
String updatedMapping = XContentFactory.jsonBuilder().startObject().startObject("type")
.startObject("properties").startObject("field").field("type", "string").startObject("norms").field("enabled", false).endObject()
.endObject().endObject().endObject().endObject().string();
defaultMapper.merge(parser.parse("type", new CompressedXContent(updatedMapping)).mapping(), false, false);
defaultMapper = mapperService.merge("type", new CompressedXContent(updatedMapping), false, false);
doc = defaultMapper.parse("test", "type", "1", XContentFactory.jsonBuilder()
.startObject()
@ -507,7 +509,7 @@ public class SimpleStringMappingTests extends ESSingleNodeTestCase {
.startObject("properties").startObject("field").field("type", "string").startObject("norms").field("enabled", true).endObject()
.endObject().endObject().endObject().endObject().string();
try {
defaultMapper.merge(parser.parse("type", new CompressedXContent(updatedMapping)).mapping(), true, false);
mapperService.merge("type", new CompressedXContent(updatedMapping), false, false);
fail();
} catch (IllegalArgumentException e) {
assertThat(e.getMessage(), containsString("different [omit_norms]"));

View File

@ -143,17 +143,16 @@ public class TimestampMappingTests extends ESSingleNodeTestCase {
String enabledMapping = XContentFactory.jsonBuilder().startObject().startObject("type")
.startObject("_timestamp").field("enabled", true).endObject()
.endObject().endObject().string();
DocumentMapperParser parser = createIndex("test").mapperService().documentMapperParser();
DocumentMapper enabledMapper = parser.parse("type", new CompressedXContent(enabledMapping));
MapperService mapperService = createIndex("test").mapperService();
DocumentMapper enabledMapper = mapperService.merge("type", new CompressedXContent(enabledMapping), true, false);
String disabledMapping = XContentFactory.jsonBuilder().startObject().startObject("type")
.startObject("_timestamp").field("enabled", false).endObject()
.endObject().endObject().string();
DocumentMapper disabledMapper = parser.parse("type", new CompressedXContent(disabledMapping));
DocumentMapper disabledMapper = mapperService.merge("type", new CompressedXContent(disabledMapping), false, false);
enabledMapper.merge(disabledMapper.mapping(), false, false);
assertThat(enabledMapper.timestampFieldMapper().enabled(), is(false));
assertThat(enabledMapper.timestampFieldMapper().enabled(), is(true));
assertThat(disabledMapper.timestampFieldMapper().enabled(), is(false));
}
// issue 3174
@ -504,16 +503,16 @@ public class TimestampMappingTests extends ESSingleNodeTestCase {
.startObject("_timestamp").field("enabled", randomBoolean()).startObject("fielddata").field("loading", "lazy").field("format", "doc_values").endObject().field("store", "yes").endObject()
.endObject().endObject().string();
Settings indexSettings = Settings.builder().put(IndexMetaData.SETTING_VERSION_CREATED, Version.V_1_4_2.id).build();
DocumentMapperParser parser = createIndex("test", indexSettings).mapperService().documentMapperParser();
MapperService mapperService = createIndex("test", indexSettings).mapperService();
DocumentMapper docMapper = parser.parse("type", new CompressedXContent(mapping));
DocumentMapper docMapper = mapperService.merge("type", new CompressedXContent(mapping), true, false);
assertThat(docMapper.timestampFieldMapper().fieldType().fieldDataType().getLoading(), equalTo(MappedFieldType.Loading.LAZY));
assertThat(docMapper.timestampFieldMapper().fieldType().fieldDataType().getFormat(indexSettings), equalTo("doc_values"));
mapping = XContentFactory.jsonBuilder().startObject().startObject("type")
.startObject("_timestamp").field("enabled", randomBoolean()).startObject("fielddata").field("loading", "eager").field("format", "array").endObject().field("store", "yes").endObject()
.endObject().endObject().string();
docMapper.merge(parser.parse("type", new CompressedXContent(mapping)).mapping(), false, false);
docMapper = mapperService.merge("type", new CompressedXContent(mapping), false, false);
assertThat(docMapper.timestampFieldMapper().fieldType().fieldDataType().getLoading(), equalTo(MappedFieldType.Loading.EAGER));
assertThat(docMapper.timestampFieldMapper().fieldType().fieldDataType().getFormat(indexSettings), equalTo("array"));
}
@ -571,8 +570,8 @@ public class TimestampMappingTests extends ESSingleNodeTestCase {
.startObject("fielddata").field("format", "array").endObject()
.field("store", "no")
.field("index", "no")
.field("path", "bar")
.field("default", "1970-01-02")
.field("path", "foo")
.field("default", "1970-01-01")
.endObject()
.endObject().endObject().string();
@ -584,6 +583,24 @@ public class TimestampMappingTests extends ESSingleNodeTestCase {
assertThat(e.getMessage(), containsString("mapper [_timestamp] has different [store] values"));
}
mapping = XContentFactory.jsonBuilder().startObject().startObject("type")
.startObject("_timestamp").field("enabled", false)
.startObject("fielddata").field("format", "array").endObject()
.field("store", "yes")
.field("index", "analyzed")
.field("path", "bar")
.field("default", "1970-01-02")
.endObject()
.endObject().endObject().string();
try {
mapperService.merge("type", new CompressedXContent(mapping), false, false);
fail();
} catch (IllegalArgumentException e) {
assertThat(e.getMessage(), containsString("Cannot update default in _timestamp value"));
assertThat(e.getMessage(), containsString("Cannot update path in _timestamp value"));
}
assertThat(docMapper.timestampFieldMapper().fieldType().fieldDataType().getLoading(), equalTo(MappedFieldType.Loading.LAZY));
assertTrue(docMapper.timestampFieldMapper().enabled());
@ -650,7 +667,7 @@ public class TimestampMappingTests extends ESSingleNodeTestCase {
public void testBackcompatMergePaths() throws Exception {
String[] possiblePathValues = {"some_path", "anotherPath", null};
DocumentMapperParser parser = createIndex("test", BWC_SETTINGS).mapperService().documentMapperParser();
MapperService mapperService = createIndex("test", BWC_SETTINGS).mapperService();
XContentBuilder mapping1 = XContentFactory.jsonBuilder().startObject()
.startObject("type")
.startObject("_timestamp");
@ -670,21 +687,17 @@ public class TimestampMappingTests extends ESSingleNodeTestCase {
mapping2.endObject()
.endObject().endObject();
assertConflict(mapping1.string(), mapping2.string(), parser, (path1 == path2 ? null : "Cannot update path in _timestamp value"));
assertConflict(mapperService, "type", mapping1.string(), mapping2.string(), (path1 == path2 ? null : "Cannot update path in _timestamp value"));
}
void assertConflict(String mapping1, String mapping2, DocumentMapperParser parser, String conflict) throws IOException {
DocumentMapper docMapper = parser.parse("type", new CompressedXContent(mapping1));
docMapper = parser.parse("type", docMapper.mappingSource());
if (conflict == null) {
docMapper.merge(parser.parse("type", new CompressedXContent(mapping2)).mapping(), true, false);
} else {
try {
docMapper.merge(parser.parse("type", new CompressedXContent(mapping2)).mapping(), true, false);
fail();
} catch (IllegalArgumentException e) {
assertThat(e.getMessage(), containsString(conflict));
}
void assertConflict(MapperService mapperService, String type, String mapping1, String mapping2, String conflict) throws IOException {
mapperService.merge("type", new CompressedXContent(mapping1), true, false);
try {
mapperService.merge("type", new CompressedXContent(mapping2), false, false);
assertNull(conflict);
} catch (IllegalArgumentException e) {
assertNotNull(conflict);
assertThat(e.getMessage(), containsString(conflict));
}
}

View File

@ -33,8 +33,8 @@ import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.index.IndexService;
import org.elasticsearch.index.mapper.DocumentMapper;
import org.elasticsearch.index.mapper.DocumentMapperParser;
import org.elasticsearch.index.mapper.MapperParsingException;
import org.elasticsearch.index.mapper.MapperService;
import org.elasticsearch.index.mapper.ParsedDocument;
import org.elasticsearch.index.mapper.SourceToParse;
import org.elasticsearch.index.mapper.internal.TTLFieldMapper;
@ -111,13 +111,12 @@ public class TTLMappingTests extends ESSingleNodeTestCase {
.startObject("properties").field("field").startObject().field("type", "string").endObject().endObject()
.endObject().endObject().string();
DocumentMapperParser parser = createIndex("test").mapperService().documentMapperParser();
DocumentMapper mapperWithoutTtl = parser.parse("type", new CompressedXContent(mappingWithoutTtl));
DocumentMapper mapperWithTtl = parser.parse("type", new CompressedXContent(mappingWithTtl));
MapperService mapperService = createIndex("test").mapperService();
DocumentMapper mapperWithoutTtl = mapperService.merge("type", new CompressedXContent(mappingWithoutTtl), true, false);
DocumentMapper mapperWithTtl = mapperService.merge("type", new CompressedXContent(mappingWithTtl), false, false);
mapperWithoutTtl.merge(mapperWithTtl.mapping(), false, false);
assertThat(mapperWithoutTtl.TTLFieldMapper().enabled(), equalTo(true));
assertThat(mapperWithoutTtl.TTLFieldMapper().enabled(), equalTo(false));
assertThat(mapperWithTtl.TTLFieldMapper().enabled(), equalTo(true));
}
public void testThatChangingTTLKeepsMapperEnabled() throws Exception {
@ -135,24 +134,22 @@ public class TTLMappingTests extends ESSingleNodeTestCase {
.startObject("properties").field("field").startObject().field("type", "string").endObject().endObject()
.endObject().endObject().string();
DocumentMapperParser parser = createIndex("test").mapperService().documentMapperParser();
DocumentMapper initialMapper = parser.parse("type", new CompressedXContent(mappingWithTtl));
DocumentMapper updatedMapper = parser.parse("type", new CompressedXContent(updatedMapping));
initialMapper.merge(updatedMapper.mapping(), true, false);
MapperService mapperService = createIndex("test").mapperService();
DocumentMapper initialMapper = mapperService.merge("type", new CompressedXContent(mappingWithTtl), true, false);
DocumentMapper updatedMapper = mapperService.merge("type", new CompressedXContent(updatedMapping), false, false);
assertThat(initialMapper.TTLFieldMapper().enabled(), equalTo(true));
assertThat(updatedMapper.TTLFieldMapper().enabled(), equalTo(true));
}
public void testThatDisablingTTLReportsConflict() throws Exception {
String mappingWithTtl = getMappingWithTtlEnabled().string();
String mappingWithTtlDisabled = getMappingWithTtlDisabled().string();
DocumentMapperParser parser = createIndex("test").mapperService().documentMapperParser();
DocumentMapper initialMapper = parser.parse("type", new CompressedXContent(mappingWithTtl));
DocumentMapper updatedMapper = parser.parse("type", new CompressedXContent(mappingWithTtlDisabled));
MapperService mapperService = createIndex("test").mapperService();
DocumentMapper initialMapper = mapperService.merge("type", new CompressedXContent(mappingWithTtl), true, false);
try {
initialMapper.merge(updatedMapper.mapping(), true, false);
mapperService.merge("type", new CompressedXContent(mappingWithTtlDisabled), false, false);
fail();
} catch (IllegalArgumentException e) {
// expected
@ -190,20 +187,20 @@ public class TTLMappingTests extends ESSingleNodeTestCase {
public void testNoConflictIfNothingSetAndDisabledLater() throws Exception {
IndexService indexService = createIndex("testindex", Settings.settingsBuilder().build(), "type");
XContentBuilder mappingWithTtlDisabled = getMappingWithTtlDisabled("7d");
indexService.mapperService().documentMapper("type").merge(indexService.mapperService().parse("type", new CompressedXContent(mappingWithTtlDisabled.string()), true).mapping(), randomBoolean(), false);
indexService.mapperService().merge("type", new CompressedXContent(mappingWithTtlDisabled.string()), randomBoolean(), false);
}
public void testNoConflictIfNothingSetAndEnabledLater() throws Exception {
IndexService indexService = createIndex("testindex", Settings.settingsBuilder().build(), "type");
XContentBuilder mappingWithTtlEnabled = getMappingWithTtlEnabled("7d");
indexService.mapperService().documentMapper("type").merge(indexService.mapperService().parse("type", new CompressedXContent(mappingWithTtlEnabled.string()), true).mapping(), randomBoolean(), false);
indexService.mapperService().merge("type", new CompressedXContent(mappingWithTtlEnabled.string()), randomBoolean(), false);
}
public void testMergeWithOnlyDefaultSet() throws Exception {
XContentBuilder mappingWithTtlEnabled = getMappingWithTtlEnabled("7d");
IndexService indexService = createIndex("testindex", Settings.settingsBuilder().build(), "type", mappingWithTtlEnabled);
XContentBuilder mappingWithOnlyDefaultSet = getMappingWithOnlyTtlDefaultSet("6m");
indexService.mapperService().documentMapper("type").merge(indexService.mapperService().parse("type", new CompressedXContent(mappingWithOnlyDefaultSet.string()), true).mapping(), false, false);
indexService.mapperService().merge("type", new CompressedXContent(mappingWithOnlyDefaultSet.string()), false, false);
CompressedXContent mappingAfterMerge = indexService.mapperService().documentMapper("type").mappingSource();
assertThat(mappingAfterMerge, equalTo(new CompressedXContent("{\"type\":{\"_ttl\":{\"enabled\":true,\"default\":360000},\"properties\":{\"field\":{\"type\":\"string\"}}}}")));
}
@ -214,65 +211,11 @@ public class TTLMappingTests extends ESSingleNodeTestCase {
CompressedXContent mappingAfterCreation = indexService.mapperService().documentMapper("type").mappingSource();
assertThat(mappingAfterCreation, equalTo(new CompressedXContent("{\"type\":{\"_ttl\":{\"enabled\":false},\"properties\":{\"field\":{\"type\":\"string\"}}}}")));
XContentBuilder mappingWithOnlyDefaultSet = getMappingWithOnlyTtlDefaultSet("6m");
indexService.mapperService().documentMapper("type").merge(indexService.mapperService().parse("type", new CompressedXContent(mappingWithOnlyDefaultSet.string()), true).mapping(), false, false);
indexService.mapperService().merge("type", new CompressedXContent(mappingWithOnlyDefaultSet.string()), false, false);
CompressedXContent mappingAfterMerge = indexService.mapperService().documentMapper("type").mappingSource();
assertThat(mappingAfterMerge, equalTo(new CompressedXContent("{\"type\":{\"_ttl\":{\"enabled\":false},\"properties\":{\"field\":{\"type\":\"string\"}}}}")));
}
public void testThatSimulatedMergingLeavesStateUntouched() throws Exception {
//check if default ttl changed when simulate set to true
XContentBuilder mappingWithTtl = getMappingWithTtlEnabled("6d");
IndexService indexService = createIndex("testindex", Settings.settingsBuilder().build(), "type", mappingWithTtl);
CompressedXContent mappingBeforeMerge = indexService.mapperService().documentMapper("type").mappingSource();
XContentBuilder mappingWithTtlDifferentDefault = getMappingWithTtlEnabled("7d");
indexService.mapperService().documentMapper("type").merge(indexService.mapperService().parse("type", new CompressedXContent(mappingWithTtlDifferentDefault.string()), true).mapping(), true, false);
// make sure simulate flag actually worked - no mappings applied
CompressedXContent mappingAfterMerge = indexService.mapperService().documentMapper("type").mappingSource();
assertThat(mappingAfterMerge, equalTo(mappingBeforeMerge));
client().admin().indices().prepareDelete("testindex").get();
// check if enabled changed when simulate set to true
XContentBuilder mappingWithoutTtl = getMappingWithTtlDisabled();
indexService = createIndex("testindex", Settings.settingsBuilder().build(), "type", mappingWithoutTtl);
mappingBeforeMerge = indexService.mapperService().documentMapper("type").mappingSource();
XContentBuilder mappingWithTtlEnabled = getMappingWithTtlEnabled();
indexService.mapperService().documentMapper("type").merge(indexService.mapperService().parse("type", new CompressedXContent(mappingWithTtlEnabled.string()), true).mapping(), true, false);
// make sure simulate flag actually worked - no mappings applied
mappingAfterMerge = indexService.mapperService().documentMapper("type").mappingSource();
assertThat(mappingAfterMerge, equalTo(mappingBeforeMerge));
client().admin().indices().prepareDelete("testindex").get();
// check if enabled changed when simulate set to true
mappingWithoutTtl = getMappingWithTtlDisabled("6d");
indexService = createIndex("testindex", Settings.settingsBuilder().build(), "type", mappingWithoutTtl);
mappingBeforeMerge = indexService.mapperService().documentMapper("type").mappingSource();
mappingWithTtlEnabled = getMappingWithTtlEnabled("7d");
indexService.mapperService().documentMapper("type").merge(indexService.mapperService().parse("type", new CompressedXContent(mappingWithTtlEnabled.string()), true).mapping(), true, false);
// make sure simulate flag actually worked - no mappings applied
mappingAfterMerge = indexService.mapperService().documentMapper("type").mappingSource();
assertThat(mappingAfterMerge, equalTo(mappingBeforeMerge));
client().admin().indices().prepareDelete("testindex").get();
// check if switching simulate flag off works
mappingWithoutTtl = getMappingWithTtlDisabled("6d");
indexService = createIndex("testindex", Settings.settingsBuilder().build(), "type", mappingWithoutTtl);
mappingWithTtlEnabled = getMappingWithTtlEnabled("7d");
indexService.mapperService().documentMapper("type").merge(indexService.mapperService().parse("type", new CompressedXContent(mappingWithTtlEnabled.string()), true).mapping(), false, false);
// make sure simulate flag actually worked - mappings applied
mappingAfterMerge = indexService.mapperService().documentMapper("type").mappingSource();
assertThat(mappingAfterMerge, equalTo(new CompressedXContent("{\"type\":{\"_ttl\":{\"enabled\":true,\"default\":604800000},\"properties\":{\"field\":{\"type\":\"string\"}}}}")));
client().admin().indices().prepareDelete("testindex").get();
// check if switching simulate flag off works if nothing was applied in the beginning
indexService = createIndex("testindex", Settings.settingsBuilder().build(), "type");
mappingWithTtlEnabled = getMappingWithTtlEnabled("7d");
indexService.mapperService().documentMapper("type").merge(indexService.mapperService().parse("type", new CompressedXContent(mappingWithTtlEnabled.string()), true).mapping(), false, false);
// make sure simulate flag actually worked - mappings applied
mappingAfterMerge = indexService.mapperService().documentMapper("type").mappingSource();
assertThat(mappingAfterMerge, equalTo(new CompressedXContent("{\"type\":{\"_ttl\":{\"enabled\":true,\"default\":604800000},\"properties\":{\"field\":{\"type\":\"string\"}}}}")));
}
public void testIncludeInObjectBackcompat() throws Exception {
String mapping = XContentFactory.jsonBuilder().startObject().startObject("type")
.startObject("_ttl").field("enabled", true).endObject()

View File

@ -76,7 +76,7 @@ public class UpdateMappingTests extends ESSingleNodeTestCase {
private void testNoConflictWhileMergingAndMappingChanged(XContentBuilder mapping, XContentBuilder mappingUpdate, XContentBuilder expectedMapping) throws IOException {
IndexService indexService = createIndex("test", Settings.settingsBuilder().build(), "type", mapping);
// simulate like in MetaDataMappingService#putMapping
indexService.mapperService().documentMapper("type").merge(indexService.mapperService().parse("type", new CompressedXContent(mappingUpdate.bytes()), true).mapping(), false, false);
indexService.mapperService().merge("type", new CompressedXContent(mappingUpdate.bytes()), false, false);
// make sure mappings applied
CompressedXContent mappingAfterUpdate = indexService.mapperService().documentMapper("type").mappingSource();
assertThat(mappingAfterUpdate.toString(), equalTo(expectedMapping.string()));
@ -99,7 +99,7 @@ public class UpdateMappingTests extends ESSingleNodeTestCase {
CompressedXContent mappingBeforeUpdate = indexService.mapperService().documentMapper("type").mappingSource();
// simulate like in MetaDataMappingService#putMapping
try {
indexService.mapperService().documentMapper("type").merge(indexService.mapperService().parse("type", new CompressedXContent(mappingUpdate.bytes()), true).mapping(), true, false);
indexService.mapperService().merge("type", new CompressedXContent(mappingUpdate.bytes()), true, false);
fail();
} catch (IllegalArgumentException e) {
// expected
@ -123,14 +123,14 @@ public class UpdateMappingTests extends ESSingleNodeTestCase {
mapperService.merge("type", new CompressedXContent(update.string()), false, false);
fail();
} catch (IllegalArgumentException e) {
assertThat(e.getMessage(), containsString("mapper [foo] cannot be changed from type [long] to [double]"));
assertThat(e.getMessage(), containsString("mapper [foo] of different type, current_type [long], merged_type [double]"));
}
try {
mapperService.merge("type", new CompressedXContent(update.string()), false, false);
fail();
} catch (IllegalArgumentException e) {
assertThat(e.getMessage(), containsString("mapper [foo] cannot be changed from type [long] to [double]"));
assertThat(e.getMessage(), containsString("mapper [foo] of different type, current_type [long], merged_type [double]"));
}
assertTrue(mapperService.documentMapper("type").mapping().root().getMapper("foo") instanceof LongFieldMapper);

View File

@ -149,7 +149,7 @@ public class UpdateMappingIntegrationIT extends ESIntegTestCase {
.setSource("{\"type\":{\"properties\":{\"body\":{\"type\":\"integer\"}}}}").execute().actionGet();
fail("Expected MergeMappingException");
} catch (IllegalArgumentException e) {
assertThat(e.getMessage(), containsString("mapper [body] cannot be changed from type [string] to [int]"));
assertThat(e.getMessage(), containsString("mapper [body] of different type, current_type [string], merged_type [integer]"));
}
}

View File

@ -2,7 +2,7 @@
"type": {
"_all": {
"store": false,
"enabled": false,
"enabled": true,
"store_term_vectors": false,
"store_term_vector_offsets": false,
"store_term_vector_positions": false,

View File

@ -134,14 +134,13 @@ public class SizeMappingTests extends ESSingleNodeTestCase {
String enabledMapping = XContentFactory.jsonBuilder().startObject().startObject("type")
.startObject("_size").field("enabled", true).endObject()
.endObject().endObject().string();
DocumentMapper enabledMapper = parser.parse("type", new CompressedXContent(enabledMapping));
DocumentMapper enabledMapper = indexService.mapperService().merge("type", new CompressedXContent(enabledMapping), true, false);
String disabledMapping = XContentFactory.jsonBuilder().startObject().startObject("type")
.startObject("_size").field("enabled", false).endObject()
.endObject().endObject().string();
DocumentMapper disabledMapper = parser.parse("type", new CompressedXContent(disabledMapping));
DocumentMapper disabledMapper = indexService.mapperService().merge("type", new CompressedXContent(disabledMapping), false, false);
enabledMapper.merge(disabledMapper.mapping(), false, false);
assertThat(enabledMapper.metadataMapper(SizeFieldMapper.class).enabled(), is(false));
assertThat(disabledMapper.metadataMapper(SizeFieldMapper.class).enabled(), is(false));
}
}