Skip to content

Commit 6797844

Browse files
author
Christoph Büscher
authored
Support 'include_type_name' in RestGetIndicesAction (#37267)
This change adds support for the 'include_type_name' parameter for the indices.get API. This parameter, which defaults to `false` starting in 7.0, changes the response to not include the indices type names any longer. If the parameter is set in the request, we additionally emit a deprecation warning since using the parameter should be only temporarily necessary while adapting to the new response format and we will remove it with the next major version.
1 parent 02509c7 commit 6797844

File tree

13 files changed

+262
-31
lines changed

13 files changed

+262
-31
lines changed

client/rest-high-level/src/main/java/org/elasticsearch/client/IndicesRequestConverters.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -312,6 +312,8 @@ static Request getIndex(GetIndexRequest getIndexRequest) {
312312
params.withIncludeDefaults(getIndexRequest.includeDefaults());
313313
params.withHuman(getIndexRequest.humanReadable());
314314
params.withMasterTimeout(getIndexRequest.masterNodeTimeout());
315+
// Force "include_type_name" parameter since responses need to be compatible when coming from 7.0 nodes
316+
params.withIncludeTypeName(true);
315317

316318
return request;
317319
}

client/rest-high-level/src/main/java/org/elasticsearch/client/RequestConverters.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@
7575
import org.elasticsearch.index.reindex.DeleteByQueryRequest;
7676
import org.elasticsearch.index.reindex.ReindexRequest;
7777
import org.elasticsearch.index.reindex.UpdateByQueryRequest;
78+
import org.elasticsearch.rest.BaseRestHandler;
7879
import org.elasticsearch.rest.action.search.RestSearchAction;
7980
import org.elasticsearch.script.mustache.MultiSearchTemplateRequest;
8081
import org.elasticsearch.script.mustache.SearchTemplateRequest;
@@ -930,6 +931,14 @@ Params withIncludeDefaults(boolean includeDefaults) {
930931
return this;
931932
}
932933

934+
Params withIncludeTypeName(boolean includeTypeName) {
935+
if (includeTypeName) {
936+
return putParam(BaseRestHandler.INCLUDE_TYPE_NAME_PARAMETER,
937+
Boolean.toString(BaseRestHandler.DEFAULT_INCLUDE_TYPE_NAME_POLICY));
938+
}
939+
return this;
940+
}
941+
933942
Params withPreserveExisting(boolean preserveExisting) {
934943
if (preserveExisting) {
935944
return putParam("preserve_existing", Boolean.TRUE.toString());

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

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,6 @@
5050
import org.elasticsearch.action.admin.indices.mapping.put.PutMappingRequest;
5151
import org.elasticsearch.action.admin.indices.open.OpenIndexRequest;
5252
import org.elasticsearch.action.admin.indices.open.OpenIndexResponse;
53-
import org.elasticsearch.action.support.ActiveShardCount;
5453
import org.elasticsearch.action.admin.indices.refresh.RefreshRequest;
5554
import org.elasticsearch.action.admin.indices.refresh.RefreshResponse;
5655
import org.elasticsearch.action.admin.indices.rollover.RolloverRequest;
@@ -67,6 +66,7 @@
6766
import org.elasticsearch.action.admin.indices.validate.query.ValidateQueryRequest;
6867
import org.elasticsearch.action.admin.indices.validate.query.ValidateQueryResponse;
6968
import org.elasticsearch.action.index.IndexRequest;
69+
import org.elasticsearch.action.support.ActiveShardCount;
7070
import org.elasticsearch.action.support.IndicesOptions;
7171
import org.elasticsearch.action.support.WriteRequest;
7272
import org.elasticsearch.action.support.broadcast.BroadcastResponse;
@@ -90,6 +90,7 @@
9090
import org.elasticsearch.common.xcontent.json.JsonXContent;
9191
import org.elasticsearch.common.xcontent.support.XContentMapValues;
9292
import org.elasticsearch.index.IndexSettings;
93+
import org.elasticsearch.index.mapper.MapperService;
9394
import org.elasticsearch.index.query.QueryBuilder;
9495
import org.elasticsearch.index.query.QueryBuilders;
9596
import org.elasticsearch.rest.RestStatus;
@@ -217,7 +218,7 @@ public void testCreateIndex() throws IOException {
217218
mappingBuilder.startObject().startObject("properties").startObject("field");
218219
mappingBuilder.field("type", "text");
219220
mappingBuilder.endObject().endObject().endObject();
220-
createIndexRequest.mapping("type_name", mappingBuilder);
221+
createIndexRequest.mapping(MapperService.SINGLE_MAPPING_NAME, mappingBuilder);
221222

222223
CreateIndexResponse createIndexResponse =
223224
execute(createIndexRequest, highLevelClient().indices()::create, highLevelClient().indices()::createAsync,
@@ -235,7 +236,7 @@ public void testCreateIndex() throws IOException {
235236
Map<String, Object> term = (Map) filter.get("term");
236237
assertEquals(2016, term.get("year"));
237238

238-
assertEquals("text", XContentMapValues.extractValue(indexName + ".mappings.type_name.properties.field.type", getIndexResponse));
239+
assertEquals("text", XContentMapValues.extractValue(indexName + ".mappings._doc.properties.field.type", getIndexResponse));
239240
}
240241
}
241242

@@ -349,7 +350,7 @@ public void testGetIndex() throws IOException {
349350
.put(SETTING_NUMBER_OF_SHARDS, 1)
350351
.put(SETTING_NUMBER_OF_REPLICAS, 0)
351352
.build();
352-
String mappings = "\"type-1\":{\"properties\":{\"field-1\":{\"type\":\"integer\"}}}";
353+
String mappings = "\"_doc\":{\"properties\":{\"field-1\":{\"type\":\"integer\"}}}";
353354
createIndex(indexName, basicSettings, mappings);
354355

355356
GetIndexRequest getIndexRequest = new GetIndexRequest()
@@ -362,8 +363,8 @@ public void testGetIndex() throws IOException {
362363
assertEquals("1", getIndexResponse.getSetting(indexName, SETTING_NUMBER_OF_SHARDS));
363364
assertEquals("0", getIndexResponse.getSetting(indexName, SETTING_NUMBER_OF_REPLICAS));
364365
assertNotNull(getIndexResponse.getMappings().get(indexName));
365-
assertNotNull(getIndexResponse.getMappings().get(indexName).get("type-1"));
366-
Object o = getIndexResponse.getMappings().get(indexName).get("type-1").getSourceAsMap().get("properties");
366+
assertNotNull(getIndexResponse.getMappings().get(indexName).get("_doc"));
367+
Object o = getIndexResponse.getMappings().get(indexName).get("_doc").getSourceAsMap().get("properties");
367368
assertThat(o, instanceOf(Map.class));
368369
//noinspection unchecked
369370
assertThat(((Map<String, Object>) o).get("field-1"), instanceOf(Map.class));
@@ -379,7 +380,7 @@ public void testGetIndexWithDefaults() throws IOException {
379380
.put(SETTING_NUMBER_OF_SHARDS, 1)
380381
.put(SETTING_NUMBER_OF_REPLICAS, 0)
381382
.build();
382-
String mappings = "\"type-1\":{\"properties\":{\"field-1\":{\"type\":\"integer\"}}}";
383+
String mappings = "\"_doc\":{\"properties\":{\"field-1\":{\"type\":\"integer\"}}}";
383384
createIndex(indexName, basicSettings, mappings);
384385

385386
GetIndexRequest getIndexRequest = new GetIndexRequest()
@@ -393,8 +394,8 @@ public void testGetIndexWithDefaults() throws IOException {
393394
assertEquals("1", getIndexResponse.getSetting(indexName, SETTING_NUMBER_OF_SHARDS));
394395
assertEquals("0", getIndexResponse.getSetting(indexName, SETTING_NUMBER_OF_REPLICAS));
395396
assertNotNull(getIndexResponse.getMappings().get(indexName));
396-
assertNotNull(getIndexResponse.getMappings().get(indexName).get("type-1"));
397-
Object o = getIndexResponse.getMappings().get(indexName).get("type-1").getSourceAsMap().get("properties");
397+
assertNotNull(getIndexResponse.getMappings().get(indexName).get("_doc"));
398+
Object o = getIndexResponse.getMappings().get(indexName).get("_doc").getSourceAsMap().get("properties");
398399
assertThat(o, instanceOf(Map.class));
399400
assertThat(((Map<String, Object>) o).get("field-1"), instanceOf(Map.class));
400401
Map<String, Object> fieldMapping = (Map<String, Object>) ((Map<String, Object>) o).get("field-1");
@@ -417,7 +418,7 @@ public void testPutMapping() throws IOException {
417418
createIndex(indexName, Settings.EMPTY);
418419

419420
PutMappingRequest putMappingRequest = new PutMappingRequest(indexName);
420-
putMappingRequest.type("type_name");
421+
putMappingRequest.type("_doc");
421422
XContentBuilder mappingBuilder = JsonXContent.contentBuilder();
422423
mappingBuilder.startObject().startObject("properties").startObject("field");
423424
mappingBuilder.field("type", "text");
@@ -430,7 +431,7 @@ public void testPutMapping() throws IOException {
430431
assertTrue(putMappingResponse.isAcknowledged());
431432

432433
Map<String, Object> getIndexResponse = getAsMap(indexName);
433-
assertEquals("text", XContentMapValues.extractValue(indexName + ".mappings.type_name.properties.field.type", getIndexResponse));
434+
assertEquals("text", XContentMapValues.extractValue(indexName + ".mappings._doc.properties.field.type", getIndexResponse));
434435
}
435436

436437
public void testGetMapping() throws IOException {

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@
6161
import org.elasticsearch.common.unit.TimeValue;
6262
import org.elasticsearch.common.util.CollectionUtils;
6363
import org.elasticsearch.index.RandomCreateIndexGenerator;
64+
import org.elasticsearch.rest.BaseRestHandler;
6465
import org.elasticsearch.test.ESTestCase;
6566
import org.junit.Assert;
6667

@@ -364,6 +365,8 @@ public void testGetIndex() throws IOException {
364365
RequestConvertersTests.setRandomIndicesOptions(getIndexRequest::indicesOptions, getIndexRequest::indicesOptions, expectedParams);
365366
RequestConvertersTests.setRandomLocal(getIndexRequest, expectedParams);
366367
RequestConvertersTests.setRandomHumanReadable(getIndexRequest, expectedParams);
368+
// Force "include_type_name" parameter since responses need to be compatible when coming from 7.0 nodes
369+
expectedParams.put(BaseRestHandler.INCLUDE_TYPE_NAME_PARAMETER, "true");
367370

368371
if (ESTestCase.randomBoolean()) {
369372
// the request object will not have include_defaults present unless it is set to

client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/IndicesClientDocumentationIT.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -70,15 +70,15 @@
7070
import org.elasticsearch.action.support.IndicesOptions;
7171
import org.elasticsearch.action.support.master.AcknowledgedResponse;
7272
import org.elasticsearch.client.ESRestHighLevelClientTestCase;
73-
import org.elasticsearch.client.indices.FreezeIndexRequest;
7473
import org.elasticsearch.client.GetAliasesResponse;
7574
import org.elasticsearch.client.RequestOptions;
7675
import org.elasticsearch.client.RestHighLevelClient;
7776
import org.elasticsearch.client.SyncedFlushResponse;
77+
import org.elasticsearch.client.core.ShardsAcknowledgedResponse;
78+
import org.elasticsearch.client.indices.FreezeIndexRequest;
7879
import org.elasticsearch.client.indices.GetIndexTemplatesRequest;
7980
import org.elasticsearch.client.indices.IndexTemplatesExistRequest;
8081
import org.elasticsearch.client.indices.UnfreezeIndexRequest;
81-
import org.elasticsearch.client.core.ShardsAcknowledgedResponse;
8282
import org.elasticsearch.cluster.metadata.AliasMetaData;
8383
import org.elasticsearch.cluster.metadata.IndexTemplateMetaData;
8484
import org.elasticsearch.cluster.metadata.AliasMetaData;
@@ -1246,7 +1246,7 @@ public void testGetIndex() throws Exception {
12461246
Settings settings = Settings.builder().put("number_of_shards", 3).build();
12471247
String mappings = "{\"properties\":{\"field-1\":{\"type\":\"integer\"}}}";
12481248
CreateIndexResponse createIndexResponse = client.indices().create(
1249-
new CreateIndexRequest("index", settings).mapping("doc", mappings, XContentType.JSON),
1249+
new CreateIndexRequest("index", settings).mapping("_doc", mappings, XContentType.JSON),
12501250
RequestOptions.DEFAULT);
12511251
assertTrue(createIndexResponse.isAcknowledged());
12521252
}
@@ -1269,7 +1269,7 @@ public void testGetIndex() throws Exception {
12691269

12701270
// tag::get-index-response
12711271
ImmutableOpenMap<String, MappingMetaData> indexMappings = getIndexResponse.getMappings().get("index"); // <1>
1272-
Map<String, Object> indexTypeMappings = indexMappings.get("doc").getSourceAsMap(); // <2>
1272+
Map<String, Object> indexTypeMappings = indexMappings.get("_doc").getSourceAsMap(); // <2>
12731273
List<AliasMetaData> indexAliases = getIndexResponse.getAliases().get("index"); // <3>
12741274
String numberOfShardsString = getIndexResponse.getSetting("index", "index.number_of_shards"); // <4>
12751275
Settings indexSettings = getIndexResponse.getSettings().get("index"); // <5>

docs/reference/indices/get-index.asciidoc

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,71 @@ alias or wildcard expression is required.
1515

1616
The get index API can also be applied to more than one index, or on
1717
all indices by using `_all` or `*` as index.
18+
19+
[float]
20+
=== Skipping types
21+
22+
Types are being removed from Elasticsearch: in 7.0, the `mappings` element will no
23+
longer return the type name as a top-level key by default. You can already opt in for
24+
this behavior by setting `include_type_name=false` on the request.
25+
26+
NOTE: Such calls will be rejected on indices that have multiple types as it
27+
introduces ambiguity as to which mapping should be returned. Only indices
28+
created by Elasticsearch 5.x may have multiple types.
29+
30+
Here is an example:
31+
32+
[source,js]
33+
--------------------------------------------------
34+
GET twitter?include_type_name=false
35+
--------------------------------------------------
36+
// CONSOLE
37+
// TEST[setup:twitter]
38+
39+
which returns
40+
41+
[source,js]
42+
--------------------------------------------------
43+
{
44+
"twitter": {
45+
"aliases": {},
46+
"mappings" : {
47+
"properties" : {
48+
"date" : {
49+
"type" : "date"
50+
},
51+
"likes" : {
52+
"type" : "long"
53+
},
54+
"message" : {
55+
"type" : "text",
56+
"fields" : {
57+
"keyword" : {
58+
"type" : "keyword",
59+
"ignore_above" : 256
60+
}
61+
}
62+
},
63+
"user" : {
64+
"type" : "keyword"
65+
}
66+
}
67+
},
68+
"settings": {
69+
"index": {
70+
"creation_date": "1547028674905",
71+
"number_of_shards": "1",
72+
"number_of_replicas": "1",
73+
"uuid": "u1YpkPqLSqGIn3kNAvY8cA",
74+
"version": {
75+
"created": ...
76+
},
77+
"provided_name": "twitter"
78+
}
79+
}
80+
}
81+
}
82+
--------------------------------------------------
83+
// TESTRESPONSE[s/1547028674905/$body.twitter.settings.index.creation_date/]
84+
// TESTRESPONSE[s/u1YpkPqLSqGIn3kNAvY8cA/$body.twitter.settings.index.uuid/]
85+
// TESTRESPONSE[s/"created": \.\.\./"created": $body.twitter.settings.index.version.created/]

rest-api-spec/src/main/resources/rest-api-spec/api/indices.get.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@
1313
}
1414
},
1515
"params":{
16+
"include_type_name": {
17+
"type" : "boolean",
18+
"description" : "Whether to add the type name to the response (default: true)"
19+
},
1620
"local":{
1721
"type":"boolean",
1822
"description":"Return local information, do not retrieve the state from master node (default: false)"

rest-api-spec/src/main/resources/rest-api-spec/test/indices.get/10_basic.yml

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,35 @@ setup:
5252
- is_true: test_index.settings
5353
- is_true: test_index.mappings
5454

55+
---
56+
"Test include_type_name":
57+
- skip:
58+
version: " - 6.6.99"
59+
reason: the include_type_name parameter is not supported before 6.7
60+
61+
- do:
62+
indices.get:
63+
index: test_index
64+
65+
- is_true: test_index.mappings
66+
- is_true: test_index.mappings.type_1
67+
68+
- do:
69+
indices.get:
70+
include_type_name: true
71+
index: test_index
72+
73+
- is_true: test_index.mappings
74+
- is_true: test_index.mappings.type_1
75+
76+
- do:
77+
indices.get:
78+
include_type_name: false
79+
index: test_index
80+
81+
- is_true: test_index.mappings
82+
- is_false: test_index.mappings.type_1
83+
5584
---
5685
"Get index infos should work for wildcards":
5786

server/src/main/java/org/elasticsearch/action/admin/indices/get/GetIndexResponse.java

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
package org.elasticsearch.action.admin.indices.get;
2121

2222
import com.carrotsearch.hppc.cursors.ObjectObjectCursor;
23+
2324
import org.apache.lucene.util.CollectionUtil;
2425
import org.elasticsearch.Version;
2526
import org.elasticsearch.action.ActionResponse;
@@ -34,6 +35,8 @@
3435
import org.elasticsearch.common.xcontent.XContentBuilder;
3536
import org.elasticsearch.common.xcontent.XContentParser;
3637
import org.elasticsearch.common.xcontent.XContentParser.Token;
38+
import org.elasticsearch.index.mapper.MapperService;
39+
import org.elasticsearch.rest.BaseRestHandler;
3740

3841
import java.io.IOException;
3942
import java.util.ArrayList;
@@ -44,6 +47,7 @@
4447
import java.util.Objects;
4548

4649
import static org.elasticsearch.common.xcontent.XContentParserUtils.ensureExpectedToken;
50+
import static org.elasticsearch.rest.BaseRestHandler.INCLUDE_TYPE_NAME_PARAMETER;
4751

4852
/**
4953
* A response for a get index action.
@@ -249,15 +253,34 @@ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws
249253
}
250254
builder.endObject();
251255

252-
builder.startObject("mappings");
253256
ImmutableOpenMap<String, MappingMetaData> indexMappings = mappings.get(index);
254-
if (indexMappings != null) {
257+
// the default on 6.x should be true to include types in the response
258+
boolean includeTypeName = params.paramAsBoolean(INCLUDE_TYPE_NAME_PARAMETER,
259+
BaseRestHandler.DEFAULT_INCLUDE_TYPE_NAME_POLICY);
260+
if (includeTypeName) {
261+
builder.startObject("mappings");
262+
if (indexMappings != null) {
263+
for (final ObjectObjectCursor<String, MappingMetaData> typeEntry : indexMappings) {
264+
builder.field(typeEntry.key);
265+
builder.map(typeEntry.value.sourceAsMap());
266+
}
267+
}
268+
builder.endObject();
269+
} else {
270+
MappingMetaData mappings = null;
255271
for (final ObjectObjectCursor<String, MappingMetaData> typeEntry : indexMappings) {
256-
builder.field(typeEntry.key);
257-
builder.map(typeEntry.value.sourceAsMap());
272+
if (typeEntry.key.equals(MapperService.DEFAULT_MAPPING) == false) {
273+
assert mappings == null;
274+
mappings = typeEntry.value;
275+
}
276+
}
277+
if (mappings == null) {
278+
// no mappings yet
279+
builder.startObject("mappings").endObject();
280+
} else {
281+
builder.field("mappings", mappings.sourceAsMap());
258282
}
259283
}
260-
builder.endObject();
261284

262285
builder.startObject("settings");
263286
Settings indexSettings = settings.get(index);

0 commit comments

Comments
 (0)