Merge pull request #15539 from jpountz/fix/immutable_document_mapper
Make mapping updates more robust.
This commit is contained in:
commit
a2072fe927
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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}.
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -216,7 +216,7 @@ public class FieldNamesFieldMapper extends MetadataFieldMapper {
|
|||
FieldNamesFieldType newFieldType = fieldType().clone();
|
||||
newFieldType.setEnabled(false);
|
||||
newFieldType.freeze();
|
||||
fieldTypeRef.set(newFieldType);
|
||||
this.fieldType = newFieldType;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
|
|
|
@ -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"));
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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)));
|
||||
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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"));
|
||||
|
|
|
@ -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());
|
||||
|
||||
|
|
|
@ -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));
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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]"));
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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]"));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue