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:
parent
45e7e24736
commit
6a6c0ea5e6
|
@ -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
|
A detailed explanation of `wait_for_active_shards` and its possible values can be found
|
||||||
<<index-wait-for-active-shards,here>>.
|
<<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
|
||||||
|
|
|
@ -41,3 +41,48 @@ GET /_mapping
|
||||||
--------------------------------------------------
|
--------------------------------------------------
|
||||||
// CONSOLE
|
// CONSOLE
|
||||||
// TEST[setup:twitter]
|
// 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
|
||||||
|
|
|
@ -109,3 +109,54 @@ PUT my_index/_mapping/_doc
|
||||||
|
|
||||||
Each <<mapping-params,mapping parameter>> specifies whether or not its setting
|
Each <<mapping-params,mapping parameter>> specifies whether or not its setting
|
||||||
can be updated on an existing field.
|
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
|
||||||
|
|
|
@ -13,6 +13,10 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"params": {
|
"params": {
|
||||||
|
"include_type_name": {
|
||||||
|
"type" : "string",
|
||||||
|
"description" : "Whether a type should be expected in the body of the mappings."
|
||||||
|
},
|
||||||
"wait_for_active_shards": {
|
"wait_for_active_shards": {
|
||||||
"type" : "string",
|
"type" : "string",
|
||||||
"description" : "Set the number of active shards to wait for before the operation returns."
|
"description" : "Set the number of active shards to wait for before the operation returns."
|
||||||
|
|
|
@ -16,6 +16,10 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"params": {
|
"params": {
|
||||||
|
"include_type_name": {
|
||||||
|
"type" : "string",
|
||||||
|
"description" : "Whether to add the type name to the response"
|
||||||
|
},
|
||||||
"ignore_unavailable": {
|
"ignore_unavailable": {
|
||||||
"type" : "boolean",
|
"type" : "boolean",
|
||||||
"description" : "Whether specified concrete indices should be ignored when unavailable (missing or closed)"
|
"description" : "Whether specified concrete indices should be ignored when unavailable (missing or closed)"
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
"methods": ["PUT", "POST"],
|
"methods": ["PUT", "POST"],
|
||||||
"url": {
|
"url": {
|
||||||
"path": "/{index}/{type}/_mapping",
|
"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": {
|
"parts": {
|
||||||
"index": {
|
"index": {
|
||||||
"type" : "list",
|
"type" : "list",
|
||||||
|
@ -12,11 +12,14 @@
|
||||||
},
|
},
|
||||||
"type": {
|
"type": {
|
||||||
"type" : "string",
|
"type" : "string",
|
||||||
"required" : true,
|
|
||||||
"description" : "The name of the document type"
|
"description" : "The name of the document type"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"params": {
|
"params": {
|
||||||
|
"include_type_name": {
|
||||||
|
"type" : "string",
|
||||||
|
"description" : "Whether a type should be expected in the body of the mappings."
|
||||||
|
},
|
||||||
"timeout": {
|
"timeout": {
|
||||||
"type" : "time",
|
"type" : "time",
|
||||||
"description" : "Explicit operation timeout"
|
"description" : "Explicit operation timeout"
|
||||||
|
|
|
@ -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: {} }
|
|
@ -23,12 +23,18 @@ import org.elasticsearch.action.admin.indices.create.CreateIndexRequest;
|
||||||
import org.elasticsearch.action.support.ActiveShardCount;
|
import org.elasticsearch.action.support.ActiveShardCount;
|
||||||
import org.elasticsearch.client.node.NodeClient;
|
import org.elasticsearch.client.node.NodeClient;
|
||||||
import org.elasticsearch.common.settings.Settings;
|
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.BaseRestHandler;
|
||||||
import org.elasticsearch.rest.RestController;
|
import org.elasticsearch.rest.RestController;
|
||||||
import org.elasticsearch.rest.RestRequest;
|
import org.elasticsearch.rest.RestRequest;
|
||||||
import org.elasticsearch.rest.action.RestToXContentListener;
|
import org.elasticsearch.rest.action.RestToXContentListener;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
public class RestCreateIndexAction extends BaseRestHandler {
|
public class RestCreateIndexAction extends BaseRestHandler {
|
||||||
public RestCreateIndexAction(Settings settings, RestController controller) {
|
public RestCreateIndexAction(Settings settings, RestController controller) {
|
||||||
|
@ -43,9 +49,16 @@ public class RestCreateIndexAction extends BaseRestHandler {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public RestChannelConsumer prepareRequest(final RestRequest request, final NodeClient client) throws IOException {
|
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"));
|
CreateIndexRequest createIndexRequest = new CreateIndexRequest(request.param("index"));
|
||||||
if (request.hasContent()) {
|
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.timeout(request.paramAsTime("timeout", createIndexRequest.timeout()));
|
||||||
createIndexRequest.masterNodeTimeout(request.paramAsTime("master_timeout", createIndexRequest.masterNodeTimeout()));
|
createIndexRequest.masterNodeTimeout(request.paramAsTime("master_timeout", createIndexRequest.masterNodeTimeout()));
|
||||||
|
|
|
@ -77,6 +77,7 @@ public class RestGetMappingAction extends BaseRestHandler {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public RestChannelConsumer prepareRequest(final RestRequest request, final NodeClient client) throws IOException {
|
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[] indices = Strings.splitStringByCommaToArray(request.param("index"));
|
||||||
final String[] types = request.paramAsStringArrayOrEmptyIfAll("type");
|
final String[] types = request.paramAsStringArrayOrEmptyIfAll("type");
|
||||||
final GetMappingsRequest getMappingsRequest = new GetMappingsRequest();
|
final GetMappingsRequest getMappingsRequest = new GetMappingsRequest();
|
||||||
|
@ -141,6 +142,21 @@ public class RestGetMappingAction extends BaseRestHandler {
|
||||||
for (final ObjectObjectCursor<String, ImmutableOpenMap<String, MappingMetaData>> indexEntry : mappingsByIndex) {
|
for (final ObjectObjectCursor<String, ImmutableOpenMap<String, MappingMetaData>> indexEntry : mappingsByIndex) {
|
||||||
builder.startObject(indexEntry.key);
|
builder.startObject(indexEntry.key);
|
||||||
{
|
{
|
||||||
|
if (includeTypeName == false) {
|
||||||
|
MappingMetaData mappings = null;
|
||||||
|
for (final ObjectObjectCursor<String, MappingMetaData> typeEntry : indexEntry.value) {
|
||||||
|
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");
|
builder.startObject("mappings");
|
||||||
{
|
{
|
||||||
for (final ObjectObjectCursor<String, MappingMetaData> typeEntry : indexEntry.value) {
|
for (final ObjectObjectCursor<String, MappingMetaData> typeEntry : indexEntry.value) {
|
||||||
|
@ -149,6 +165,7 @@ public class RestGetMappingAction extends BaseRestHandler {
|
||||||
}
|
}
|
||||||
builder.endObject();
|
builder.endObject();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
builder.endObject();
|
builder.endObject();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,6 +24,7 @@ import org.elasticsearch.action.support.IndicesOptions;
|
||||||
import org.elasticsearch.client.node.NodeClient;
|
import org.elasticsearch.client.node.NodeClient;
|
||||||
import org.elasticsearch.common.Strings;
|
import org.elasticsearch.common.Strings;
|
||||||
import org.elasticsearch.common.settings.Settings;
|
import org.elasticsearch.common.settings.Settings;
|
||||||
|
import org.elasticsearch.index.mapper.MapperService;
|
||||||
import org.elasticsearch.rest.BaseRestHandler;
|
import org.elasticsearch.rest.BaseRestHandler;
|
||||||
import org.elasticsearch.rest.RestController;
|
import org.elasticsearch.rest.RestController;
|
||||||
import org.elasticsearch.rest.RestRequest;
|
import org.elasticsearch.rest.RestRequest;
|
||||||
|
@ -67,8 +68,13 @@ public class RestPutMappingAction extends BaseRestHandler {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public RestChannelConsumer prepareRequest(final RestRequest request, final NodeClient client) throws IOException {
|
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 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.source(request.requiredContent(), request.getXContentType());
|
||||||
putMappingRequest.timeout(request.paramAsTime("timeout", putMappingRequest.timeout()));
|
putMappingRequest.timeout(request.paramAsTime("timeout", putMappingRequest.timeout()));
|
||||||
putMappingRequest.masterNodeTimeout(request.paramAsTime("master_timeout", putMappingRequest.masterNodeTimeout()));
|
putMappingRequest.masterNodeTimeout(request.paramAsTime("master_timeout", putMappingRequest.masterNodeTimeout()));
|
||||||
|
|
Loading…
Reference in New Issue