Skip to content

Commit 1f76e32

Browse files
committed
Computing full effective mappings for data stream mapping APIs
1 parent ddc1df5 commit 1f76e32

File tree

10 files changed

+206
-28
lines changed

10 files changed

+206
-28
lines changed

modules/data-streams/src/main/java/org/elasticsearch/datastreams/action/TransportGetDataStreamMappingsAction.java

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,12 @@
2222
import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver;
2323
import org.elasticsearch.cluster.project.ProjectResolver;
2424
import org.elasticsearch.cluster.service.ClusterService;
25+
import org.elasticsearch.indices.IndicesService;
2526
import org.elasticsearch.injection.guice.Inject;
2627
import org.elasticsearch.tasks.Task;
2728
import org.elasticsearch.threadpool.ThreadPool;
2829
import org.elasticsearch.transport.TransportService;
30+
import org.elasticsearch.xcontent.NamedXContentRegistry;
2931

3032
import java.util.ArrayList;
3133
import java.util.List;
@@ -35,6 +37,8 @@ public class TransportGetDataStreamMappingsAction extends TransportLocalProjectM
3537
GetDataStreamMappingsAction.Request,
3638
GetDataStreamMappingsAction.Response> {
3739
private final IndexNameExpressionResolver indexNameExpressionResolver;
40+
private final NamedXContentRegistry xContentRegistry;
41+
private final IndicesService indicesService;
3842

3943
@Inject
4044
public TransportGetDataStreamMappingsAction(
@@ -43,7 +47,9 @@ public TransportGetDataStreamMappingsAction(
4347
ThreadPool threadPool,
4448
ActionFilters actionFilters,
4549
ProjectResolver projectResolver,
46-
IndexNameExpressionResolver indexNameExpressionResolver
50+
IndexNameExpressionResolver indexNameExpressionResolver,
51+
NamedXContentRegistry xContentRegistry,
52+
IndicesService indicesService
4753
) {
4854
super(
4955
GetSettingsAction.NAME,
@@ -54,6 +60,8 @@ public TransportGetDataStreamMappingsAction(
5460
projectResolver
5561
);
5662
this.indexNameExpressionResolver = indexNameExpressionResolver;
63+
this.xContentRegistry = xContentRegistry;
64+
this.indicesService = indicesService;
5765
}
5866

5967
@Override
@@ -81,7 +89,7 @@ protected void localClusterStateOperation(
8189
new GetDataStreamMappingsAction.DataStreamMappingsResponse(
8290
dataStreamName,
8391
dataStream.getMappings(),
84-
dataStream.getEffectiveMappings(project.metadata())
92+
dataStream.getEffectiveMappings(project.metadata(), xContentRegistry, indicesService)
8593
)
8694
);
8795
}

modules/data-streams/src/main/java/org/elasticsearch/datastreams/action/TransportUpdateDataStreamMappingsAction.java

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,14 @@
2929
import org.elasticsearch.common.util.concurrent.EsExecutors;
3030
import org.elasticsearch.core.TimeValue;
3131
import org.elasticsearch.index.mapper.Mapping;
32+
import org.elasticsearch.indices.IndicesService;
3233
import org.elasticsearch.indices.SystemIndices;
3334
import org.elasticsearch.injection.guice.Inject;
3435
import org.elasticsearch.tasks.Task;
3536
import org.elasticsearch.threadpool.ThreadPool;
3637
import org.elasticsearch.transport.TransportService;
38+
import org.elasticsearch.xcontent.NamedXContentRegistry;
3739

38-
import java.io.IOException;
3940
import java.util.ArrayList;
4041
import java.util.List;
4142

@@ -47,6 +48,8 @@ public class TransportUpdateDataStreamMappingsAction extends TransportMasterNode
4748
private final IndexNameExpressionResolver indexNameExpressionResolver;
4849
private final SystemIndices systemIndices;
4950
private final ProjectResolver projectResolver;
51+
private final NamedXContentRegistry xContentRegistry;
52+
private final IndicesService indicesService;
5053

5154
@Inject
5255
public TransportUpdateDataStreamMappingsAction(
@@ -57,7 +60,9 @@ public TransportUpdateDataStreamMappingsAction(
5760
ProjectResolver projectResolver,
5861
MetadataDataStreamsService metadataDataStreamsService,
5962
IndexNameExpressionResolver indexNameExpressionResolver,
60-
SystemIndices systemIndices
63+
SystemIndices systemIndices,
64+
NamedXContentRegistry xContentRegistry,
65+
IndicesService indicesService
6166
) {
6267
super(
6368
UpdateDataStreamMappingsAction.NAME,
@@ -73,6 +78,8 @@ public TransportUpdateDataStreamMappingsAction(
7378
this.metadataDataStreamsService = metadataDataStreamsService;
7479
this.indexNameExpressionResolver = indexNameExpressionResolver;
7580
this.systemIndices = systemIndices;
81+
this.xContentRegistry = xContentRegistry;
82+
this.indicesService = indicesService;
7683
}
7784

7885
@Override
@@ -163,10 +170,14 @@ private void updateSingleDataStream(
163170
true,
164171
null,
165172
mappingsOverrides,
166-
dataStream.getEffectiveMappings(clusterService.state().metadata().getProject(projectId))
173+
dataStream.getEffectiveMappings(
174+
clusterService.state().metadata().getProject(projectId),
175+
xContentRegistry,
176+
indicesService
177+
)
167178
)
168179
);
169-
} catch (IOException e) {
180+
} catch (Exception e) {
170181
dataStreamMappingsResponseActionListener.onResponse(
171182
new UpdateDataStreamMappingsAction.DataStreamMappingsResponse(
172183
dataStreamName,

modules/data-streams/src/yamlRestTest/resources/rest-api-spec/test/data_stream/250_data_stream_mappings.yml

Lines changed: 112 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ setup:
3737
name: my-data-stream-1
3838
- match: { data_streams.0.name: my-data-stream-1 }
3939
- match: { data_streams.0.mappings: {} }
40-
- length: { data_streams.0.effective_mappings.properties: 1 }
40+
- length: { data_streams.0.effective_mappings.properties: 2 }
4141

4242
- do:
4343
indices.get_data_stream:
@@ -74,7 +74,7 @@ setup:
7474
indices.get_data_stream_mappings:
7575
name: my-data-stream-1
7676
- match: { data_streams.0.name: my-data-stream-1 }
77-
- length: { data_streams.0.effective_mappings.properties: 2 }
77+
- length: { data_streams.0.effective_mappings.properties: 3 }
7878
- match: { data_streams.0.mappings.properties.name.type: "keyword" }
7979
- match: { data_streams.0.effective_mappings.properties.name.type: "keyword" }
8080

@@ -92,3 +92,113 @@ setup:
9292
index: my-data-stream-1
9393
- match: { .$oldIndexName.mappings.properties.name: null }
9494
- match: { .$newIndexName.mappings.properties.name.type: "keyword" }
95+
96+
---
97+
"Test mappings component templates only":
98+
- requires:
99+
cluster_features: [ "logs_stream" ]
100+
reason: requires setting 'logs_stream' to get or set data stream settings
101+
102+
- do:
103+
cluster.put_component_template:
104+
name: mappings-template
105+
body:
106+
template:
107+
mappings:
108+
properties:
109+
field1:
110+
type: keyword
111+
field2:
112+
type: keyword
113+
114+
- do:
115+
allowed_warnings:
116+
- "index template [my-component-only-template] has index patterns [my-component-only-data-stream-*] matching patterns from existing older templates [global] with patterns (global => [*]); this template [my-component-only-template] will take precedence during new index creation"
117+
indices.put_index_template:
118+
name: my-component-only-template
119+
body:
120+
index_patterns: [ my-component-only-data-stream-* ]
121+
data_stream: { }
122+
composed_of:
123+
- mappings-template
124+
125+
- do:
126+
indices.create_data_stream:
127+
name: my-component-only-data-stream-1
128+
129+
- do:
130+
cluster.health:
131+
index: "my-component-only-data-stream-1"
132+
wait_for_status: green
133+
134+
- do:
135+
indices.get_data_stream:
136+
name: my-component-only-data-stream-1
137+
- match: { data_streams.0.name: my-component-only-data-stream-1 }
138+
- match: { data_streams.0.mappings: {} }
139+
- match: { data_streams.0.effective_mappings: null }
140+
141+
- do:
142+
indices.put_data_stream_mappings:
143+
name: my-component-only-data-stream-1
144+
body:
145+
properties:
146+
field1:
147+
type: text
148+
field3:
149+
type: text
150+
- match: { data_streams.0.name: my-component-only-data-stream-1 }
151+
- match: { data_streams.0.applied_to_data_stream: true }
152+
- match: { data_streams.0.mappings.properties.field1.type: "text" }
153+
- match: { data_streams.0.mappings.properties.field2: null }
154+
- match: { data_streams.0.mappings.properties.field3.type: "text" }
155+
- match: { data_streams.0.effective_mappings.properties.field1.type: "text" }
156+
- match: { data_streams.0.effective_mappings.properties.field2.type: "keyword" }
157+
- match: { data_streams.0.effective_mappings.properties.field3.type: "text" }
158+
159+
- do:
160+
indices.rollover:
161+
alias: "my-component-only-data-stream-1"
162+
163+
- do:
164+
cluster.health:
165+
index: "my-component-only-data-stream-1"
166+
wait_for_status: green
167+
168+
- do:
169+
indices.get_data_stream_mappings:
170+
name: my-component-only-data-stream-1
171+
- match: { data_streams.0.name: my-component-only-data-stream-1 }
172+
- length: { data_streams.0.effective_mappings.properties: 4 }
173+
- match: { data_streams.0.mappings.properties.field1.type: "text" }
174+
- match: { data_streams.0.effective_mappings.properties.field3.type: "text" }
175+
176+
- do:
177+
indices.get_data_stream:
178+
name: my-component-only-data-stream-1
179+
- match: { data_streams.0.name: my-component-only-data-stream-1 }
180+
- match: { data_streams.0.mappings.properties.field1.type: "text" }
181+
- match: { data_streams.0.effective_mappings: null }
182+
- set: { data_streams.0.indices.0.index_name: oldIndexName }
183+
- set: { data_streams.0.indices.1.index_name: newIndexName }
184+
185+
- do:
186+
indices.get_mapping:
187+
index: my-component-only-data-stream-1
188+
- match: { .$oldIndexName.mappings.properties.field1.type: "keyword" }
189+
- match: { .$oldIndexName.mappings.properties.field2.type: "keyword" }
190+
- match: { .$oldIndexName.mappings.properties.field3: null }
191+
- match: { .$newIndexName.mappings.properties.field1.type: "text" }
192+
- match: { .$newIndexName.mappings.properties.field2.type: "keyword" }
193+
- match: { .$newIndexName.mappings.properties.field3.type: "text" }
194+
195+
- do:
196+
indices.put_data_stream_mappings:
197+
name: my-component-only-data-stream-1
198+
body: {}
199+
- match: { data_streams.0.name: my-component-only-data-stream-1 }
200+
- match: { data_streams.0.applied_to_data_stream: true }
201+
- match: { data_streams.0.mappings null }
202+
- match: { data_streams.0.effective_mappings.properties.field1.type: "keyword" }
203+
- match: { data_streams.0.effective_mappings.properties.field2.type: "keyword" }
204+
- match: { data_streams.0.effective_mappings.properties.field3: null }

server/src/main/java/org/elasticsearch/cluster/metadata/ComposableIndexTemplate.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -373,7 +373,7 @@ public ComposableIndexTemplate mergeMappings(CompressedXContent mappings) throws
373373
}
374374

375375
@SuppressWarnings("unchecked")
376-
private CompressedXContent merge(CompressedXContent originalMapping, CompressedXContent mappingAddition) throws IOException {
376+
public static CompressedXContent merge(CompressedXContent originalMapping, CompressedXContent mappingAddition) throws IOException {
377377
Map<String, Object> mappingAdditionMap = XContentHelper.convertToMap(mappingAddition.uncompressed(), true, XContentType.JSON).v2();
378378
Map<String, Object> combinedMappingMap = new HashMap<>();
379379
if (originalMapping != null) {
@@ -389,7 +389,7 @@ private CompressedXContent merge(CompressedXContent originalMapping, CompressedX
389389
return convertMappingMapToXContent(combinedMappingMap);
390390
}
391391

392-
private static CompressedXContent convertMappingMapToXContent(Map<String, Object> rawAdditionalMapping) throws IOException {
392+
public static CompressedXContent convertMappingMapToXContent(Map<String, ?> rawAdditionalMapping) throws IOException {
393393
CompressedXContent compressedXContent;
394394
if (rawAdditionalMapping.isEmpty()) {
395395
compressedXContent = EMPTY_MAPPINGS;

server/src/main/java/org/elasticsearch/cluster/metadata/DataStream.java

Lines changed: 50 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,12 @@
4646
import org.elasticsearch.index.IndexMode;
4747
import org.elasticsearch.index.IndexSettings;
4848
import org.elasticsearch.index.mapper.DateFieldMapper;
49+
import org.elasticsearch.index.mapper.DocumentMapper;
50+
import org.elasticsearch.index.mapper.MapperService;
51+
import org.elasticsearch.indices.IndicesService;
4952
import org.elasticsearch.indices.SystemIndices;
5053
import org.elasticsearch.xcontent.ConstructingObjectParser;
54+
import org.elasticsearch.xcontent.NamedXContentRegistry;
5155
import org.elasticsearch.xcontent.ObjectParser;
5256
import org.elasticsearch.xcontent.ParseField;
5357
import org.elasticsearch.xcontent.ToXContentObject;
@@ -73,7 +77,9 @@
7377
import java.util.stream.Collectors;
7478

7579
import static org.elasticsearch.cluster.metadata.ComposableIndexTemplate.EMPTY_MAPPINGS;
80+
import static org.elasticsearch.cluster.metadata.ComposableIndexTemplate.convertMappingMapToXContent;
7681
import static org.elasticsearch.cluster.metadata.MetadataCreateDataStreamService.lookupTemplateForDataStream;
82+
import static org.elasticsearch.cluster.metadata.MetadataCreateIndexService.collectV2Mappings;
7783
import static org.elasticsearch.common.xcontent.XContentParserUtils.ensureExpectedToken;
7884
import static org.elasticsearch.index.IndexSettings.LIFECYCLE_ORIGINATION_DATE;
7985
import static org.elasticsearch.index.IndexSettings.PREFER_ILM_SETTING;
@@ -408,8 +414,50 @@ public Settings getEffectiveSettings(ProjectMetadata projectMetadata) {
408414
return templateSettings.merge(settings);
409415
}
410416

411-
public CompressedXContent getEffectiveMappings(ProjectMetadata projectMetadata) throws IOException {
412-
return getMatchingIndexTemplate(projectMetadata).mergeMappings(mappings).template().mappings();
417+
public CompressedXContent getEffectiveMappings(
418+
ProjectMetadata projectMetadata,
419+
NamedXContentRegistry xContentRegistry,
420+
IndicesService indicesService
421+
) throws Exception {
422+
ComposableIndexTemplate templateWithMergedMappings = getEffectiveIndexTemplate(projectMetadata);
423+
return getEffectiveMappings(projectMetadata, templateWithMergedMappings, getWriteIndex(), xContentRegistry, indicesService);
424+
}
425+
426+
@SuppressWarnings("unchecked")
427+
public static CompressedXContent getEffectiveMappings(
428+
ProjectMetadata projectMetadata,
429+
ComposableIndexTemplate templateWithMergedMappings,
430+
Index writeIndex,
431+
NamedXContentRegistry xContentRegistry,
432+
IndicesService indicesService
433+
) throws Exception {
434+
final List<CompressedXContent> mappings = collectV2Mappings(
435+
"{}",
436+
projectMetadata,
437+
templateWithMergedMappings,
438+
xContentRegistry,
439+
writeIndex.getName()
440+
);
441+
return indicesService.withTempIndexService(projectMetadata.index(writeIndex), indexService -> {
442+
MapperService mapperService = indexService.mapperService();
443+
DocumentMapper documentMapper = mapperService.merge(
444+
MapperService.SINGLE_MAPPING_NAME,
445+
mappings,
446+
MapperService.MergeReason.INDEX_TEMPLATE
447+
);
448+
Map<String, ?> resultMapping;
449+
Map<String, Object> originalMappingMap = XContentHelper.convertToMap(
450+
documentMapper.mappingSource().uncompressed(),
451+
true,
452+
XContentType.JSON
453+
).v2();
454+
if (originalMappingMap.containsKey(MapperService.SINGLE_MAPPING_NAME)) {
455+
resultMapping = (Map<String, ?>) originalMappingMap.get(MapperService.SINGLE_MAPPING_NAME);
456+
} else {
457+
resultMapping = originalMappingMap;
458+
}
459+
return convertMappingMapToXContent(resultMapping);
460+
});
413461
}
414462

415463
private ComposableIndexTemplate getMatchingIndexTemplate(ProjectMetadata projectMetadata) {

server/src/main/java/org/elasticsearch/cluster/metadata/MetadataDataStreamsService.java

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
import org.elasticsearch.logging.Logger;
3939
import org.elasticsearch.snapshots.SnapshotInProgressException;
4040
import org.elasticsearch.snapshots.SnapshotsService;
41+
import org.elasticsearch.xcontent.NamedXContentRegistry;
4142

4243
import java.io.IOException;
4344
import java.util.HashSet;
@@ -56,6 +57,7 @@ public class MetadataDataStreamsService {
5657
private static final Logger LOGGER = LogManager.getLogger(MetadataDataStreamsService.class);
5758
private final ClusterService clusterService;
5859
private final IndicesService indicesService;
60+
private final NamedXContentRegistry xContentRegistry;
5961
private final DataStreamGlobalRetentionSettings globalRetentionSettings;
6062
private final MasterServiceTaskQueue<UpdateLifecycleTask> updateLifecycleTaskQueue;
6163
private final MasterServiceTaskQueue<SetRolloverOnWriteTask> setRolloverOnWriteTaskQueue;
@@ -66,10 +68,12 @@ public class MetadataDataStreamsService {
6668
public MetadataDataStreamsService(
6769
ClusterService clusterService,
6870
IndicesService indicesService,
71+
NamedXContentRegistry xContentRegistry,
6972
DataStreamGlobalRetentionSettings globalRetentionSettings
7073
) {
7174
this.clusterService = clusterService;
7275
this.indicesService = indicesService;
76+
this.xContentRegistry = xContentRegistry;
7377
this.globalRetentionSettings = globalRetentionSettings;
7478
ClusterStateTaskExecutor<UpdateLifecycleTask> updateLifecycleExecutor = new SimpleBatchedAckListenerTaskExecutor<>() {
7579

@@ -497,11 +501,7 @@ private DataStream createDataStreamForUpdatedDataStreamSettings(
497501
final ComposableIndexTemplate template = lookupTemplateForDataStream(dataStreamName, projectMetadata);
498502
Settings templateSettings = MetadataIndexTemplateService.resolveSettings(template, projectMetadata.componentTemplates());
499503
Settings mergedEffectiveSettings = templateSettings.merge(mergedDataStreamSettings);
500-
MetadataIndexTemplateService.validateTemplate(
501-
mergedEffectiveSettings,
502-
dataStream.getEffectiveMappings(projectMetadata),
503-
indicesService
504-
);
504+
MetadataIndexTemplateService.validateTemplate(mergedEffectiveSettings, null, indicesService);
505505

506506
return dataStream.copy().setSettings(mergedDataStreamSettings).build();
507507
}
@@ -518,11 +518,14 @@ private DataStream createDataStreamForUpdatedDataStreamMappings(
518518

519519
final ComposableIndexTemplate template = lookupTemplateForDataStream(dataStreamName, projectMetadata);
520520
ComposableIndexTemplate mergedTemplate = template.mergeMappings(mappingsOverrides);
521-
MetadataIndexTemplateService.validateTemplate(
522-
dataStream.getEffectiveSettings(projectMetadata),
523-
mergedTemplate.template().mappings(),
521+
CompressedXContent effectiveMappings = DataStream.getEffectiveMappings(
522+
projectMetadata,
523+
mergedTemplate,
524+
dataStream.getWriteIndex(),
525+
xContentRegistry,
524526
indicesService
525527
);
528+
MetadataIndexTemplateService.validateTemplate(dataStream.getEffectiveSettings(projectMetadata), effectiveMappings, indicesService);
526529
return dataStream.copy().setMappings(mappingsOverrides).build();
527530
}
528531

0 commit comments

Comments
 (0)