Skip to content

Commit ac1c694

Browse files
authored
Stop automatically nesting mappings in index creation requests. (#36924)
Now that we unwrap mappings in DocumentMapperParser#extractMappings, it is not necessary for the mapping definition to always be nested under the type. This leniency around the mapping format was added in 2341825.
1 parent eaeccd8 commit ac1c694

File tree

5 files changed

+111
-93
lines changed

5 files changed

+111
-93
lines changed

server/src/main/java/org/elasticsearch/action/admin/indices/create/CreateIndexRequest.java

+1-6
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@
3333
import org.elasticsearch.common.Strings;
3434
import org.elasticsearch.common.bytes.BytesArray;
3535
import org.elasticsearch.common.bytes.BytesReference;
36-
import org.elasticsearch.common.collect.MapBuilder;
3736
import org.elasticsearch.common.io.stream.StreamInput;
3837
import org.elasticsearch.common.io.stream.StreamOutput;
3938
import org.elasticsearch.common.settings.Settings;
@@ -256,10 +255,6 @@ public CreateIndexRequest mapping(String type, Map<String, ?> source) {
256255
if (mappings.containsKey(type)) {
257256
throw new IllegalStateException("mappings for type \"" + type + "\" were already defined");
258257
}
259-
// wrap it in a type map if its not
260-
if (source.size() != 1 || !source.containsKey(type)) {
261-
source = MapBuilder.<String, Object>newMapBuilder().put(type, source).map();
262-
}
263258
try {
264259
XContentBuilder builder = XContentFactory.contentBuilder(XContentType.JSON);
265260
builder.map(source);
@@ -274,7 +269,7 @@ public CreateIndexRequest mapping(String type, Map<String, ?> source) {
274269
* ("field1", "type=string,store=true").
275270
*/
276271
public CreateIndexRequest mapping(String type, Object... source) {
277-
mapping(type, PutMappingRequest.buildFromSimplifiedDef(type, source));
272+
mapping(type, PutMappingRequest.buildFromSimplifiedDef(source));
278273
return this;
279274
}
280275

server/src/main/java/org/elasticsearch/action/admin/indices/mapping/put/PutMappingRequest.java

+12
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,18 @@ public PutMappingRequest source(Object... source) {
184184
return source(buildFromSimplifiedDef(type, source));
185185
}
186186

187+
/**
188+
* @param source
189+
* consisting of field/properties pairs (e.g. "field1",
190+
* "type=string,store=true")
191+
* @throws IllegalArgumentException
192+
* if the number of the source arguments is not divisible by two
193+
* @return the mappings definition
194+
*/
195+
public static XContentBuilder buildFromSimplifiedDef(Object... source) {
196+
return buildFromSimplifiedDef(null, source);
197+
}
198+
187199
/**
188200
* @param type
189201
* the mapping type

server/src/test/java/org/elasticsearch/action/admin/indices/create/CreateIndexIT.java

+15-1
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ public void testNonNestedMappings() throws Exception {
143143
assertFalse(metadata.sourceAsMap().isEmpty());
144144
}
145145

146-
public void testEmptyNestedMappings() throws Exception {
146+
public void testNonNestedEmptyMappings() throws Exception {
147147
assertAcked(prepareCreate("test")
148148
.addMapping("_doc", XContentFactory.jsonBuilder().startObject().endObject()));
149149

@@ -173,6 +173,20 @@ public void testEmptyMappings() throws Exception {
173173
assertTrue(metadata.sourceAsMap().isEmpty());
174174
}
175175

176+
public void testFlatMappingFormat() throws Exception {
177+
assertAcked(prepareCreate("test")
178+
.addMapping("_doc", "field", "type=keyword"));
179+
180+
GetMappingsResponse response = client().admin().indices().prepareGetMappings("test").get();
181+
182+
ImmutableOpenMap<String, MappingMetaData> mappings = response.mappings().get("test");
183+
assertNotNull(mappings);
184+
185+
MappingMetaData metadata = mappings.get("_doc");
186+
assertNotNull(metadata);
187+
assertFalse(metadata.sourceAsMap().isEmpty());
188+
}
189+
176190
public void testInvalidShardCountSettings() throws Exception {
177191
int value = randomIntBetween(-10, 0);
178192
try {

server/src/test/java/org/elasticsearch/action/admin/indices/create/CreateIndexRequestTests.java

+65-84
Original file line numberDiff line numberDiff line change
@@ -22,31 +22,86 @@
2222
import org.elasticsearch.ElasticsearchParseException;
2323
import org.elasticsearch.action.admin.indices.alias.Alias;
2424
import org.elasticsearch.common.Strings;
25-
import org.elasticsearch.common.bytes.BytesReference;
2625
import org.elasticsearch.common.io.stream.BytesStreamOutput;
2726
import org.elasticsearch.common.io.stream.StreamInput;
28-
import org.elasticsearch.common.settings.Settings;
2927
import org.elasticsearch.common.xcontent.LoggingDeprecationHandler;
3028
import org.elasticsearch.common.xcontent.NamedXContentRegistry;
3129
import org.elasticsearch.common.xcontent.XContentParser;
3230
import org.elasticsearch.common.xcontent.XContentType;
3331
import org.elasticsearch.common.xcontent.json.JsonXContent;
3432
import org.elasticsearch.index.RandomCreateIndexGenerator;
35-
import org.elasticsearch.test.ESTestCase;
36-
import org.elasticsearch.test.hamcrest.ElasticsearchAssertions;
33+
import org.elasticsearch.test.AbstractXContentTestCase;
3734

3835
import java.io.IOException;
3936
import java.util.Map;
4037
import java.util.Set;
4138

42-
import static org.elasticsearch.cluster.metadata.IndexMetaData.SETTING_NUMBER_OF_SHARDS;
43-
import static org.elasticsearch.common.xcontent.ToXContent.EMPTY_PARAMS;
39+
public class CreateIndexRequestTests extends AbstractXContentTestCase<CreateIndexRequest> {
4440

45-
public class CreateIndexRequestTests extends ESTestCase {
41+
@Override
42+
protected CreateIndexRequest createTestInstance() {
43+
try {
44+
return RandomCreateIndexGenerator.randomCreateIndexRequest();
45+
} catch (IOException e) {
46+
throw new RuntimeException(e);
47+
}
48+
}
49+
50+
@Override
51+
protected CreateIndexRequest doParseInstance(XContentParser parser) throws IOException {
52+
CreateIndexRequest request = new CreateIndexRequest();
53+
request.source(parser.map(), LoggingDeprecationHandler.INSTANCE);
54+
return request;
55+
}
56+
57+
@Override
58+
protected void assertEqualInstances(CreateIndexRequest expectedInstance, CreateIndexRequest newInstance) {
59+
assertEquals(expectedInstance.settings(), newInstance.settings());
60+
assertAliasesEqual(expectedInstance.aliases(), newInstance.aliases());
61+
assertMappingsEqual(expectedInstance.mappings(), newInstance.mappings());
62+
}
63+
64+
@Override
65+
protected boolean supportsUnknownFields() {
66+
return false;
67+
}
68+
69+
public static void assertMappingsEqual(Map<String, String> expected, Map<String, String> actual) {
70+
assertEquals(expected.keySet(), actual.keySet());
71+
72+
for (Map.Entry<String, String> expectedEntry : expected.entrySet()) {
73+
String expectedValue = expectedEntry.getValue();
74+
String actualValue = actual.get(expectedEntry.getKey());
75+
try (XContentParser expectedJson = JsonXContent.jsonXContent.createParser(NamedXContentRegistry.EMPTY,
76+
LoggingDeprecationHandler.INSTANCE, expectedValue);
77+
XContentParser actualJson = JsonXContent.jsonXContent.createParser(NamedXContentRegistry.EMPTY,
78+
LoggingDeprecationHandler.INSTANCE, actualValue)) {
79+
assertEquals(expectedJson.map(), actualJson.map());
80+
} catch (IOException e) {
81+
throw new RuntimeException(e);
82+
}
83+
}
84+
}
85+
86+
public static void assertAliasesEqual(Set<Alias> expected, Set<Alias> actual) {
87+
assertEquals(expected, actual);
88+
89+
for (Alias expectedAlias : expected) {
90+
for (Alias actualAlias : actual) {
91+
if (expectedAlias.equals(actualAlias)) {
92+
// As Alias#equals only looks at name, we check the equality of the other Alias parameters here.
93+
assertEquals(expectedAlias.filter(), actualAlias.filter());
94+
assertEquals(expectedAlias.indexRouting(), actualAlias.indexRouting());
95+
assertEquals(expectedAlias.searchRouting(), actualAlias.searchRouting());
96+
}
97+
}
98+
}
99+
}
46100

47101
public void testSerialization() throws IOException {
48102
CreateIndexRequest request = new CreateIndexRequest("foo");
49-
String mapping = Strings.toString(JsonXContent.contentBuilder().startObject().startObject("type").endObject().endObject());
103+
String mapping = Strings.toString(JsonXContent.contentBuilder().startObject()
104+
.startObject("type").endObject().endObject());
50105
request.mapping("my_type", mapping, XContentType.JSON);
51106

52107
try (BytesStreamOutput output = new BytesStreamOutput()) {
@@ -63,7 +118,7 @@ public void testSerialization() throws IOException {
63118

64119
public void testTopLevelKeys() {
65120
String createIndex =
66-
"{\n"
121+
"{\n"
67122
+ " \"FOO_SHOULD_BE_ILLEGAL_HERE\": {\n"
68123
+ " \"BAR_IS_THE_SAME\": 42\n"
69124
+ " },\n"
@@ -80,81 +135,7 @@ public void testTopLevelKeys() {
80135

81136
CreateIndexRequest request = new CreateIndexRequest();
82137
ElasticsearchParseException e = expectThrows(ElasticsearchParseException.class,
83-
() -> {request.source(createIndex, XContentType.JSON);});
138+
() -> {request.source(createIndex, XContentType.JSON);});
84139
assertEquals("unknown key [FOO_SHOULD_BE_ILLEGAL_HERE] for create index", e.getMessage());
85140
}
86-
87-
public void testToXContent() throws IOException {
88-
CreateIndexRequest request = new CreateIndexRequest("foo");
89-
90-
String mapping = Strings.toString(JsonXContent.contentBuilder().startObject().startObject("type").endObject().endObject());
91-
request.mapping("my_type", mapping, XContentType.JSON);
92-
93-
Alias alias = new Alias("test_alias");
94-
alias.routing("1");
95-
alias.filter("{\"term\":{\"year\":2016}}");
96-
alias.writeIndex(true);
97-
request.alias(alias);
98-
99-
Settings.Builder settings = Settings.builder();
100-
settings.put(SETTING_NUMBER_OF_SHARDS, 10);
101-
request.settings(settings);
102-
103-
String actualRequestBody = Strings.toString(request);
104-
105-
String expectedRequestBody = "{\"settings\":{\"index\":{\"number_of_shards\":\"10\"}}," +
106-
"\"mappings\":{\"my_type\":{\"type\":{}}}," +
107-
"\"aliases\":{\"test_alias\":{\"filter\":{\"term\":{\"year\":2016}},\"routing\":\"1\",\"is_write_index\":true}}}";
108-
109-
assertEquals(expectedRequestBody, actualRequestBody);
110-
}
111-
112-
public void testToAndFromXContent() throws IOException {
113-
114-
final CreateIndexRequest createIndexRequest = RandomCreateIndexGenerator.randomCreateIndexRequest();
115-
116-
boolean humanReadable = randomBoolean();
117-
final XContentType xContentType = randomFrom(XContentType.values());
118-
BytesReference originalBytes = toShuffledXContent(createIndexRequest, xContentType, EMPTY_PARAMS, humanReadable);
119-
120-
CreateIndexRequest parsedCreateIndexRequest = new CreateIndexRequest();
121-
parsedCreateIndexRequest.source(originalBytes, xContentType);
122-
123-
assertMappingsEqual(createIndexRequest.mappings(), parsedCreateIndexRequest.mappings());
124-
assertAliasesEqual(createIndexRequest.aliases(), parsedCreateIndexRequest.aliases());
125-
assertEquals(createIndexRequest.settings(), parsedCreateIndexRequest.settings());
126-
127-
BytesReference finalBytes = toShuffledXContent(parsedCreateIndexRequest, xContentType, EMPTY_PARAMS, humanReadable);
128-
ElasticsearchAssertions.assertToXContentEquivalent(originalBytes, finalBytes, xContentType);
129-
}
130-
131-
public static void assertMappingsEqual(Map<String, String> expected, Map<String, String> actual) throws IOException {
132-
assertEquals(expected.keySet(), actual.keySet());
133-
134-
for (Map.Entry<String, String> expectedEntry : expected.entrySet()) {
135-
String expectedValue = expectedEntry.getValue();
136-
String actualValue = actual.get(expectedEntry.getKey());
137-
try (XContentParser expectedJson = JsonXContent.jsonXContent.createParser(NamedXContentRegistry.EMPTY,
138-
LoggingDeprecationHandler.INSTANCE, expectedValue);
139-
XContentParser actualJson = JsonXContent.jsonXContent.createParser(NamedXContentRegistry.EMPTY,
140-
LoggingDeprecationHandler.INSTANCE, actualValue)){
141-
assertEquals(expectedJson.map(), actualJson.map());
142-
}
143-
}
144-
}
145-
146-
public static void assertAliasesEqual(Set<Alias> expected, Set<Alias> actual) throws IOException {
147-
assertEquals(expected, actual);
148-
149-
for (Alias expectedAlias : expected) {
150-
for (Alias actualAlias : actual) {
151-
if (expectedAlias.equals(actualAlias)) {
152-
// As Alias#equals only looks at name, we check the equality of the other Alias parameters here.
153-
assertEquals(expectedAlias.filter(), actualAlias.filter());
154-
assertEquals(expectedAlias.indexRouting(), actualAlias.indexRouting());
155-
assertEquals(expectedAlias.searchRouting(), actualAlias.searchRouting());
156-
}
157-
}
158-
}
159-
}
160141
}

test/framework/src/main/java/org/elasticsearch/index/RandomCreateIndexGenerator.java

+18-2
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929

3030
import static org.elasticsearch.cluster.metadata.IndexMetaData.SETTING_NUMBER_OF_REPLICAS;
3131
import static org.elasticsearch.cluster.metadata.IndexMetaData.SETTING_NUMBER_OF_SHARDS;
32+
import static org.elasticsearch.test.ESTestCase.frequently;
3233
import static org.elasticsearch.test.ESTestCase.randomAlphaOfLength;
3334
import static org.elasticsearch.test.ESTestCase.randomBoolean;
3435
import static org.elasticsearch.test.ESTestCase.randomIntBetween;
@@ -45,9 +46,14 @@ public static CreateIndexRequest randomCreateIndexRequest() throws IOException {
4546
String index = randomAlphaOfLength(5);
4647
CreateIndexRequest request = new CreateIndexRequest(index);
4748
randomAliases(request);
48-
if (randomBoolean()) {
49+
if (frequently()) {
4950
String type = randomAlphaOfLength(5);
50-
request.mapping(type, randomMapping(type));
51+
if (randomBoolean()) {
52+
request.mapping(type, randomMapping());
53+
} else {
54+
request.mapping(type, randomMapping(type));
55+
56+
}
5157
}
5258
if (randomBoolean()) {
5359
request.settings(randomIndexSettings());
@@ -76,6 +82,16 @@ public static Settings randomIndexSettings() {
7682
return builder.build();
7783
}
7884

85+
public static XContentBuilder randomMapping() throws IOException {
86+
XContentBuilder builder = XContentFactory.jsonBuilder();
87+
builder.startObject();
88+
89+
randomMappingFields(builder, true);
90+
91+
builder.endObject();
92+
return builder;
93+
}
94+
7995
public static XContentBuilder randomMapping(String type) throws IOException {
8096
XContentBuilder builder = XContentFactory.jsonBuilder();
8197
builder.startObject().startObject(type);

0 commit comments

Comments
 (0)