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
This commit is contained in:
Adrien Grand 2018-04-11 15:54:16 +02:00 committed by GitHub
parent 45e7e24736
commit 6a6c0ea5e6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 257 additions and 8 deletions

View File

@ -173,3 +173,28 @@ PUT test?wait_for_active_shards=2
A detailed explanation of `wait_for_active_shards` and its possible values can be found
<<index-wait-for-active-shards,here>>.
[float]
=== Skipping types
Types are scheduled to be fully removed in Elasticsearch 8.0 and will not appear
in requests or responses anymore. You can opt in for this future behaviour by
setting `include_type_name=false` and putting mappings directly under `mappings`
in the index creation call.
Here is an example:
[source,js]
--------------------------------------------------
PUT test?include_type_name=false
{
"mappings": {
"properties": {
"foo": {
"type": "keyword"
}
}
}
}
--------------------------------------------------
// CONSOLE

View File

@ -41,3 +41,48 @@ GET /_mapping
--------------------------------------------------
// CONSOLE
// TEST[setup:twitter]
[float]
=== Skipping types
Types are scheduled to be fully removed in Elasticsearch 8.0 and will not appear
in requests or responses anymore. You can opt in for this future behaviour by
setting `include_type_name=false` in the request, which will return mappings
directly under `mappings` without keying by the type name.
Here is an example:
[source,js]
--------------------------------------------------
PUT test?include_type_name=false
{
"mappings": {
"properties": {
"foo": {
"type": "keyword"
}
}
}
}
GET test/_mappings?include_type_name=false
--------------------------------------------------
// CONSOLE
which returns
[source,js]
--------------------------------------------------
{
"test": {
"mappings": {
"properties": {
"foo": {
"type": "keyword"
}
}
}
}
}
--------------------------------------------------
// TESTRESPONSE

View File

@ -109,3 +109,54 @@ PUT my_index/_mapping/_doc
Each <<mapping-params,mapping parameter>> specifies whether or not its setting
can be updated on an existing field.
[float]
=== Skipping types
Types are scheduled to be fully removed in Elasticsearch 8.0 and will not appear
in requests or responses anymore. You can opt in for this future behaviour by
setting `include_type_name=false`.
NOTE: This should only be done on indices that have been created with
`include_type_name=false` or that used `_doc` as a type name.
The Console script from the above section is equivalent to the below invocation:
[source,js]
-----------------------------------
PUT my_index?include_type_name=false <1>
{
"mappings": {
"properties": {
"name": {
"properties": {
"first": {
"type": "text"
}
}
},
"user_id": {
"type": "keyword"
}
}
}
}
PUT my_index/_mapping?include_type_name=false
{
"properties": {
"name": {
"properties": {
"last": { <2>
"type": "text"
}
}
},
"user_id": {
"type": "keyword",
"ignore_above": 100 <3>
}
}
}
-----------------------------------
// CONSOLE

View File

