Skip to content

Commit a76df69

Browse files
authored
IndexTemplateMetaData.mappings() should return a single object (#52961)
Currently it returns a map, but that map can only ever hold one set of mappings so it makes sense to change the signature here. Relates to #41059
1 parent 9a2a59b commit a76df69

File tree

9 files changed

+53
-94
lines changed

9 files changed

+53
-94
lines changed

client/rest-high-level/src/test/java/org/elasticsearch/client/indices/GetIndexTemplatesResponseTests.java

+5-3
Original file line numberDiff line numberDiff line change
@@ -110,8 +110,7 @@ public void testParsingFromEsResponse() throws IOException {
110110
assertThat(result.order(), equalTo(esIMD.order()));
111111
assertThat(result.version(), equalTo(esIMD.version()));
112112

113-
assertThat(esIMD.mappings().size(), equalTo(1));
114-
BytesArray mappingSource = new BytesArray(esIMD.mappings().valuesIt().next().uncompressed());
113+
BytesArray mappingSource = new BytesArray(esIMD.mappings().uncompressed());
115114
Map<String, Object> expectedMapping =
116115
XContentHelper.convertToMap(mappingSource, true, xContentBuilder.contentType()).v2();
117116
assertThat(result.mappings().sourceAsMap(), equalTo(expectedMapping.get("_doc")));
@@ -205,7 +204,10 @@ static void toXContent(GetIndexTemplatesResponse response, XContentBuilder build
205204
serverTemplateBuilder.order(clientITMD.order());
206205
serverTemplateBuilder.version(clientITMD.version());
207206
if (clientITMD.mappings() != null) {
208-
serverTemplateBuilder.putMapping(MapperService.SINGLE_MAPPING_NAME, clientITMD.mappings().source());
207+
// The client-side mappings never include a wrapping type, but server-side mappings
208+
// for index templates still do so we need to wrap things here
209+
String mappings = "{\"" + MapperService.SINGLE_MAPPING_NAME + "\": " + clientITMD.mappings().source().string() + "}";
210+
serverTemplateBuilder.putMapping(MapperService.SINGLE_MAPPING_NAME, mappings);
209211
}
210212
serverIndexTemplates.add(serverTemplateBuilder.build());
211213

server/src/main/java/org/elasticsearch/cluster/ClusterState.java

+1-25
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,6 @@
4646
import org.elasticsearch.common.bytes.BytesArray;
4747
import org.elasticsearch.common.bytes.BytesReference;
4848
import org.elasticsearch.common.collect.ImmutableOpenMap;
49-
import org.elasticsearch.common.compress.CompressedXContent;
5049
import org.elasticsearch.common.io.stream.BytesStreamOutput;
5150
import org.elasticsearch.common.io.stream.NamedWriteableAwareStreamInput;
5251
import org.elasticsearch.common.io.stream.NamedWriteableRegistry;
@@ -430,30 +429,7 @@ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws
430429
builder.startObject("templates");
431430
for (ObjectCursor<IndexTemplateMetaData> cursor : metaData().templates().values()) {
432431
IndexTemplateMetaData templateMetaData = cursor.value;
433-
builder.startObject(templateMetaData.name());
434-
435-
builder.field("index_patterns", templateMetaData.patterns());
436-
builder.field("order", templateMetaData.order());
437-
438-
builder.startObject("settings");
439-
Settings settings = templateMetaData.settings();
440-
settings.toXContent(builder, params);
441-
builder.endObject();
442-
443-
builder.startObject("mappings");
444-
for (ObjectObjectCursor<String, CompressedXContent> cursor1 : templateMetaData.mappings()) {
445-
Map<String, Object> mapping = XContentHelper.convertToMap(new BytesArray(cursor1.value.uncompressed()), false).v2();
446-
if (mapping.size() == 1 && mapping.containsKey(cursor1.key)) {
447-
// the type name is the root value, reduce it
448-
mapping = (Map<String, Object>) mapping.get(cursor1.key);
449-
}
450-
builder.field(cursor1.key);
451-
builder.map(mapping);
452-
}
453-
builder.endObject();
454-
455-
456-
builder.endObject();
432+
IndexTemplateMetaData.Builder.toXContentWithTypes(templateMetaData, builder, params);
457433
}
458434
builder.endObject();
459435

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

+35-44
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,10 @@
3838
import org.elasticsearch.common.xcontent.XContentFactory;
3939
import org.elasticsearch.common.xcontent.XContentHelper;
4040
import org.elasticsearch.common.xcontent.XContentParser;
41+
import org.elasticsearch.common.xcontent.json.JsonXContent;
4142

4243
import java.io.IOException;
44+
import java.io.UncheckedIOException;
4345
import java.util.ArrayList;
4446
import java.util.Collections;
4547
import java.util.List;
@@ -132,12 +134,15 @@ public Settings settings() {
132134
return this.settings;
133135
}
134136

135-
public ImmutableOpenMap<String, CompressedXContent> mappings() {
136-
return this.mappings;
137+
public CompressedXContent mappings() {
138+
if (this.mappings.isEmpty()) {
139+
return null;
140+
}
141+
return this.mappings.iterator().next().value;
137142
}
138143

139-
public ImmutableOpenMap<String, CompressedXContent> getMappings() {
140-
return this.mappings;
144+
public CompressedXContent getMappings() {
145+
return this.mappings();
141146
}
142147

143148
public ImmutableOpenMap<String, AliasMetaData> aliases() {
@@ -219,6 +224,19 @@ public void writeTo(StreamOutput out) throws IOException {
219224
out.writeOptionalVInt(version);
220225
}
221226

227+
@Override
228+
public String toString() {
229+
try {
230+
XContentBuilder builder = JsonXContent.contentBuilder();
231+
builder.startObject();
232+
IndexTemplateMetaData.Builder.toXContentWithTypes(this, builder, ToXContent.EMPTY_PARAMS);
233+
builder.endObject();
234+
return Strings.toString(builder);
235+
} catch (IOException e) {
236+
throw new UncheckedIOException(e);
237+
}
238+
}
239+
222240
public static class Builder {
223241

224242
private static final Set<String> VALID_FIELDS = Sets.newHashSet(
@@ -251,7 +269,7 @@ public Builder(IndexTemplateMetaData indexTemplateMetaData) {
251269
patterns(indexTemplateMetaData.patterns());
252270
settings(indexTemplateMetaData.settings());
253271

254-
mappings = ImmutableOpenMap.builder(indexTemplateMetaData.mappings());
272+
mappings = ImmutableOpenMap.builder(indexTemplateMetaData.mappings);
255273
aliases = ImmutableOpenMap.builder(indexTemplateMetaData.aliases());
256274
}
257275

@@ -371,41 +389,18 @@ private static void toInnerXContent(IndexTemplateMetaData indexTemplateMetaData,
371389
indexTemplateMetaData.settings().toXContent(builder, params);
372390
builder.endObject();
373391

374-
if (params.paramAsBoolean("reduce_mappings", false)) {
375-
// The parameter include_type_name is only ever used in the REST API, where reduce_mappings is
376-
// always set to true. We therefore only check for include_type_name in this branch.
377-
if (includeTypeName == false) {
378-
Map<String, Object> documentMapping = null;
379-
for (ObjectObjectCursor<String, CompressedXContent> cursor : indexTemplateMetaData.mappings()) {
380-
assert documentMapping == null;
381-
byte[] mappingSource = cursor.value.uncompressed();
382-
Map<String, Object> mapping = XContentHelper.convertToMap(new BytesArray(mappingSource), true).v2();
383-
documentMapping = reduceMapping(cursor.key, mapping);
384-
}
392+
includeTypeName &= (params.paramAsBoolean("reduce_mappings", false) == false);
385393

386-
if (documentMapping != null) {
387-
builder.field("mappings", documentMapping);
388-
} else {
389-
builder.startObject("mappings").endObject();
390-
}
391-
} else {
392-
builder.startObject("mappings");
393-
for (ObjectObjectCursor<String, CompressedXContent> cursor : indexTemplateMetaData.mappings()) {
394-
byte[] mappingSource = cursor.value.uncompressed();
395-
Map<String, Object> mapping = XContentHelper.convertToMap(new BytesArray(mappingSource), true).v2();
396-
mapping = reduceMapping(cursor.key, mapping);
397-
builder.field(cursor.key);
398-
builder.map(mapping);
399-
}
400-
builder.endObject();
394+
CompressedXContent m = indexTemplateMetaData.mappings();
395+
if (m != null) {
396+
Map<String, Object> documentMapping = XContentHelper.convertToMap(new BytesArray(m.uncompressed()), true).v2();
397+
if (includeTypeName == false) {
398+
documentMapping = reduceMapping(documentMapping);
401399
}
400+
builder.field("mappings");
401+
builder.map(documentMapping);
402402
} else {
403-
builder.startArray("mappings");
404-
for (ObjectObjectCursor<String, CompressedXContent> cursor : indexTemplateMetaData.mappings()) {
405-
byte[] data = cursor.value.uncompressed();
406-
builder.map(XContentHelper.convertToMap(new BytesArray(data), true).v2());
407-
}
408-
builder.endArray();
403+
builder.startObject("mappings").endObject();
409404
}
410405

411406
builder.startObject("aliases");
@@ -416,13 +411,9 @@ private static void toInnerXContent(IndexTemplateMetaData indexTemplateMetaData,
416411
}
417412

418413
@SuppressWarnings("unchecked")
419-
private static Map<String, Object> reduceMapping(String type, Map<String, Object> mapping) {
420-
if (mapping.size() == 1 && mapping.containsKey(type)) {
421-
// the type name is the root value, reduce it
422-
return (Map<String, Object>) mapping.get(type);
423-
} else {
424-
return mapping;
425-
}
414+
private static Map<String, Object> reduceMapping(Map<String, Object> mapping) {
415+
assert mapping.keySet().size() == 1;
416+
return (Map<String, Object>) mapping.values().iterator().next();
426417
}
427418

428419
public static IndexTemplateMetaData fromXContent(XContentParser parser, String templateName) throws IOException {

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

+4-8
Original file line numberDiff line numberDiff line change
@@ -414,15 +414,11 @@ static Map<String, Object> parseMappings(String mappingsJson, List<IndexTemplate
414414
Map<String, Object> mappings = MapperService.parseMapping(xContentRegistry, mappingsJson);
415415
// apply templates, merging the mappings into the request mapping if exists
416416
for (IndexTemplateMetaData template : templates) {
417-
for (ObjectObjectCursor<String, CompressedXContent> cursor : template.mappings()) {
418-
String mappingString = cursor.value.string();
419-
// Templates are wrapped with their _type names, which for pre-8x templates may not
420-
// be _doc. For now, we unwrap them based on the _type name, and then re-wrap with
421-
// _doc
422-
// TODO in 9x these will all have a _type of _doc so no re-wrapping will be necessary
423-
Map<String, Object> templateMapping = MapperService.parseMapping(xContentRegistry, mappingString);
417+
CompressedXContent mapping = template.mappings();
418+
if (mapping != null) {
419+
Map<String, Object> templateMapping = MapperService.parseMapping(xContentRegistry, mapping.string());
424420
assert templateMapping.size() == 1 : templateMapping;
425-
assert cursor.key.equals(templateMapping.keySet().iterator().next()) : cursor.key + " != " + templateMapping;
421+
// pre-8x templates may have a wrapper type other than _doc, so we re-wrap things here
426422
templateMapping = Collections.singletonMap(MapperService.SINGLE_MAPPING_NAME,
427423
templateMapping.values().iterator().next());
428424
if (mappings.isEmpty()) {

server/src/test/java/org/elasticsearch/cluster/metadata/IndexTemplateMetaDataTests.java

+1-3
Original file line numberDiff line numberDiff line change
@@ -35,14 +35,12 @@
3535
import java.util.Arrays;
3636
import java.util.Collections;
3737

38-
import static java.util.Collections.singletonMap;
3938
import static org.hamcrest.CoreMatchers.equalTo;
4039
import static org.hamcrest.Matchers.contains;
4140

4241
public class IndexTemplateMetaDataTests extends ESTestCase {
4342

4443
public void testIndexTemplateMetaDataXContentRoundTrip() throws Exception {
45-
ToXContent.Params params = new ToXContent.MapParams(singletonMap("reduce_mappings", "true"));
4644

4745
String template = "{\"index_patterns\" : [ \".test-*\" ],\"order\" : 1000," +
4846
"\"settings\" : {\"number_of_shards\" : 1,\"number_of_replicas\" : 0}," +
@@ -62,7 +60,7 @@ public void testIndexTemplateMetaDataXContentRoundTrip() throws Exception {
6260
final BytesReference templateBytesRoundTrip;
6361
try (XContentBuilder builder = XContentBuilder.builder(JsonXContent.jsonXContent)) {
6462
builder.startObject();
65-
IndexTemplateMetaData.Builder.toXContentWithTypes(indexTemplateMetaData, builder, params);
63+
IndexTemplateMetaData.Builder.toXContentWithTypes(indexTemplateMetaData, builder, ToXContent.EMPTY_PARAMS);
6664
builder.endObject();
6765
templateBytesRoundTrip = BytesReference.bytes(builder);
6866
}

x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/template/TemplateUtils.java

+3-5
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414
import org.elasticsearch.common.Strings;
1515
import org.elasticsearch.common.bytes.BytesArray;
1616
import org.elasticsearch.common.bytes.BytesReference;
17-
import org.elasticsearch.common.collect.ImmutableOpenMap;
1817
import org.elasticsearch.common.compress.CompressedXContent;
1918
import org.elasticsearch.common.io.Streams;
2019
import org.elasticsearch.common.xcontent.LoggingDeprecationHandler;
@@ -161,14 +160,13 @@ public static boolean checkTemplateExistsAndVersionMatches(
161160
if (templateMeta == null) {
162161
return false;
163162
}
164-
ImmutableOpenMap<String, CompressedXContent> mappings = templateMeta.getMappings();
163+
CompressedXContent mappings = templateMeta.getMappings();
165164
// check all mappings contain correct version in _meta
166165
// we have to parse the source here which is annoying
167-
for (Object typeMapping : mappings.values().toArray()) {
168-
CompressedXContent typeMappingXContent = (CompressedXContent) typeMapping;
166+
if (mappings != null) {
169167
try {
170168
Map<String, Object> typeMappingMap = convertToMap(
171-
new BytesArray(typeMappingXContent.uncompressed()), false,
169+
new BytesArray(mappings.uncompressed()), false,
172170
XContentType.JSON).v2();
173171
// should always contain one entry with key = typename
174172
assert (typeMappingMap.size() == 1);

x-pack/plugin/logstash/src/main/java/org/elasticsearch/xpack/logstash/Logstash.java

+1-3
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
import org.elasticsearch.action.ActionResponse;
1212
import org.elasticsearch.cluster.metadata.IndexTemplateMetaData;
1313
import org.elasticsearch.common.settings.Settings;
14-
import org.elasticsearch.index.mapper.MapperService;
1514
import org.elasticsearch.indices.SystemIndexDescriptor;
1615
import org.elasticsearch.plugins.Plugin;
1716
import org.elasticsearch.plugins.SystemIndexPlugin;
@@ -56,8 +55,7 @@ public UnaryOperator<Map<String, IndexTemplateMetaData>> getIndexTemplateMetaDat
5655
templates.keySet().removeIf(OLD_LOGSTASH_INDEX_NAME::equals);
5756
TemplateUtils.loadTemplateIntoMap("/" + LOGSTASH_TEMPLATE_FILE_NAME + ".json", templates, LOGSTASH_INDEX_TEMPLATE_NAME,
5857
Version.CURRENT.toString(), TEMPLATE_VERSION_VARIABLE, LogManager.getLogger(Logstash.class));
59-
//internal representation of typeless templates requires the default "_doc" type, which is also required for internal templates
60-
assert templates.get(LOGSTASH_INDEX_TEMPLATE_NAME).mappings().get(MapperService.SINGLE_MAPPING_NAME) != null;
58+
assert templates.get(LOGSTASH_INDEX_TEMPLATE_NAME).mappings() != null;
6159
return templates;
6260
};
6361
}

x-pack/plugin/monitoring/src/test/java/org/elasticsearch/xpack/monitoring/exporter/local/LocalExporterResourceIntegTests.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,7 @@ private void assertTemplateNotUpdated() {
194194
final String name = MonitoringTemplateUtils.templateName(system.getSystem());
195195

196196
for (IndexTemplateMetaData template : client().admin().indices().prepareGetTemplates(name).get().getIndexTemplates()) {
197-
final String docMapping = template.getMappings().get("_doc").toString();
197+
final String docMapping = template.getMappings().toString();
198198

199199
assertThat(docMapping, notNullValue());
200200
assertThat(docMapping, containsString("test"));

x-pack/plugin/transform/src/main/java/org/elasticsearch/xpack/transform/persistence/TransformInternalIndex.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -362,7 +362,7 @@ protected static void installLatestVersionedIndexTemplateIfRequired(
362362
// Installing the template involves communication with the master node, so it's more expensive but much rarer
363363
try {
364364
IndexTemplateMetaData indexTemplateMetaData = getIndexTemplateMetaData();
365-
BytesReference jsonMappings = new BytesArray(indexTemplateMetaData.mappings().get(SINGLE_MAPPING_NAME).uncompressed());
365+
BytesReference jsonMappings = new BytesArray(indexTemplateMetaData.mappings().uncompressed());
366366
PutIndexTemplateRequest request = new PutIndexTemplateRequest(TransformInternalIndexConstants.LATEST_INDEX_VERSIONED_NAME)
367367
.patterns(indexTemplateMetaData.patterns())
368368
.version(indexTemplateMetaData.version())
@@ -396,7 +396,7 @@ protected static void installLatestAuditIndexTemplateIfRequired(
396396
// Installing the template involves communication with the master node, so it's more expensive but much rarer
397397
try {
398398
IndexTemplateMetaData indexTemplateMetaData = getAuditIndexTemplateMetaData();
399-
BytesReference jsonMappings = new BytesArray(indexTemplateMetaData.mappings().get(SINGLE_MAPPING_NAME).uncompressed());
399+
BytesReference jsonMappings = new BytesArray(indexTemplateMetaData.mappings().uncompressed());
400400
PutIndexTemplateRequest request = new PutIndexTemplateRequest(TransformInternalIndexConstants.AUDIT_INDEX).patterns(
401401
indexTemplateMetaData.patterns()
402402
)

0 commit comments

Comments
 (0)