Skip to content

Commit 6a6c0ea

Browse files
authored
Add an include_type_name option. (#29453)
This adds an `include_type_name` option to the `indices.create`, `indices.get_mapping` and `indices.put_mapping` APIs, which defaults to `true`. When set to `false`, then mappings will be returned directly in the body of the `indices.get_mapping` API, without keying them by the type name, the `indices.create` will expect mappings directly under the `mappings` key, and the `indices.put_mapping` will use `_doc` as a type name and fail if a `type` is provided explicitly. Relates #15613
1 parent 45e7e24 commit 6a6c0ea

File tree

10 files changed

+257
-8
lines changed

10 files changed

+257
-8
lines changed

docs/reference/indices/create-index.asciidoc

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,3 +173,28 @@ PUT test?wait_for_active_shards=2
173173

174174
A detailed explanation of `wait_for_active_shards` and its possible values can be found
175175
<<index-wait-for-active-shards,here>>.
176+
177+
[float]
178+
=== Skipping types
179+
180+
Types are scheduled to be fully removed in Elasticsearch 8.0 and will not appear
181+
in requests or responses anymore. You can opt in for this future behaviour by
182+
setting `include_type_name=false` and putting mappings directly under `mappings`
183+
in the index creation call.
184+
185+
Here is an example:
186+
187+
[source,js]
188+
--------------------------------------------------
189+
PUT test?include_type_name=false
190+
{
191+
"mappings": {
192+
"properties": {
193+
"foo": {
194+
"type": "keyword"
195+
}
196+
}
197+
}
198+
}
199+
--------------------------------------------------
200+
// CONSOLE

docs/reference/indices/get-mapping.asciidoc

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,3 +41,48 @@ GET /_mapping
4141
--------------------------------------------------
4242
// CONSOLE
4343
// TEST[setup:twitter]
44+
45+
[float]
46+
=== Skipping types
47+
48+
Types are scheduled to be fully removed in Elasticsearch 8.0 and will not appear
49+
in requests or responses anymore. You can opt in for this future behaviour by
50+
setting `include_type_name=false` in the request, which will return mappings
51+
directly under `mappings` without keying by the type name.
52+
53+
Here is an example:
54+
55+
[source,js]
56+
--------------------------------------------------
57+
PUT test?include_type_name=false
58+
{
59+
"mappings": {
60+
"properties": {
61+
"foo": {
62+
"type": "keyword"
63+
}
64+
}
65+
}
66+
}
67+
68+
GET test/_mappings?include_type_name=false
69+
--------------------------------------------------
70+
// CONSOLE
71+
72+
which returns
73+
74+
[source,js]
75+
--------------------------------------------------
76+
{
77+
"test": {
78+
"mappings": {
79+
"properties": {
80+
"foo": {
81+
"type": "keyword"
82+
}
83+
}
84+
}
85+
}
86+
}
87+
--------------------------------------------------
88+
// TESTRESPONSE

docs/reference/indices/put-mapping.asciidoc

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,3 +109,54 @@ PUT my_index/_mapping/_doc
109109

110110
Each <<mapping-params,mapping parameter>> specifies whether or not its setting
111111
can be updated on an existing field.
112+
113+
[float]
114+
=== Skipping types
115+
116+
Types are scheduled to be fully removed in Elasticsearch 8.0 and will not appear
117+
in requests or responses anymore. You can opt in for this future behaviour by
118+
setting `include_type_name=false`.
119+
120+
NOTE: This should only be done on indices that have been created with
121+
`include_type_name=false` or that used `_doc` as a type name.
122+
123+
The Console script from the above section is equivalent to the below invocation:
124+
125+
[source,js]
126+
-----------------------------------
127+
PUT my_index?include_type_name=false <1>
128+
{
129+
"mappings": {
130+
"properties": {
131+
"name": {
132+
"properties": {
133+
"first": {
134+
"type": "text"
135+
}
136+
}
137+
},
138+
"user_id": {
139+
"type": "keyword"
140+
}
141+
}
142+
}
143+
}
144+
145+
PUT my_index/_mapping?include_type_name=false
146+
{
147+
"properties": {
148+
"name": {
149+
"properties": {
150+
"last": { <2>
151+
"type": "text"
152+
}
153+
}
154+
},
155+
"user_id": {
156+
"type": "keyword",
157+
"ignore_above": 100 <3>
158+
}
159+
}
160+
}
161+
-----------------------------------
162+
// CONSOLE

rest-api-spec/src/main/resources/rest-api-spec/api/indices.create.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" : "string",
18+
"description" : "Whether a type should be expected in the body of the mappings."
19+
},
1620
"wait_for_active_shards": {
1721
"type" : "string",
1822
"description" : "Set the number of active shards to wait for before the operation returns."

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@
1616
}
1717
},
1818
"params": {
19+
"include_type_name": {
20+
"type" : "string",
21+
"description" : "Whether to add the type name to the response"
22+
},
1923
"ignore_unavailable": {
2024
"type" : "boolean",
2125
"description" : "Whether specified concrete indices should be ignored when unavailable (missing or closed)"

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

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,19 +4,22 @@
44
"methods": ["PUT", "POST"],
55
"url": {
66
"path": "/{index}/{type}/_mapping",
7-
"paths": ["/{index}/{type}/_mapping", "/{index}/_mapping/{type}", "/_mapping/{type}", "/{index}/{type}/_mappings", "/{index}/_mappings/{type}", "/_mappings/{type}"],
7+
"paths": ["/{index}/{type}/_mapping", "/{index}/_mapping/{type}", "/_mapping/{type}", "/{index}/{type}/_mappings", "/{index}/_mappings/{type}", "/_mappings/{type}", "{index}/_mappings", "{index}/_mapping"],
88
"parts": {
99
"index": {
1010
"type" : "list",
1111
"description" : "A comma-separated list of index names the mapping should be added to (supports wildcards); use `_all` or omit to add the mapping on all indices."
1212
},
1313
"type": {
1414
"type" : "string",
15-
"required" : true,
1615
"description" : "The name of the document type"
1716
}
1817
},
1918
"params": {
19+
"include_type_name": {
20+
"type" : "string",
21+
"description" : "Whether a type should be expected in the body of the mappings."
22+
},
2023
"timeout": {
2124
"type" : "time",
2225
"description" : "Explicit operation timeout"
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
---
2+
"Create indices and manage mappings without types":
3+
4+
- skip:
5+
version: " - 6.99.99"
6+
reason: include_type_name was introduced in 7.0.0
7+
8+
- do:
9+
indices.create:
10+
index: index
11+
include_type_name: false
12+
body:
13+
mappings:
14+
properties:
15+
foo:
16+
type: keyword
17+
18+
- do:
19+
indices.get_mapping:
20+
index: index
21+
include_type_name: false
22+
23+
- match: { index.mappings.properties.foo.type: "keyword" }
24+
25+
- do:
26+
indices.put_mapping:
27+
index: index
28+
include_type_name: false
29+
body:
30+
properties:
31+
bar:
32+
type: float
33+
34+
- do:
35+
indices.get_mapping:
36+
index: index
37+
include_type_name: false
38+
39+
- match: { index.mappings.properties.foo.type: "keyword" }
40+
- match: { index.mappings.properties.bar.type: "float" }
41+
42+
---
43+
"PUT mapping with a type and include_type_name: false":
44+
45+
- skip:
46+
version: " - 6.99.99"
47+
reason: include_type_name was introduced in 7.0.0
48+
49+
- do:
50+
indices.create:
51+
index: index
52+
53+
- do:
54+
catch: /illegal_argument_exception/
55+
indices.put_mapping:
56+
index: index
57+
type: _doc
58+
include_type_name: false
59+
body:
60+
properties:
61+
bar:
62+
type: float
63+
64+
---
65+
"Empty index with the include_type_name=false option":
66+
67+
- skip:
68+
version: " - 6.99.99"
69+
reason: include_type_name was introduced in 7.0.0
70+
71+
- do:
72+
indices.create:
73+
index: index
74+
include_type_name: false
75+
76+
- do:
77+
indices.get_mapping:
78+
index: index
79+
include_type_name: false
80+
81+
- match: { index.mappings: {} }

server/src/main/java/org/elasticsearch/rest/action/admin/indices/RestCreateIndexAction.java

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,18 @@
2323
import org.elasticsearch.action.support.ActiveShardCount;
2424
import org.elasticsearch.client.node.NodeClient;
2525
import org.elasticsearch.common.settings.Settings;
26+
import org.elasticsearch.common.xcontent.LoggingDeprecationHandler;
27+
import org.elasticsearch.common.xcontent.XContentHelper;
28+
import org.elasticsearch.index.mapper.MapperService;
2629
import org.elasticsearch.rest.BaseRestHandler;
2730
import org.elasticsearch.rest.RestController;
2831
import org.elasticsearch.rest.RestRequest;
2932
import org.elasticsearch.rest.action.RestToXContentListener;
3033

3134
import java.io.IOException;
35+
import java.util.Collections;
36+
import java.util.HashMap;
37+
import java.util.Map;
3238

3339
public class RestCreateIndexAction extends BaseRestHandler {
3440
public RestCreateIndexAction(Settings settings, RestController controller) {
@@ -43,9 +49,16 @@ public String getName() {
4349

4450
@Override
4551
public RestChannelConsumer prepareRequest(final RestRequest request, final NodeClient client) throws IOException {
52+
final boolean includeTypeName = request.paramAsBoolean("include_type_name", true);
4653
CreateIndexRequest createIndexRequest = new CreateIndexRequest(request.param("index"));
4754
if (request.hasContent()) {
48-
createIndexRequest.source(request.content(), request.getXContentType());
55+
Map<String, Object> sourceAsMap = XContentHelper.convertToMap(request.content(), false, request.getXContentType()).v2();
56+
if (includeTypeName == false && sourceAsMap.containsKey("mappings")) {
57+
Map<String, Object> newSourceAsMap = new HashMap<>(sourceAsMap);
58+
newSourceAsMap.put("mappings", Collections.singletonMap(MapperService.SINGLE_MAPPING_NAME, sourceAsMap.get("mappings")));
59+
sourceAsMap = newSourceAsMap;
60+
}
61+
createIndexRequest.source(sourceAsMap, LoggingDeprecationHandler.INSTANCE);
4962
}
5063
createIndexRequest.timeout(request.paramAsTime("timeout", createIndexRequest.timeout()));
5164
createIndexRequest.masterNodeTimeout(request.paramAsTime("master_timeout", createIndexRequest.masterNodeTimeout()));

server/src/main/java/org/elasticsearch/rest/action/admin/indices/RestGetMappingAction.java

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ public String getName() {
7777

7878
@Override
7979
public RestChannelConsumer prepareRequest(final RestRequest request, final NodeClient client) throws IOException {
80+
final boolean includeTypeName = request.paramAsBoolean("include_type_name", true);
8081
final String[] indices = Strings.splitStringByCommaToArray(request.param("index"));
8182
final String[] types = request.paramAsStringArrayOrEmptyIfAll("type");
8283
final GetMappingsRequest getMappingsRequest = new GetMappingsRequest();
@@ -141,13 +142,29 @@ public RestResponse buildResponse(final GetMappingsResponse response, final XCon
141142
for (final ObjectObjectCursor<String, ImmutableOpenMap<String, MappingMetaData>> indexEntry : mappingsByIndex) {
142143
builder.startObject(indexEntry.key);
143144
{
144-
builder.startObject("mappings");
145-
{
145+
if (includeTypeName == false) {
146+
MappingMetaData mappings = null;
146147
for (final ObjectObjectCursor<String, MappingMetaData> typeEntry : indexEntry.value) {
147-
builder.field(typeEntry.key, typeEntry.value.sourceAsMap());
148+
if (typeEntry.key.equals("_default_") == false) {
149+
assert mappings == null;
150+
mappings = typeEntry.value;
151+
}
148152
}
153+
if (mappings == null) {
154+
// no mappings yet
155+
builder.startObject("mappings").endObject();
156+
} else {
157+
builder.field("mappings", mappings.sourceAsMap());
158+
}
159+
} else {
160+
builder.startObject("mappings");
161+
{
162+
for (final ObjectObjectCursor<String, MappingMetaData> typeEntry : indexEntry.value) {
163+
builder.field(typeEntry.key, typeEntry.value.sourceAsMap());
164+
}
165+
}
166+
builder.endObject();
149167
}
150-
builder.endObject();
151168
}
152169
builder.endObject();
153170
}

server/src/main/java/org/elasticsearch/rest/action/admin/indices/RestPutMappingAction.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import org.elasticsearch.client.node.NodeClient;
2525
import org.elasticsearch.common.Strings;
2626
import org.elasticsearch.common.settings.Settings;
27+
import org.elasticsearch.index.mapper.MapperService;
2728
import org.elasticsearch.rest.BaseRestHandler;
2829
import org.elasticsearch.rest.RestController;
2930
import org.elasticsearch.rest.RestRequest;
@@ -67,8 +68,13 @@ public String getName() {
6768

6869
@Override
6970
public RestChannelConsumer prepareRequest(final RestRequest request, final NodeClient client) throws IOException {
71+
final boolean includeTypeName = request.paramAsBoolean("include_type_name", true);
7072
PutMappingRequest putMappingRequest = putMappingRequest(Strings.splitStringByCommaToArray(request.param("index")));
71-
putMappingRequest.type(request.param("type"));
73+
final String type = request.param("type");
74+
if (type != null && includeTypeName == false) {
75+
throw new IllegalArgumentException("Cannot set include_type_name=false and provide a type at the same time");
76+
}
77+
putMappingRequest.type(includeTypeName ? type : MapperService.SINGLE_MAPPING_NAME);
7278
putMappingRequest.source(request.requiredContent(), request.getXContentType());
7379
putMappingRequest.timeout(request.paramAsTime("timeout", putMappingRequest.timeout()));
7480
putMappingRequest.masterNodeTimeout(request.paramAsTime("master_timeout", putMappingRequest.masterNodeTimeout()));

0 commit comments

Comments
 (0)