Skip to content

Commit

Permalink
Support 'include_type_name' in RestGetIndicesAction (#37267)
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
Christoph Büscher committed Jan 11, 2019
1 parent 02509c7 commit 6797844
Show file tree
Hide file tree
Showing 13 changed files with 262 additions and 31 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,8 @@ static Request getIndex(GetIndexRequest getIndexRequest) {
params.withIncludeDefaults(getIndexRequest.includeDefaults());
params.withHuman(getIndexRequest.humanReadable());
params.withMasterTimeout(getIndexRequest.masterNodeTimeout());
// Force "include_type_name" parameter since responses need to be compatible when coming from 7.0 nodes
params.withIncludeTypeName(true);

return request;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@
import org.elasticsearch.index.reindex.DeleteByQueryRequest;
import org.elasticsearch.index.reindex.ReindexRequest;
import org.elasticsearch.index.reindex.UpdateByQueryRequest;
import org.elasticsearch.rest.BaseRestHandler;
import org.elasticsearch.rest.action.search.RestSearchAction;
import org.elasticsearch.script.mustache.MultiSearchTemplateRequest;
import org.elasticsearch.script.mustache.SearchTemplateRequest;
Expand Down Expand Up @@ -930,6 +931,14 @@ Params withIncludeDefaults(boolean includeDefaults) {
return this;
}

Params withIncludeTypeName(boolean includeTypeName) {
if (includeTypeName) {
return putParam(BaseRestHandler.INCLUDE_TYPE_NAME_PARAMETER,
Boolean.toString(BaseRestHandler.DEFAULT_INCLUDE_TYPE_NAME_POLICY));
}
return this;
}

Params withPreserveExisting(boolean preserveExisting) {
if (preserveExisting) {
return putParam("preserve_existing", Boolean.TRUE.toString());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,6 @@
import org.elasticsearch.action.admin.indices.mapping.put.PutMappingRequest;
import org.elasticsearch.action.admin.indices.open.OpenIndexRequest;
import org.elasticsearch.action.admin.indices.open.OpenIndexResponse;
import org.elasticsearch.action.support.ActiveShardCount;
import org.elasticsearch.action.admin.indices.refresh.RefreshRequest;
import org.elasticsearch.action.admin.indices.refresh.RefreshResponse;
import org.elasticsearch.action.admin.indices.rollover.RolloverRequest;
Expand All @@ -67,6 +66,7 @@
import org.elasticsearch.action.admin.indices.validate.query.ValidateQueryRequest;
import org.elasticsearch.action.admin.indices.validate.query.ValidateQueryResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.support.ActiveShardCount;
import org.elasticsearch.action.support.IndicesOptions;
import org.elasticsearch.action.support.WriteRequest;
import org.elasticsearch.action.support.broadcast.BroadcastResponse;
Expand All @@ -90,6 +90,7 @@
import org.elasticsearch.common.xcontent.json.JsonXContent;
import org.elasticsearch.common.xcontent.support.XContentMapValues;
import org.elasticsearch.index.IndexSettings;
import org.elasticsearch.index.mapper.MapperService;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.rest.RestStatus;
Expand Down Expand Up @@ -217,7 +218,7 @@ public void testCreateIndex() throws IOException {
mappingBuilder.startObject().startObject("properties").startObject("field");
mappingBuilder.field("type", "text");
mappingBuilder.endObject().endObject().endObject();
createIndexRequest.mapping("type_name", mappingBuilder);
createIndexRequest.mapping(MapperService.SINGLE_MAPPING_NAME, mappingBuilder);

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

assertEquals("text", XContentMapValues.extractValue(indexName + ".mappings.type_name.properties.field.type", getIndexResponse));
assertEquals("text", XContentMapValues.extractValue(indexName + ".mappings._doc.properties.field.type", getIndexResponse));
}
}

Expand Down Expand Up @@ -349,7 +350,7 @@ public void testGetIndex() throws IOException {
.put(SETTING_NUMBER_OF_SHARDS, 1)
.put(SETTING_NUMBER_OF_REPLICAS, 0)
.build();
String mappings = "\"type-1\":{\"properties\":{\"field-1\":{\"type\":\"integer\"}}}";
String mappings = "\"_doc\":{\"properties\":{\"field-1\":{\"type\":\"integer\"}}}";
createIndex(indexName, basicSettings, mappings);

GetIndexRequest getIndexRequest = new GetIndexRequest()
Expand All @@ -362,8 +363,8 @@ public void testGetIndex() throws IOException {
assertEquals("1", getIndexResponse.getSetting(indexName, SETTING_NUMBER_OF_SHARDS));
assertEquals("0", getIndexResponse.getSetting(indexName, SETTING_NUMBER_OF_REPLICAS));
assertNotNull(getIndexResponse.getMappings().get(indexName));
assertNotNull(getIndexResponse.getMappings().get(indexName).get("type-1"));
Object o = getIndexResponse.getMappings().get(indexName).get("type-1").getSourceAsMap().get("properties");
assertNotNull(getIndexResponse.getMappings().get(indexName).get("_doc"));
Object o = getIndexResponse.getMappings().get(indexName).get("_doc").getSourceAsMap().get("properties");
assertThat(o, instanceOf(Map.class));
//noinspection unchecked
assertThat(((Map<String, Object>) o).get("field-1"), instanceOf(Map.class));
Expand All @@ -379,7 +380,7 @@ public void testGetIndexWithDefaults() throws IOException {
.put(SETTING_NUMBER_OF_SHARDS, 1)
.put(SETTING_NUMBER_OF_REPLICAS, 0)
.build();
String mappings = "\"type-1\":{\"properties\":{\"field-1\":{\"type\":\"integer\"}}}";
String mappings = "\"_doc\":{\"properties\":{\"field-1\":{\"type\":\"integer\"}}}";
createIndex(indexName, basicSettings, mappings);

GetIndexRequest getIndexRequest = new GetIndexRequest()
Expand All @@ -393,8 +394,8 @@ public void testGetIndexWithDefaults() throws IOException {
assertEquals("1", getIndexResponse.getSetting(indexName, SETTING_NUMBER_OF_SHARDS));
assertEquals("0", getIndexResponse.getSetting(indexName, SETTING_NUMBER_OF_REPLICAS));
assertNotNull(getIndexResponse.getMappings().get(indexName));
assertNotNull(getIndexResponse.getMappings().get(indexName).get("type-1"));
Object o = getIndexResponse.getMappings().get(indexName).get("type-1").getSourceAsMap().get("properties");
assertNotNull(getIndexResponse.getMappings().get(indexName).get("_doc"));
Object o = getIndexResponse.getMappings().get(indexName).get("_doc").getSourceAsMap().get("properties");
assertThat(o, instanceOf(Map.class));
assertThat(((Map<String, Object>) o).get("field-1"), instanceOf(Map.class));
Map<String, Object> fieldMapping = (Map<String, Object>) ((Map<String, Object>) o).get("field-1");
Expand All @@ -417,7 +418,7 @@ public void testPutMapping() throws IOException {
createIndex(indexName, Settings.EMPTY);

PutMappingRequest putMappingRequest = new PutMappingRequest(indexName);
putMappingRequest.type("type_name");
putMappingRequest.type("_doc");
XContentBuilder mappingBuilder = JsonXContent.contentBuilder();
mappingBuilder.startObject().startObject("properties").startObject("field");
mappingBuilder.field("type", "text");
Expand All @@ -430,7 +431,7 @@ public void testPutMapping() throws IOException {
assertTrue(putMappingResponse.isAcknowledged());

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

public void testGetMapping() throws IOException {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.util.CollectionUtils;
import org.elasticsearch.index.RandomCreateIndexGenerator;
import org.elasticsearch.rest.BaseRestHandler;
import org.elasticsearch.test.ESTestCase;
import org.junit.Assert;

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

if (ESTestCase.randomBoolean()) {
// the request object will not have include_defaults present unless it is set to
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,15 +70,15 @@
import org.elasticsearch.action.support.IndicesOptions;
import org.elasticsearch.action.support.master.AcknowledgedResponse;
import org.elasticsearch.client.ESRestHighLevelClientTestCase;
import org.elasticsearch.client.indices.FreezeIndexRequest;
import org.elasticsearch.client.GetAliasesResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.SyncedFlushResponse;
import org.elasticsearch.client.core.ShardsAcknowledgedResponse;
import org.elasticsearch.client.indices.FreezeIndexRequest;
import org.elasticsearch.client.indices.GetIndexTemplatesRequest;
import org.elasticsearch.client.indices.IndexTemplatesExistRequest;
import org.elasticsearch.client.indices.UnfreezeIndexRequest;
import org.elasticsearch.client.core.ShardsAcknowledgedResponse;
import org.elasticsearch.cluster.metadata.AliasMetaData;
import org.elasticsearch.cluster.metadata.IndexTemplateMetaData;
import org.elasticsearch.cluster.metadata.AliasMetaData;
Expand Down Expand Up @@ -1246,7 +1246,7 @@ public void testGetIndex() throws Exception {
Settings settings = Settings.builder().put("number_of_shards", 3).build();
String mappings = "{\"properties\":{\"field-1\":{\"type\":\"integer\"}}}";
CreateIndexResponse createIndexResponse = client.indices().create(
new CreateIndexRequest("index", settings).mapping("doc", mappings, XContentType.JSON),
new CreateIndexRequest("index", settings).mapping("_doc", mappings, XContentType.JSON),
RequestOptions.DEFAULT);
assertTrue(createIndexResponse.isAcknowledged());
}
Expand All @@ -1269,7 +1269,7 @@ public void testGetIndex() throws Exception {

// tag::get-index-response
ImmutableOpenMap<String, MappingMetaData> indexMappings = getIndexResponse.getMappings().get("index"); // <1>
Map<String, Object> indexTypeMappings = indexMappings.get("doc").getSourceAsMap(); // <2>
Map<String, Object> indexTypeMappings = indexMappings.get("_doc").getSourceAsMap(); // <2>
List<AliasMetaData> indexAliases = getIndexResponse.getAliases().get("index"); // <3>
String numberOfShardsString = getIndexResponse.getSetting("index", "index.number_of_shards"); // <4>
Settings indexSettings = getIndexResponse.getSettings().get("index"); // <5>
Expand Down
68 changes: 68 additions & 0 deletions docs/reference/indices/get-index.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,71 @@ alias or wildcard expression is required.

The get index API can also be applied to more than one index, or on
all indices by using `_all` or `*` as index.

[float]
=== Skipping types

Types are being removed from Elasticsearch: in 7.0, the `mappings` element will no
longer return the type name as a top-level key by default. You can already opt in for
this behavior by setting `include_type_name=false` on the request.

NOTE: Such calls will be rejected on indices that have multiple types as it
introduces ambiguity as to which mapping should be returned. Only indices
created by Elasticsearch 5.x may have multiple types.

Here is an example:

[source,js]
--------------------------------------------------
GET twitter?include_type_name=false
--------------------------------------------------
// CONSOLE
// TEST[setup:twitter]

which returns

[source,js]
--------------------------------------------------
{
"twitter": {
"aliases": {},
"mappings" : {
"properties" : {
"date" : {
"type" : "date"
},
"likes" : {
"type" : "long"
},
"message" : {
"type" : "text",
"fields" : {
"keyword" : {
"type" : "keyword",
"ignore_above" : 256
}
}
},
"user" : {
"type" : "keyword"
}
}
},
"settings": {
"index": {
"creation_date": "1547028674905",
"number_of_shards": "1",
"number_of_replicas": "1",
"uuid": "u1YpkPqLSqGIn3kNAvY8cA",
"version": {
"created": ...
},
"provided_name": "twitter"
}
}
}
}
--------------------------------------------------
// TESTRESPONSE[s/1547028674905/$body.twitter.settings.index.creation_date/]
// TESTRESPONSE[s/u1YpkPqLSqGIn3kNAvY8cA/$body.twitter.settings.index.uuid/]
// TESTRESPONSE[s/"created": \.\.\./"created": $body.twitter.settings.index.version.created/]
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@
}
},
"params":{
"include_type_name": {
"type" : "boolean",
"description" : "Whether to add the type name to the response (default: true)"
},
"local":{
"type":"boolean",
"description":"Return local information, do not retrieve the state from master node (default: false)"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,35 @@ setup:
- is_true: test_index.settings
- is_true: test_index.mappings

---
"Test include_type_name":
- skip:
version: " - 6.6.99"
reason: the include_type_name parameter is not supported before 6.7

- do:
indices.get:
index: test_index

- is_true: test_index.mappings
- is_true: test_index.mappings.type_1

- do:
indices.get:
include_type_name: true
index: test_index

- is_true: test_index.mappings
- is_true: test_index.mappings.type_1

- do:
indices.get:
include_type_name: false
index: test_index

- is_true: test_index.mappings
- is_false: test_index.mappings.type_1

---
"Get index infos should work for wildcards":

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
package org.elasticsearch.action.admin.indices.get;

import com.carrotsearch.hppc.cursors.ObjectObjectCursor;

import org.apache.lucene.util.CollectionUtil;
import org.elasticsearch.Version;
import org.elasticsearch.action.ActionResponse;
Expand All @@ -34,6 +35,8 @@
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.common.xcontent.XContentParser.Token;
import org.elasticsearch.index.mapper.MapperService;
import org.elasticsearch.rest.BaseRestHandler;

import java.io.IOException;
import java.util.ArrayList;
Expand All @@ -44,6 +47,7 @@
import java.util.Objects;

import static org.elasticsearch.common.xcontent.XContentParserUtils.ensureExpectedToken;
import static org.elasticsearch.rest.BaseRestHandler.INCLUDE_TYPE_NAME_PARAMETER;

/**
* A response for a get index action.
Expand Down Expand Up @@ -249,15 +253,34 @@ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws
}
builder.endObject();

builder.startObject("mappings");
ImmutableOpenMap<String, MappingMetaData> indexMappings = mappings.get(index);
if (indexMappings != null) {
// the default on 6.x should be true to include types in the response
boolean includeTypeName = params.paramAsBoolean(INCLUDE_TYPE_NAME_PARAMETER,
BaseRestHandler.DEFAULT_INCLUDE_TYPE_NAME_POLICY);
if (includeTypeName) {
builder.startObject("mappings");
if (indexMappings != null) {
for (final ObjectObjectCursor<String, MappingMetaData> typeEntry : indexMappings) {
builder.field(typeEntry.key);
builder.map(typeEntry.value.sourceAsMap());
}
}
builder.endObject();
} else {
MappingMetaData mappings = null;
for (final ObjectObjectCursor<String, MappingMetaData> typeEntry : indexMappings) {
builder.field(typeEntry.key);
builder.map(typeEntry.value.sourceAsMap());
if (typeEntry.key.equals(MapperService.DEFAULT_MAPPING) == false) {
assert mappings == null;
mappings = typeEntry.value;
}
}
if (mappings == null) {
// no mappings yet
builder.startObject("mappings").endObject();
} else {
builder.field("mappings", mappings.sourceAsMap());
}
}
builder.endObject();

builder.startObject("settings");
Settings indexSettings = settings.get(index);
Expand Down
Loading

0 comments on commit 6797844

Please sign in to comment.