@ -13,6 +13,10 @@
}
},
"params": {
"include_type_name": {
"type" : "string",
"description" : "Whether a type should be expected in the body of the mappings."
},
"wait_for_active_shards": {
"type" : "string",
"description" : "Set the number of active shards to wait for before the operation returns."

View File

@ -16,6 +16,10 @@
}
},
"params": {
"include_type_name": {
"type" : "string",
"description" : "Whether to add the type name to the response"
},
"ignore_unavailable": {
"type" : "boolean",
"description" : "Whether specified concrete indices should be ignored when unavailable (missing or closed)"

View File

@ -4,7 +4,7 @@
"methods": ["PUT", "POST"],
"url": {
"path": "/{index}/{type}/_mapping",
"paths": ["/{index}/{type}/_mapping", "/{index}/_mapping/{type}", "/_mapping/{type}", "/{index}/{type}/_mappings", "/{index}/_mappings/{type}", "/_mappings/{type}"],
"paths": ["/{index}/{type}/_mapping", "/{index}/_mapping/{type}", "/_mapping/{type}", "/{index}/{type}/_mappings", "/{index}/_mappings/{type}", "/_mappings/{type}", "{index}/_mappings", "{index}/_mapping"],
"parts": {
"index": {
"type" : "list",
@ -12,11 +12,14 @@
},
"type": {
"type" : "string",
"required" : true,
"description" : "The name of the document type"
}
},
"params": {
"include_type_name": {
"type" : "string",
"description" : "Whether a type should be expected in the body of the mappings."
},
"timeout": {
"type" : "time",
"description" : "Explicit operation timeout"

View File

@ -0,0 +1,81 @@
---
"Create indices and manage mappings without types":
- skip:
version: " - 6.99.99"
reason: include_type_name was introduced in 7.0.0
- do:
indices.create:
index: index
include_type_name: false
body:
mappings:
properties:
foo:
type: keyword
- do:
indices.get_mapping:
index: index
include_type_name: false
- match: { index.mappings.properties.foo.type: "keyword" }
- do:
indices.put_mapping:
index: index
include_type_name: false
body:
properties:
bar:
type: float
- do:
indices.get_mapping:
index: index
include_type_name: false
- match: { index.mappings.properties.foo.type: "keyword" }
- match: { index.mappings.properties.bar.type: "float" }
---
"PUT mapping with a type and include_type_name: false":
- skip:
version: " - 6.99.99"
reason: include_type_name was introduced in 7.0.0
- do:
indices.create:
index: index
- do:
catch: /illegal_argument_exception/
indices.put_mapping:
index: index
type: _doc
include_type_name: false
body:
properties:
bar:
type: float
---
"Empty index with the include_type_name=false option":
- skip:
version: " - 6.99.99"
reason: include_type_name was introduced in 7.0.0
- do:
indices.create:
index: index
include_type_name: false
- do:
indices.get_mapping:
index: index
include_type_name: false
- match: { index.mappings: {} }

View File

@ -23,12 +23,18 @@ import org.elasticsearch.action.admin.indices.create.CreateIndexRequest;
import org.elasticsearch.action.support.ActiveShardCount;
import org.elasticsearch.client.node.NodeClient;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.LoggingDeprecationHandler;
import org.elasticsearch.common.xcontent.XContentHelper;
import org.elasticsearch.index.mapper.MapperService;
import org.elasticsearch.rest.BaseRestHandler;
import org.elasticsearch.rest.RestController;
import org.elasticsearch.rest.RestRequest;
import org.elasticsearch.rest.action.RestToXContentListener;
import java.io.IOException;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
public class RestCreateIndexAction extends BaseRestHandler {
public RestCreateIndexAction(Settings settings, RestController controller) {
@ -43,9 +49,16 @@ public class RestCreateIndexAction extends BaseRestHandler {
@Override
public RestChannelConsumer prepareRequest(final RestRequest request, final NodeClient client) throws IOException {
final boolean includeTypeName = request.paramAsBoolean("include_type_name", true);
CreateIndexRequest createIndexRequest = new CreateIndexRequest(request.param("index"));
if (request.hasContent()) {
createIndexRequest.source(request.content(), request.getXContentType());
Map<String, Object> sourceAsMap = XContentHelper.convertToMap(request.content(), false, request.getXContentType()).v2();
if (includeTypeName == false && sourceAsMap.containsKey("mappings")) {
Map<String, Object> newSourceAsMap = new HashMap<>(sourceAsMap);
newSourceAsMap.put("mappings", Collections.singletonMap(MapperService.SINGLE_MAPPING_NAME, sourceAsMap.get("mappings")));
sourceAsMap = newSourceAsMap;
}
createIndexRequest.source(sourceAsMap, LoggingDeprecationHandler.INSTANCE);
}
createIndexRequest.timeout(request.paramAsTime("timeout", createIndexRequest.timeout()));
createIndexRequest.masterNodeTimeout(request.paramAsTime("master_timeout", createIndexRequest.masterNodeTimeout()));

View File

@ -77,6 +77,7 @@ public class RestGetMappingAction extends BaseRestHandler {
@Override
public RestChannelConsumer prepareRequest(final RestRequest request, final NodeClient client) throws IOException {
final boolean includeTypeName = request.paramAsBoolean("include_type_name", true);
final String[] indices = Strings.splitStringByCommaToArray(request.param("index"));
final String[] types = request.paramAsStringArrayOrEmptyIfAll("type");
final GetMappingsRequest getMappingsRequest = new GetMappingsRequest();
@ -141,13 +142,29 @@ public class RestGetMappingAction extends BaseRestHandler {
for (final ObjectObjectCursor<String, ImmutableOpenMap<String, MappingMetaData>> indexEntry : mappingsByIndex) {
builder.startObject(indexEntry.key);
{
builder.startObject("mappings");
{
if (includeTypeName == false) {
MappingMetaData mappings = null;
for (final ObjectObjectCursor<String, MappingMetaData> typeEntry : indexEntry.value) {
builder.field(typeEntry.key, typeEntry.value.sourceAsMap());
if (typeEntry.key.equals("_default_") == false) {
assert mappings == null;
mappings = typeEntry.value;
}
}
if (mappings == null) {
// no mappings yet
builder.startObject("mappings").endObject();
} else {
builder.field("mappings", mappings.sourceAsMap());
}
} else {
builder.startObject("mappings");
{
for (final ObjectObjectCursor<String, MappingMetaData> typeEntry : indexEntry.value) {
builder.field(typeEntry.key, typeEntry.value.sourceAsMap());
}
}
builder.endObject();
}
builder.endObject();
}
builder.endObject();
}

View File

@ -24,6 +24,7 @@ import org.elasticsearch.action.support.IndicesOptions;
import org.elasticsearch.client.node.NodeClient;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.index.mapper.MapperService;
import org.elasticsearch.rest.BaseRestHandler;
import org.elasticsearch.rest.RestController;
import org.elasticsearch.rest.RestRequest;
@ -67,8 +68,13 @@ public class RestPutMappingAction extends BaseRestHandler {
@Override
public RestChannelConsumer prepareRequest(final RestRequest request, final NodeClient client) throws IOException {
final boolean includeTypeName = request.paramAsBoolean("include_type_name", true);
PutMappingRequest putMappingRequest = putMappingRequest(Strings.splitStringByCommaToArray(request.param("index")));
putMappingRequest.type(request.param("type"));
final String type = request.param("type");
if (type != null && includeTypeName == false) {
throw new IllegalArgumentException("Cannot set include_type_name=false and provide a type at the same time");
}
putMappingRequest.type(includeTypeName ? type : MapperService.SINGLE_MAPPING_NAME);
putMappingRequest.source(request.requiredContent(), request.getXContentType());
putMappingRequest.timeout(request.paramAsTime("timeout", putMappingRequest.timeout()));
putMappingRequest.masterNodeTimeout(request.paramAsTime("master_timeout", putMappingRequest.masterNodeTimeout()));