Skip to content

Commit 05bf0ea

Browse files
authored
Remove DocumentMapperForType (#72616)
DocumentMapperForType is used to create a document mapper when no mappings exists for an index and we are indexing the first document in it. This is only to cover for the edge case of empty docs, without any fields to dynamically map, being indexed, as we need to ensure that any index with at least one document in it has some mappings. We can replace using DocumentMapperForType with the same logic that MapperService#documentMapperWithAutoCreate includes. This also helps clean up the only case where we create a DocumentMapper from its public constructor, which can be removed and replaced by a more targeted static method.
1 parent 658a75b commit 05bf0ea

File tree

6 files changed

+38
-89
lines changed

6 files changed

+38
-89
lines changed

server/src/main/java/org/elasticsearch/index/mapper/DocumentMapper.java

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,20 +12,21 @@
1212
import org.elasticsearch.index.IndexSettings;
1313
import org.elasticsearch.index.analysis.IndexAnalyzers;
1414

15-
import java.util.Collections;
16-
1715
public class DocumentMapper {
1816
private final String type;
1917
private final CompressedXContent mappingSource;
2018
private final MappingLookup mappingLookup;
2119

22-
public DocumentMapper(RootObjectMapper.Builder rootBuilder, MapperService mapperService) {
23-
this(mapperService.getIndexSettings(), mapperService.getIndexAnalyzers(), mapperService.documentParser(),
24-
new Mapping(
25-
rootBuilder.build(new ContentPath(1)),
26-
mapperService.getMetadataMappers(rootBuilder.name()).values().toArray(new MetadataFieldMapper[0]),
27-
Collections.emptyMap()
28-
));
20+
/**
21+
* Create a new {@link DocumentMapper} that holds empty mappings.
22+
* @param type the type of the mappings to create
23+
* @param mapperService the mapper service that holds the needed components
24+
* @return the newly created document mapper
25+
*/
26+
public static DocumentMapper createEmpty(String type, MapperService mapperService) {
27+
Mapping mapping = mapperService.parseMapping(type, null, true);
28+
return new DocumentMapper(
29+
mapperService.getIndexSettings(), mapperService.getIndexAnalyzers(), mapperService.documentParser(), mapping);
2930
}
3031

3132
DocumentMapper(IndexSettings indexSettings,

server/src/main/java/org/elasticsearch/index/mapper/DocumentMapperForType.java

Lines changed: 0 additions & 27 deletions
This file was deleted.

server/src/main/java/org/elasticsearch/index/mapper/MapperService.java

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -582,20 +582,6 @@ public String resolveDocumentType(String type) {
582582
return type;
583583
}
584584

585-
/**
586-
* Returns the document mapper created, including a mapping update if the
587-
* type has been dynamically created.
588-
*/
589-
public DocumentMapperForType documentMapperWithAutoCreate(String type) {
590-
DocumentMapper mapper = documentMapper(type);
591-
if (mapper != null) {
592-
return new DocumentMapperForType(mapper, null);
593-
}
594-
Mapping mapping = parseMapping(type, null, true);
595-
mapper = new DocumentMapper(indexSettings, indexAnalyzers, documentParser, mapping);
596-
return new DocumentMapperForType(mapper, mapper.mapping());
597-
}
598-
599585
/**
600586
* Given the full name of a field, returns its {@link MappedFieldType}.
601587
*/

server/src/main/java/org/elasticsearch/index/shard/IndexShard.java

Lines changed: 23 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@
9999
import org.elasticsearch.index.get.GetStats;
100100
import org.elasticsearch.index.get.ShardGetService;
101101
import org.elasticsearch.index.mapper.DateFieldMapper;
102-
import org.elasticsearch.index.mapper.DocumentMapperForType;
102+
import org.elasticsearch.index.mapper.DocumentMapper;
103103
import org.elasticsearch.index.mapper.IdFieldMapper;
104104
import org.elasticsearch.index.mapper.MappedFieldType;
105105
import org.elasticsearch.index.mapper.MapperParsingException;
@@ -830,7 +830,7 @@ private Engine.IndexResult applyIndexOperation(Engine engine, long seqNo, long o
830830
sourceWithResolvedType = new SourceToParse(sourceToParse.index(), resolvedType, sourceToParse.id(),
831831
sourceToParse.source(), sourceToParse.getXContentType(), sourceToParse.routing(), sourceToParse.dynamicTemplates());
832832
}
833-
operation = prepareIndex(docMapper(resolvedType), sourceWithResolvedType,
833+
operation = prepareIndex(mapperService, resolvedType, sourceWithResolvedType,
834834
seqNo, opPrimaryTerm, version, versionType, origin, autoGeneratedTimeStamp, isRetry, ifSeqNo, ifPrimaryTerm);
835835
Mapping update = operation.parsedDoc().dynamicMappingsUpdate();
836836
if (update != null) {
@@ -848,16 +848,24 @@ private Engine.IndexResult applyIndexOperation(Engine engine, long seqNo, long o
848848
return index(engine, operation);
849849
}
850850

851-
public static Engine.Index prepareIndex(DocumentMapperForType docMapper, SourceToParse source, long seqNo,
851+
public static Engine.Index prepareIndex(MapperService mapperService, String type, SourceToParse source, long seqNo,
852852
long primaryTerm, long version, VersionType versionType, Engine.Operation.Origin origin,
853853
long autoGeneratedIdTimestamp, boolean isRetry,
854854
long ifSeqNo, long ifPrimaryTerm) {
855855
long startTime = System.nanoTime();
856856
assert source.dynamicTemplates().isEmpty() || origin == Engine.Operation.Origin.PRIMARY :
857857
"dynamic_templates parameter can only be associated with primary operations";
858-
ParsedDocument doc = docMapper.getDocumentMapper().parse(source);
859-
if (docMapper.getMapping() != null) {
860-
doc.addDynamicMappingsUpdate(docMapper.getMapping());
858+
DocumentMapper documentMapper = mapperService.documentMapper(type);
859+
Mapping mapping = null;
860+
if (documentMapper == null) {
861+
documentMapper = DocumentMapper.createEmpty(type, mapperService);
862+
mapping = documentMapper.mapping();
863+
}
864+
ParsedDocument doc = documentMapper.parse(source);
865+
if (mapping != null) {
866+
//If we are indexing but there is no mapping we create one. This is to ensure that whenever at least a document is indexed
867+
// some mappings do exist. It covers for the case of indexing an empty doc (`{}`).
868+
doc.addDynamicMappingsUpdate(mapping);
861869
}
862870
Term uid = new Term(IdFieldMapper.NAME, Uid.encodeId(doc.id()));
863871
return new Engine.Index(uid, doc, seqNo, primaryTerm, version, versionType, origin, startTime, autoGeneratedIdTimestamp, isRetry,
@@ -955,20 +963,21 @@ private Engine.DeleteResult applyDeleteOperation(Engine engine, long seqNo, long
955963
// In order to work around this issue, we make deletions create types. This way, we
956964
// fail if index and delete operations do not use the same type.
957965
// TODO: clean this up when types are gone
966+
String resolvedType = mapperService.resolveDocumentType(type);
958967
try {
959-
Mapping update = docMapper(type).getMapping();
960-
if (update != null) {
961-
return new Engine.DeleteResult(update);
968+
DocumentMapper documentMapper = mapperService.documentMapper(resolvedType);
969+
if (documentMapper == null) {
970+
documentMapper = DocumentMapper.createEmpty(resolvedType, mapperService);
971+
return new Engine.DeleteResult(documentMapper.mapping());
962972
}
963973
} catch (MapperParsingException | IllegalArgumentException | TypeMissingException e) {
964974
return new Engine.DeleteResult(e, version, getOperationPrimaryTerm(), seqNo, false);
965975
}
966-
if (mapperService.resolveDocumentType(type).equals(mapperService.mappingLookup().getType()) == false) {
976+
if (resolvedType.equals(mapperService.mappingLookup().getType()) == false) {
967977
// We should never get there due to the fact that we generate mapping updates on deletes,
968978
// but we still prefer to have a hard exception here as we would otherwise delete a
969979
// document in the wrong type.
970-
throw new IllegalStateException("Deleting document from type [" +
971-
mapperService.resolveDocumentType(type) + "] while current type is [" +
980+
throw new IllegalStateException("Deleting document from type [" + resolvedType + "] while current type is [" +
972981
mapperService.mappingLookup().getType() + "]");
973982
}
974983
final Term uid = new Term(IdFieldMapper.NAME, Uid.encodeId(id));
@@ -978,11 +987,9 @@ private Engine.DeleteResult applyDeleteOperation(Engine engine, long seqNo, long
978987
}
979988

980989
private Engine.Delete prepareDelete(String type, String id, Term uid, long seqNo, long primaryTerm, long version,
981-
VersionType versionType, Engine.Operation.Origin origin,
982-
long ifSeqNo, long ifPrimaryTerm) {
990+
VersionType versionType, Engine.Operation.Origin origin, long ifSeqNo, long ifPrimaryTerm) {
983991
long startTime = System.nanoTime();
984-
return new Engine.Delete(mapperService.resolveDocumentType(type), id, uid, seqNo, primaryTerm, version, versionType,
985-
origin, startTime, ifSeqNo, ifPrimaryTerm);
992+
return new Engine.Delete(type, id, uid, seqNo, primaryTerm, version, versionType, origin, startTime, ifSeqNo, ifPrimaryTerm);
986993
}
987994

988995
private Engine.DeleteResult delete(Engine engine, Engine.Delete delete) throws IOException {
@@ -2920,11 +2927,6 @@ protected Analyzer getWrappedAnalyzer(String fieldName) {
29202927
};
29212928
}
29222929

2923-
private DocumentMapperForType docMapper(String type) {
2924-
return mapperService.documentMapperWithAutoCreate(
2925-
mapperService.resolveDocumentType(type));
2926-
}
2927-
29282930
private EngineConfig newEngineConfig(LongSupplier globalCheckpointSupplier) {
29292931
final Sort indexSort = indexSortSupplier.get();
29302932
final Engine.Warmer warmer = reader -> {

server/src/main/java/org/elasticsearch/index/termvectors/TermVectorsService.java

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
import org.elasticsearch.common.xcontent.support.XContentMapValues;
3232
import org.elasticsearch.index.engine.Engine;
3333
import org.elasticsearch.index.get.GetResult;
34-
import org.elasticsearch.index.mapper.DocumentMapperForType;
34+
import org.elasticsearch.index.mapper.DocumentMapper;
3535
import org.elasticsearch.index.mapper.IdFieldMapper;
3636
import org.elasticsearch.index.mapper.MappedFieldType;
3737
import org.elasticsearch.index.mapper.MapperService;
@@ -329,13 +329,9 @@ public static String[] getValues(IndexableField[] fields) {
329329
private static ParsedDocument parseDocument(IndexShard indexShard, String index, String type, BytesReference doc,
330330
XContentType xContentType, String routing) {
331331
MapperService mapperService = indexShard.mapperService();
332-
DocumentMapperForType docMapper = mapperService.documentMapperWithAutoCreate(type);
333-
ParsedDocument parsedDocument = docMapper.getDocumentMapper().parse(
334-
new SourceToParse(index, type, "_id_for_tv_api", doc, xContentType, routing, Collections.emptyMap()));
335-
if (docMapper.getMapping() != null) {
336-
parsedDocument.addDynamicMappingsUpdate(docMapper.getMapping());
337-
}
338-
return parsedDocument;
332+
DocumentMapper documentMapper = mapperService.documentMapper(mapperService.resolveDocumentType(type));
333+
//TODO this throws NPE if there are no mappings yet, we have the same problem in PainlessExecutionAction
334+
return documentMapper.parse(new SourceToParse(index, type, "_id_for_tv_api", doc, xContentType, routing, Collections.emptyMap()));
339335
}
340336

341337
private static Fields mergeFields(Fields fields1, Fields fields2) throws IOException {

test/framework/src/main/java/org/elasticsearch/index/engine/TranslogHandler.java

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
package org.elasticsearch.index.engine;
1010

1111
import org.apache.lucene.analysis.standard.StandardAnalyzer;
12-
import org.elasticsearch.Version;
1312
import org.elasticsearch.common.xcontent.NamedXContentRegistry;
1413
import org.elasticsearch.common.xcontent.XContentHelper;
1514
import org.elasticsearch.index.IndexSettings;
@@ -18,12 +17,9 @@
1817
import org.elasticsearch.index.analysis.AnalyzerScope;
1918
import org.elasticsearch.index.analysis.IndexAnalyzers;
2019
import org.elasticsearch.index.analysis.NamedAnalyzer;
21-
import org.elasticsearch.index.mapper.DocumentMapper;
22-
import org.elasticsearch.index.mapper.DocumentMapperForType;
2320
import org.elasticsearch.index.mapper.MapperRegistry;
2421
import org.elasticsearch.index.mapper.MapperService;
2522
import org.elasticsearch.index.mapper.Mapping;
26-
import org.elasticsearch.index.mapper.RootObjectMapper;
2723
import org.elasticsearch.index.mapper.SourceToParse;
2824
import org.elasticsearch.index.seqno.SequenceNumbers;
2925
import org.elasticsearch.index.shard.IndexShard;
@@ -62,11 +58,6 @@ public TranslogHandler(NamedXContentRegistry xContentRegistry, IndexSettings ind
6258
() -> null, () -> false, null);
6359
}
6460

65-
private DocumentMapperForType docMapper(String type) {
66-
RootObjectMapper.Builder rootBuilder = new RootObjectMapper.Builder(type, Version.CURRENT);
67-
return new DocumentMapperForType(new DocumentMapper(rootBuilder, mapperService), mappingUpdate);
68-
}
69-
7061
private void applyOperation(Engine engine, Engine.Operation operation) throws IOException {
7162
switch (operation.operationType()) {
7263
case INDEX:
@@ -116,7 +107,7 @@ public Engine.Operation convertToEngineOp(Translog.Operation operation, Engine.O
116107
case INDEX:
117108
final Translog.Index index = (Translog.Index) operation;
118109
final String indexName = mapperService.index().getName();
119-
final Engine.Index engineIndex = IndexShard.prepareIndex(docMapper(index.type()),
110+
final Engine.Index engineIndex = IndexShard.prepareIndex(mapperService, index.type(),
120111
new SourceToParse(indexName, index.type(), index.id(), index.source(), XContentHelper.xContentType(index.source()),
121112
index.routing(), Collections.emptyMap()), index.seqNo(), index.primaryTerm(), index.version(), versionType, origin,
122113
index.getAutoGeneratedIdTimestamp(), true, SequenceNumbers.UNASSIGNED_SEQ_NO, SequenceNumbers.UNASSIGNED_PRIMARY_TERM);

0 commit comments

Comments
 (0)