From 5446f57ea00b5b67fb379f3c8e80fa1199153613 Mon Sep 17 00:00:00 2001 From: Julie Tibshirani Date: Tue, 8 Jan 2019 16:32:48 -0800 Subject: [PATCH 1/9] Deprecate types in the put mapping API. --- .../admin/indices/RestPutMappingAction.java | 14 +++- .../indices/RestPutMappingActionTests.java | 77 +++++++++++++++++++ 2 files changed, 90 insertions(+), 1 deletion(-) create mode 100644 server/src/test/java/org/elasticsearch/rest/action/admin/indices/RestPutMappingActionTests.java diff --git a/server/src/main/java/org/elasticsearch/rest/action/admin/indices/RestPutMappingAction.java b/server/src/main/java/org/elasticsearch/rest/action/admin/indices/RestPutMappingAction.java index 525b398d48b7a..b8e76b6a6bc01 100644 --- a/server/src/main/java/org/elasticsearch/rest/action/admin/indices/RestPutMappingAction.java +++ b/server/src/main/java/org/elasticsearch/rest/action/admin/indices/RestPutMappingAction.java @@ -19,10 +19,12 @@ package org.elasticsearch.rest.action.admin.indices; +import org.apache.logging.log4j.LogManager; import org.elasticsearch.action.admin.indices.mapping.put.PutMappingRequest; import org.elasticsearch.action.support.IndicesOptions; import org.elasticsearch.client.node.NodeClient; import org.elasticsearch.common.Strings; +import org.elasticsearch.common.logging.DeprecationLogger; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.index.mapper.MapperService; import org.elasticsearch.rest.BaseRestHandler; @@ -37,6 +39,11 @@ import static org.elasticsearch.rest.RestRequest.Method.PUT; public class RestPutMappingAction extends BaseRestHandler { + private static final DeprecationLogger deprecationLogger = new DeprecationLogger( + LogManager.getLogger(RestPutMappingAction.class)); + static final String TYPES_DEPRECATION_MESSAGE = "[types removal] Using include_type_name in put " + + "mapping requests is deprecated. The parameter will be removed in the next major version."; + public RestPutMappingAction(Settings settings, RestController controller) { super(settings); controller.registerHandler(PUT, "/{index}/_mapping/", this); @@ -70,12 +77,17 @@ public String getName() { public RestChannelConsumer prepareRequest(final RestRequest request, final NodeClient client) throws IOException { final boolean includeTypeName = request.paramAsBoolean(INCLUDE_TYPE_NAME_PARAMETER, DEFAULT_INCLUDE_TYPE_NAME_POLICY); - PutMappingRequest putMappingRequest = putMappingRequest(Strings.splitStringByCommaToArray(request.param("index"))); + if (request.hasParam(INCLUDE_TYPE_NAME_PARAMETER)) { + deprecationLogger.deprecatedAndMaybeLog("put_mapping_with_types", TYPES_DEPRECATION_MESSAGE); + } + final String type = request.param("type"); if (type != null && includeTypeName == false) { throw new IllegalArgumentException("Types cannot be provided in put mapping requests, unless " + "the include_type_name parameter is set to true."); } + + PutMappingRequest putMappingRequest = putMappingRequest(Strings.splitStringByCommaToArray(request.param("index"))); putMappingRequest.type(includeTypeName ? type : MapperService.SINGLE_MAPPING_NAME); putMappingRequest.source(request.requiredContent(), request.getXContentType()); putMappingRequest.timeout(request.paramAsTime("timeout", putMappingRequest.timeout())); diff --git a/server/src/test/java/org/elasticsearch/rest/action/admin/indices/RestPutMappingActionTests.java b/server/src/test/java/org/elasticsearch/rest/action/admin/indices/RestPutMappingActionTests.java new file mode 100644 index 0000000000000..daa69c20007f1 --- /dev/null +++ b/server/src/test/java/org/elasticsearch/rest/action/admin/indices/RestPutMappingActionTests.java @@ -0,0 +1,77 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.rest.action.admin.indices; + +import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.common.util.concurrent.ThreadContext; +import org.elasticsearch.rest.RestRequest; +import org.elasticsearch.rest.RestStatus; +import org.elasticsearch.test.rest.FakeRestChannel; +import org.elasticsearch.test.rest.FakeRestRequest; +import org.elasticsearch.test.rest.RestActionTestCase; +import org.junit.Before; + +import java.util.HashMap; +import java.util.Map; + +import static org.elasticsearch.rest.BaseRestHandler.INCLUDE_TYPE_NAME_PARAMETER; + +public class RestPutMappingActionTests extends RestActionTestCase { + + @Before + public void setUpAction() { + new RestPutMappingAction(Settings.EMPTY, controller()); + } + + public void testIncludeTypeName() { + Map params = new HashMap<>(); + params.put(INCLUDE_TYPE_NAME_PARAMETER, randomFrom("true", "false")); + RestRequest deprecatedRequest = new FakeRestRequest.Builder(xContentRegistry()) + .withMethod(RestRequest.Method.PUT) + .withPath("/some_index/_mapping/") + .withParams(params) + .build(); + + dispatchRequest(deprecatedRequest); + assertWarnings(RestPutMappingAction.TYPES_DEPRECATION_MESSAGE); + + RestRequest validRequest = new FakeRestRequest.Builder(xContentRegistry()) + .withMethod(RestRequest.Method.PUT) + .withPath("/some_index/_mapping") + .build(); + dispatchRequest(validRequest); + } + + public void testTypeInPath() { + // Test that specifying a type while include_type_name is false + // results in an illegal argument exception. + RestRequest request = new FakeRestRequest.Builder(xContentRegistry()) + .withMethod(RestRequest.Method.PUT) + .withPath("/some_index/_mapping/some_type") + .build(); + + FakeRestChannel channel = new FakeRestChannel(request, false, 1); + ThreadContext threadContext = new ThreadContext(Settings.EMPTY); + controller().dispatchRequest(request, channel, threadContext); + + assertEquals(1, channel.errors().get()); + assertEquals(RestStatus.BAD_REQUEST, channel.capturedResponse().status()); + } +} From 79a17d6e2dc64c74b757237a879e11af80435d65 Mon Sep 17 00:00:00 2001 From: Julie Tibshirani Date: Tue, 15 Jan 2019 13:57:29 -0800 Subject: [PATCH 2/9] Remove a REST test that is already covered by a unit test. --- .../test/indices.put_mapping/10_basic.yml | 22 ------------------- 1 file changed, 22 deletions(-) diff --git a/rest-api-spec/src/main/resources/rest-api-spec/test/indices.put_mapping/10_basic.yml b/rest-api-spec/src/main/resources/rest-api-spec/test/indices.put_mapping/10_basic.yml index 443e33d2c33a4..cdf64b07f9110 100644 --- a/rest-api-spec/src/main/resources/rest-api-spec/test/indices.put_mapping/10_basic.yml +++ b/rest-api-spec/src/main/resources/rest-api-spec/test/indices.put_mapping/10_basic.yml @@ -70,25 +70,3 @@ properties: "": type: keyword - ---- -"PUT mapping with a type and include_type_name: false": - - - skip: - version: " - 6.99.99" - reason: include_type_name defaults to true before 7.0 - - do: - indices.create: - index: index - include_type_name: false - - - do: - catch: /illegal_argument_exception/ - indices.put_mapping: - index: index - type: _doc - body: - properties: - bar: - type: float - From 49964a0d9896fad14549473637977185301ca829 Mon Sep 17 00:00:00 2001 From: Julie Tibshirani Date: Tue, 8 Jan 2019 17:12:45 -0800 Subject: [PATCH 3/9] Add a typeless put mapping method to the HLRC. --- .../elasticsearch/client/IndicesClient.java | 40 +++- .../client/IndicesRequestConverters.java | 17 +- .../client/indices/PutMappingRequest.java | 224 ++++++++++++++++++ .../elasticsearch/client/IndicesClientIT.java | 42 +++- .../client/IndicesRequestConvertersTests.java | 28 ++- .../IndicesClientDocumentationIT.java | 19 +- .../indices/PutMappingRequestTests.java | 77 ++++++ .../high-level/indices/put_mapping.asciidoc | 5 +- .../admin/indices/RestPutMappingAction.java | 2 +- .../mapping/put/PutMappingRequestTests.java | 7 +- .../index/RandomCreateIndexGenerator.java | 18 ++ 11 files changed, 440 insertions(+), 39 deletions(-) create mode 100644 client/rest-high-level/src/main/java/org/elasticsearch/client/indices/PutMappingRequest.java create mode 100644 client/rest-high-level/src/test/java/org/elasticsearch/client/indices/PutMappingRequestTests.java diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/IndicesClient.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/IndicesClient.java index 325d22fa9a0dd..92220aa2a658b 100644 --- a/client/rest-high-level/src/main/java/org/elasticsearch/client/IndicesClient.java +++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/IndicesClient.java @@ -41,7 +41,6 @@ import org.elasticsearch.action.admin.indices.mapping.get.GetFieldMappingsResponse; import org.elasticsearch.action.admin.indices.mapping.get.GetMappingsRequest; import org.elasticsearch.action.admin.indices.mapping.get.GetMappingsResponse; -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.admin.indices.refresh.RefreshRequest; @@ -63,6 +62,7 @@ import org.elasticsearch.client.indices.FreezeIndexRequest; import org.elasticsearch.client.indices.GetIndexTemplatesRequest; import org.elasticsearch.client.indices.IndexTemplatesExistRequest; +import org.elasticsearch.client.indices.PutMappingRequest; import org.elasticsearch.client.indices.UnfreezeIndexRequest; import org.elasticsearch.rest.RestStatus; @@ -166,6 +166,44 @@ public void putMappingAsync(PutMappingRequest putMappingRequest, RequestOptions AcknowledgedResponse::fromXContent, listener, emptySet()); } + /** + * Updates the mappings on an index using the Put Mapping API. + * See + * Put Mapping API on elastic.co + * @param putMappingRequest the request + * @param options the request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized + * @return the response + * @throws IOException in case there is a problem sending the request or parsing back the response + * + * @deprecated This method uses an old request object which still refers to types, a deprecated feature. The method + * {@link #putMapping(PutMappingRequest, RequestOptions)} should be used instead, which accepts a new request object. + */ + @Deprecated + public AcknowledgedResponse putMapping(org.elasticsearch.action.admin.indices.mapping.put.PutMappingRequest putMappingRequest, + RequestOptions options) throws IOException { + return restHighLevelClient.performRequestAndParseEntity(putMappingRequest, IndicesRequestConverters::putMapping, options, + AcknowledgedResponse::fromXContent, emptySet()); + } + + /** + * Asynchronously updates the mappings on an index using the Put Mapping API. + * See + * Put Mapping API on elastic.co + * @param putMappingRequest the request + * @param options the request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized + * @param listener the listener to be notified upon request completion + * + * @deprecated This method uses an old request object which still refers to types, a deprecated feature. The method + * {@link #putMapping(PutMappingRequest, RequestOptions)} should be used instead, which accepts a new request object. + */ + @Deprecated + public void putMappingAsync(org.elasticsearch.action.admin.indices.mapping.put.PutMappingRequest putMappingRequest, + RequestOptions options, + ActionListener listener) { + restHighLevelClient.performRequestAsyncAndParseEntity(putMappingRequest, IndicesRequestConverters::putMapping, options, + AcknowledgedResponse::fromXContent, listener, emptySet()); + } + /** * Retrieves the mappings on an index or indices using the Get Mapping API. * See diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/IndicesRequestConverters.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/IndicesRequestConverters.java index 79b0646770845..fb4a3f4871ccf 100644 --- a/client/rest-high-level/src/main/java/org/elasticsearch/client/IndicesRequestConverters.java +++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/IndicesRequestConverters.java @@ -37,7 +37,6 @@ import org.elasticsearch.action.admin.indices.get.GetIndexRequest; import org.elasticsearch.action.admin.indices.mapping.get.GetFieldMappingsRequest; import org.elasticsearch.action.admin.indices.mapping.get.GetMappingsRequest; -import org.elasticsearch.action.admin.indices.mapping.put.PutMappingRequest; import org.elasticsearch.action.admin.indices.open.OpenIndexRequest; import org.elasticsearch.action.admin.indices.refresh.RefreshRequest; import org.elasticsearch.action.admin.indices.rollover.RolloverRequest; @@ -51,6 +50,7 @@ import org.elasticsearch.client.indices.FreezeIndexRequest; import org.elasticsearch.client.indices.GetIndexTemplatesRequest; import org.elasticsearch.client.indices.IndexTemplatesExistRequest; +import org.elasticsearch.client.indices.PutMappingRequest; import org.elasticsearch.client.indices.UnfreezeIndexRequest; import org.elasticsearch.common.Strings; @@ -122,14 +122,25 @@ static Request updateAliases(IndicesAliasesRequest indicesAliasesRequest) throws return request; } + static Request putMapping(PutMappingRequest putMappingRequest) throws IOException { + Request request = new Request(HttpPut.METHOD_NAME, RequestConverters.endpoint(putMappingRequest.indices(), "_mapping")); + + RequestConverters.Params parameters = new RequestConverters.Params(request); + parameters.withTimeout(putMappingRequest.timeout()); + parameters.withMasterTimeout(putMappingRequest.masterNodeTimeout()); + request.setEntity(RequestConverters.createEntity(putMappingRequest, RequestConverters.REQUEST_BODY_CONTENT_TYPE)); + return request; + } + + static Request putMapping(org.elasticsearch.action.admin.indices.mapping.put.PutMappingRequest putMappingRequest) throws IOException { // The concreteIndex is an internal concept, not applicable to requests made over the REST API. if (putMappingRequest.getConcreteIndex() != null) { throw new IllegalArgumentException("concreteIndex cannot be set on PutMapping requests made over the REST API"); } - Request request = new Request(HttpPut.METHOD_NAME, RequestConverters.endpoint(putMappingRequest.indices(), "_mapping", - putMappingRequest.type())); + Request request = new Request(HttpPut.METHOD_NAME, RequestConverters.endpoint(putMappingRequest.indices(), + "_mapping", putMappingRequest.type())); RequestConverters.Params parameters = new RequestConverters.Params(request); parameters.withTimeout(putMappingRequest.timeout()); diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/indices/PutMappingRequest.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/indices/PutMappingRequest.java new file mode 100644 index 0000000000000..ed62c41075b95 --- /dev/null +++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/indices/PutMappingRequest.java @@ -0,0 +1,224 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.client.indices; + +import com.carrotsearch.hppc.ObjectHashSet; +import org.elasticsearch.ElasticsearchGenerationException; +import org.elasticsearch.action.IndicesRequest; +import org.elasticsearch.action.support.IndicesOptions; +import org.elasticsearch.client.TimedRequest; +import org.elasticsearch.common.Strings; +import org.elasticsearch.common.bytes.BytesArray; +import org.elasticsearch.common.bytes.BytesReference; +import org.elasticsearch.common.xcontent.ToXContent; +import org.elasticsearch.common.xcontent.ToXContentObject; +import org.elasticsearch.common.xcontent.XContentBuilder; +import org.elasticsearch.common.xcontent.XContentFactory; +import org.elasticsearch.common.xcontent.XContentType; + +import java.io.IOException; +import java.io.InputStream; +import java.util.Map; + +/** + * Put a mapping definition into one or more indices. If an index already contains mappings, + * the new mappings will be merged with the existing one. If there are elements that cannot + * be merged, the request will be rejected. + */ +public class PutMappingRequest extends TimedRequest implements IndicesRequest, ToXContentObject { + + private static ObjectHashSet RESERVED_FIELDS = ObjectHashSet.from( + "_uid", "_id", "_type", "_source", "_all", "_analyzer", "_parent", "_routing", "_index", + "_size", "_timestamp", "_ttl", "_field_names" + ); + + private final String[] indices; + private IndicesOptions indicesOptions = IndicesOptions.fromOptions(false, false, true, true); + + private BytesReference source; + private XContentType xContentType; + + /** + * Constructs a new put mapping request against one or more indices. If no indices + * are provided then it will be executed against all indices. + */ + public PutMappingRequest(String... indices) { + this.indices = indices; + } + + /** + * The indices into which the mappings will be put. + */ + @Override + public String[] indices() { + return indices; + } + + @Override + public IndicesOptions indicesOptions() { + return indicesOptions; + } + + public PutMappingRequest indicesOptions(IndicesOptions indicesOptions) { + this.indicesOptions = indicesOptions; + return this; + } + + /** + * The mapping source definition. + */ + public BytesReference source() { + return source; + } + + /** + * The {@link XContentType} of the mapping source. + */ + public XContentType xContentType() { + return xContentType; + } + + /** + * A specialized simplified mapping source method, takes the form of simple properties definition: + * ("field1", "type=string,store=true"). + * + * Also supports metadata mapping fields such as `_all` and `_parent` as property definition, these metadata + * mapping fields will automatically be put on the top level mapping object. + */ + public PutMappingRequest source(Object... source) { + return source(buildFromSimplifiedDef(source)); + } + + /** + * @param source A list of objects representing field andproperties pairs (e.g. "field", "type=keyword"). + * + * @throws IllegalArgumentException if the number of the source arguments is not divisible by two. + * @return the mappings definition + */ + private static XContentBuilder buildFromSimplifiedDef(Object... source) { + if (source.length % 2 != 0) { + throw new IllegalArgumentException("mapping source must be pairs of field names and properties definitions."); + } + try { + XContentBuilder builder = XContentFactory.jsonBuilder(); + builder.startObject(); + + for (int i = 0; i < source.length; i++) { + String fieldName = source[i++].toString(); + if (RESERVED_FIELDS.contains(fieldName)) { + builder.startObject(fieldName); + String[] s1 = Strings.splitStringByCommaToArray(source[i].toString()); + for (String s : s1) { + String[] s2 = Strings.split(s, "="); + if (s2.length != 2) { + throw new IllegalArgumentException("malformed " + s); + } + builder.field(s2[0], s2[1]); + } + builder.endObject(); + } + } + + builder.startObject("properties"); + for (int i = 0; i < source.length; i++) { + String fieldName = source[i++].toString(); + if (RESERVED_FIELDS.contains(fieldName)) { + continue; + } + + builder.startObject(fieldName); + String[] s1 = Strings.splitStringByCommaToArray(source[i].toString()); + for (String s : s1) { + String[] s2 = Strings.split(s, "="); + if (s2.length != 2) { + throw new IllegalArgumentException("malformed " + s); + } + builder.field(s2[0], s2[1]); + } + builder.endObject(); + } + builder.endObject(); + builder.endObject(); + return builder; + } catch (Exception e) { + throw new IllegalArgumentException("failed to generate simplified mapping definition", e); + } + } + + /** + * The mapping source definition. + * + * Note that the definition should *not* be nested under a type name. + */ + public PutMappingRequest source(Map mappingSource) { + try { + XContentBuilder builder = XContentFactory.contentBuilder(XContentType.JSON); + builder.map(mappingSource); + return source(builder); + } catch (IOException e) { + throw new ElasticsearchGenerationException("Failed to generate [" + mappingSource + "]", e); + } + } + + /** + * The mapping source definition. + * + * Note that the definition should *not* be nested under a type name. + */ + public PutMappingRequest source(String mappingSource, XContentType xContentType) { + this.source = new BytesArray(mappingSource); + this.xContentType = xContentType; + return this; + } + + /** + * The mapping source definition. + * + * Note that the definition should *not* be nested under a type name. + */ + public PutMappingRequest source(XContentBuilder builder) { + this.source = BytesReference.bytes(builder); + this.xContentType = builder.contentType(); + return this; + } + + /** + * The mapping source definition. + * + * Note that the definition should *not* be nested under a type name. + */ + public PutMappingRequest source(BytesReference source, XContentType xContentType) { + this.source = source; + this.xContentType = xContentType; + return this; + } + + @Override + public XContentBuilder toXContent(XContentBuilder builder, ToXContent.Params params) throws IOException { + if (source != null) { + try (InputStream stream = source.streamInput()) { + builder.rawValue(stream, XContentType.JSON); + } + } else { + builder.startObject().endObject(); + } + return builder; + } +} diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/IndicesClientIT.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/IndicesClientIT.java index f3a2fd2baaa3a..733aa4326aa20 100644 --- a/client/rest-high-level/src/test/java/org/elasticsearch/client/IndicesClientIT.java +++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/IndicesClientIT.java @@ -47,7 +47,6 @@ import org.elasticsearch.action.admin.indices.mapping.get.GetFieldMappingsResponse; import org.elasticsearch.action.admin.indices.mapping.get.GetMappingsRequest; import org.elasticsearch.action.admin.indices.mapping.get.GetMappingsResponse; -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.admin.indices.refresh.RefreshRequest; @@ -74,6 +73,7 @@ import org.elasticsearch.client.indices.FreezeIndexRequest; import org.elasticsearch.client.indices.GetIndexTemplatesRequest; import org.elasticsearch.client.indices.IndexTemplatesExistRequest; +import org.elasticsearch.client.indices.PutMappingRequest; import org.elasticsearch.client.indices.UnfreezeIndexRequest; import org.elasticsearch.cluster.metadata.AliasMetaData; import org.elasticsearch.cluster.metadata.IndexMetaData; @@ -93,6 +93,7 @@ import org.elasticsearch.index.query.QueryBuilder; import org.elasticsearch.index.query.QueryBuilders; import org.elasticsearch.rest.RestStatus; +import org.elasticsearch.rest.action.admin.indices.RestPutMappingAction; import java.io.IOException; import java.util.Arrays; @@ -402,26 +403,51 @@ public void testGetIndexNonExistentIndex() throws IOException { () -> execute(getIndexRequest, highLevelClient().indices()::get, highLevelClient().indices()::getAsync)); assertEquals(RestStatus.NOT_FOUND, exception.status()); } - + public void testPutMapping() throws IOException { - // Add mappings to index String indexName = "mapping_index"; createIndex(indexName, Settings.EMPTY); PutMappingRequest putMappingRequest = new PutMappingRequest(indexName); - putMappingRequest.type("_doc"); XContentBuilder mappingBuilder = JsonXContent.contentBuilder(); mappingBuilder.startObject().startObject("properties").startObject("field"); mappingBuilder.field("type", "text"); mappingBuilder.endObject().endObject().endObject(); putMappingRequest.source(mappingBuilder); - AcknowledgedResponse putMappingResponse = - execute(putMappingRequest, highLevelClient().indices()::putMapping, highLevelClient().indices()::putMappingAsync); + AcknowledgedResponse putMappingResponse = execute(putMappingRequest, + highLevelClient().indices()::putMapping, + highLevelClient().indices()::putMappingAsync); assertTrue(putMappingResponse.isAcknowledged()); Map getIndexResponse = getAsMap(indexName); - assertEquals("text", XContentMapValues.extractValue(indexName + ".mappings.properties.field.type", getIndexResponse)); + assertEquals("text", XContentMapValues.extractValue(indexName + ".mappings.properties.field.type", + getIndexResponse)); + } + + public void testPutMappingWithTypes() throws IOException { + String indexName = "mapping_index"; + createIndex(indexName, Settings.EMPTY); + + org.elasticsearch.action.admin.indices.mapping.put.PutMappingRequest putMappingRequest = + new org.elasticsearch.action.admin.indices.mapping.put.PutMappingRequest(indexName); + putMappingRequest.type("some_type"); + + XContentBuilder mappingBuilder = JsonXContent.contentBuilder(); + mappingBuilder.startObject().startObject("properties").startObject("field"); + mappingBuilder.field("type", "text"); + mappingBuilder.endObject().endObject().endObject(); + putMappingRequest.source(mappingBuilder); + + AcknowledgedResponse putMappingResponse = execute(putMappingRequest, + highLevelClient().indices()::putMapping, + highLevelClient().indices()::putMappingAsync, + expectWarnings(RestPutMappingAction.TYPES_DEPRECATION_MESSAGE)); + assertTrue(putMappingResponse.isAcknowledged()); + + Map getIndexResponse = getAsMap(indexName); + assertEquals("text", XContentMapValues.extractValue(indexName + ".mappings.properties.field.type", + getIndexResponse)); } public void testGetMapping() throws IOException { @@ -429,7 +455,6 @@ public void testGetMapping() throws IOException { createIndex(indexName, Settings.EMPTY); PutMappingRequest putMappingRequest = new PutMappingRequest(indexName); - putMappingRequest.type("_doc"); XContentBuilder mappingBuilder = JsonXContent.contentBuilder(); mappingBuilder.startObject().startObject("properties").startObject("field"); mappingBuilder.field("type", "text"); @@ -465,7 +490,6 @@ public void testGetFieldMapping() throws IOException { createIndex(indexName, Settings.EMPTY); PutMappingRequest putMappingRequest = new PutMappingRequest(indexName); - putMappingRequest.type("_doc"); XContentBuilder mappingBuilder = JsonXContent.contentBuilder(); mappingBuilder.startObject().startObject("properties").startObject("field"); mappingBuilder.field("type", "text"); diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/IndicesRequestConvertersTests.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/IndicesRequestConvertersTests.java index 663c40b17a8b2..25837ca307f35 100644 --- a/client/rest-high-level/src/test/java/org/elasticsearch/client/IndicesRequestConvertersTests.java +++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/IndicesRequestConvertersTests.java @@ -40,7 +40,6 @@ import org.elasticsearch.action.admin.indices.get.GetIndexRequest; import org.elasticsearch.action.admin.indices.mapping.get.GetFieldMappingsRequest; import org.elasticsearch.action.admin.indices.mapping.get.GetMappingsRequest; -import org.elasticsearch.action.admin.indices.mapping.put.PutMappingRequest; import org.elasticsearch.action.admin.indices.open.OpenIndexRequest; import org.elasticsearch.action.admin.indices.refresh.RefreshRequest; import org.elasticsearch.action.admin.indices.rollover.RolloverRequest; @@ -54,6 +53,7 @@ import org.elasticsearch.action.support.master.AcknowledgedRequest; import org.elasticsearch.client.indices.GetIndexTemplatesRequest; import org.elasticsearch.client.indices.IndexTemplatesExistRequest; +import org.elasticsearch.client.indices.PutMappingRequest; import org.elasticsearch.common.CheckedFunction; import org.elasticsearch.common.Strings; import org.elasticsearch.common.settings.Settings; @@ -163,7 +163,31 @@ public void testUpdateAliases() throws IOException { } public void testPutMapping() throws IOException { - PutMappingRequest putMappingRequest = new PutMappingRequest(); + String[] indices = RequestConvertersTests.randomIndicesNames(0, 5); + PutMappingRequest putMappingRequest = new PutMappingRequest(indices); + + Map expectedParams = new HashMap<>(); + RequestConvertersTests.setRandomTimeout(putMappingRequest, AcknowledgedRequest.DEFAULT_ACK_TIMEOUT, expectedParams); + RequestConvertersTests.setRandomMasterTimeout(putMappingRequest, expectedParams); + + Request request = IndicesRequestConverters.putMapping(putMappingRequest); + + StringJoiner endpoint = new StringJoiner("/", "/", ""); + String index = String.join(",", indices); + if (Strings.hasLength(index)) { + endpoint.add(index); + } + endpoint.add("_mapping"); + + Assert.assertEquals(endpoint.toString(), request.getEndpoint()); + Assert.assertEquals(expectedParams, request.getParameters()); + Assert.assertEquals(HttpPut.METHOD_NAME, request.getMethod()); + RequestConvertersTests.assertToXContentBody(putMappingRequest, request.getEntity()); + } + + public void testPutMappingWithTypes() throws IOException { + org.elasticsearch.action.admin.indices.mapping.put.PutMappingRequest putMappingRequest = + new org.elasticsearch.action.admin.indices.mapping.put.PutMappingRequest(); String[] indices = RequestConvertersTests.randomIndicesNames(0, 5); putMappingRequest.indices(indices); diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/IndicesClientDocumentationIT.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/IndicesClientDocumentationIT.java index 8f9d8a069fd48..48fc4a7d193ae 100644 --- a/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/IndicesClientDocumentationIT.java +++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/IndicesClientDocumentationIT.java @@ -46,7 +46,6 @@ import org.elasticsearch.action.admin.indices.mapping.get.GetFieldMappingsResponse; import org.elasticsearch.action.admin.indices.mapping.get.GetMappingsRequest; import org.elasticsearch.action.admin.indices.mapping.get.GetMappingsResponse; -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.admin.indices.refresh.RefreshRequest; @@ -78,6 +77,7 @@ import org.elasticsearch.client.indices.FreezeIndexRequest; import org.elasticsearch.client.indices.GetIndexTemplatesRequest; import org.elasticsearch.client.indices.IndexTemplatesExistRequest; +import org.elasticsearch.client.indices.PutMappingRequest; import org.elasticsearch.client.indices.UnfreezeIndexRequest; import org.elasticsearch.cluster.metadata.AliasMetaData; import org.elasticsearch.cluster.metadata.IndexTemplateMetaData; @@ -465,7 +465,6 @@ public void testPutMapping() throws IOException { { // tag::put-mapping-request PutMappingRequest request = new PutMappingRequest("twitter"); // <1> - request.type("_doc"); // <2> // end::put-mapping-request { @@ -527,12 +526,11 @@ public void testPutMapping() throws IOException { } // tag::put-mapping-request-timeout - request.timeout(TimeValue.timeValueMinutes(2)); // <1> - request.timeout("2m"); // <2> + request.setTimeout(TimeValue.timeValueMinutes(2)); // <1> // end::put-mapping-request-timeout + // tag::put-mapping-request-masterTimeout - request.masterNodeTimeout(TimeValue.timeValueMinutes(1)); // <1> - request.masterNodeTimeout("1m"); // <2> + request.setMasterTimeout(TimeValue.timeValueMinutes(1)); // <1> // end::put-mapping-request-masterTimeout // tag::put-mapping-execute @@ -555,7 +553,7 @@ public void testPutMappingAsync() throws Exception { } { - PutMappingRequest request = new PutMappingRequest("twitter").type("_doc"); + PutMappingRequest request = new PutMappingRequest("twitter"); // tag::put-mapping-execute-listener ActionListener listener = @@ -591,7 +589,6 @@ public void testGetMapping() throws IOException { CreateIndexResponse createIndexResponse = client.indices().create(new CreateIndexRequest("twitter"), RequestOptions.DEFAULT); assertTrue(createIndexResponse.isAcknowledged()); PutMappingRequest request = new PutMappingRequest("twitter"); - request.type("_doc"); request.source( "{\n" + " \"properties\": {\n" + @@ -648,7 +645,6 @@ public void testGetMappingAsync() throws Exception { CreateIndexResponse createIndexResponse = client.indices().create(new CreateIndexRequest("twitter"), RequestOptions.DEFAULT); assertTrue(createIndexResponse.isAcknowledged()); PutMappingRequest request = new PutMappingRequest("twitter"); - request.type("_doc"); request.source( "{\n" + " \"properties\": {\n" + @@ -719,7 +715,6 @@ public void testGetFieldMapping() throws IOException, InterruptedException { CreateIndexResponse createIndexResponse = client.indices().create(new CreateIndexRequest("twitter"), RequestOptions.DEFAULT); assertTrue(createIndexResponse.isAcknowledged()); PutMappingRequest request = new PutMappingRequest("twitter"); - request.type("_doc"); request.source( "{\n" + " \"properties\": {\n" + @@ -2521,9 +2516,7 @@ public void testAnalyze() throws IOException, InterruptedException { CreateIndexResponse resp = client.indices().create(req, RequestOptions.DEFAULT); assertTrue(resp.isAcknowledged()); - PutMappingRequest pmReq = new PutMappingRequest() - .indices("my_index") - .type("_doc") + PutMappingRequest pmReq = new PutMappingRequest("my_index") .source("my_field", "type=text,analyzer=english"); AcknowledgedResponse pmResp = client.indices().putMapping(pmReq, RequestOptions.DEFAULT); assertTrue(pmResp.isAcknowledged()); diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/indices/PutMappingRequestTests.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/indices/PutMappingRequestTests.java new file mode 100644 index 0000000000000..d00536b7a498f --- /dev/null +++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/indices/PutMappingRequestTests.java @@ -0,0 +1,77 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.client.indices; + +import org.elasticsearch.common.xcontent.XContentBuilder; +import org.elasticsearch.common.xcontent.XContentParser; +import org.elasticsearch.index.RandomCreateIndexGenerator; +import org.elasticsearch.test.AbstractXContentTestCase; + +import java.io.IOException; + +public class PutMappingRequestTests extends AbstractXContentTestCase { + + @Override + protected PutMappingRequest createTestInstance() { + PutMappingRequest request = new PutMappingRequest(); + if (frequently()) { + try { + XContentBuilder builder = RandomCreateIndexGenerator.randomMapping(); + request.source(builder); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + return request; + } + + @Override + protected PutMappingRequest doParseInstance(XContentParser parser) throws IOException { + PutMappingRequest request = new PutMappingRequest(); + request.source(parser.map()); + return request; + } + + @Override + protected boolean supportsUnknownFields() { + return false; + } + + @Override + protected void assertEqualInstances(PutMappingRequest expected, PutMappingRequest actual) { + try (XContentParser expectedJson = createParser(expected.xContentType().xContent(), expected.source()); + XContentParser actualJson = createParser(actual.xContentType().xContent(), actual.source())) { + assertEquals(expectedJson.mapOrdered(), actualJson.mapOrdered()); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + /** + * Test that {@link PutMappingRequest#source(Object...)} rejects inputs where the + * {@code Object...} varargs of field name and properties are not paired correctly. + */ + public void testSimpleSourceFormat() { + PutMappingRequest request = new PutMappingRequest(); + IllegalArgumentException e = expectThrows(IllegalArgumentException.class, + () -> request.source("only_field")); + assertEquals("mapping source must be pairs of field names and properties definitions.", e.getMessage()); + } +} diff --git a/docs/java-rest/high-level/indices/put_mapping.asciidoc b/docs/java-rest/high-level/indices/put_mapping.asciidoc index d1b9c6ad8c6fd..7772899a8d4dc 100644 --- a/docs/java-rest/high-level/indices/put_mapping.asciidoc +++ b/docs/java-rest/high-level/indices/put_mapping.asciidoc @@ -10,14 +10,13 @@ [id="{upid}-{api}-request"] ==== Put Mapping Request -A +{request}+ requires an `index` argument, and a type: +A +{request}+ requires an `index` argument: ["source","java",subs="attributes,callouts,macros"] -------------------------------------------------- include-tagged::{doc-tests-file}[{api}-request] -------------------------------------------------- <1> The index to add the mapping to -<2> The type to create (or update) ==== Mapping source A description of the fields to create on the mapping; if not defined, the mapping will default to empty. @@ -61,14 +60,12 @@ The following arguments can optionally be provided: include-tagged::{doc-tests-file}[{api}-request-timeout] -------------------------------------------------- <1> Timeout to wait for the all the nodes to acknowledge the index creation as a `TimeValue` -<2> Timeout to wait for the all the nodes to acknowledge the index creation as a `String` ["source","java",subs="attributes,callouts,macros"] -------------------------------------------------- include-tagged::{doc-tests-file}[{api}-request-masterTimeout] -------------------------------------------------- <1> Timeout to connect to the master node as a `TimeValue` -<2> Timeout to connect to the master node as a `String` include::../execution.asciidoc[] diff --git a/server/src/main/java/org/elasticsearch/rest/action/admin/indices/RestPutMappingAction.java b/server/src/main/java/org/elasticsearch/rest/action/admin/indices/RestPutMappingAction.java index b8e76b6a6bc01..bd99c26a155a0 100644 --- a/server/src/main/java/org/elasticsearch/rest/action/admin/indices/RestPutMappingAction.java +++ b/server/src/main/java/org/elasticsearch/rest/action/admin/indices/RestPutMappingAction.java @@ -41,7 +41,7 @@ public class RestPutMappingAction extends BaseRestHandler { private static final DeprecationLogger deprecationLogger = new DeprecationLogger( LogManager.getLogger(RestPutMappingAction.class)); - static final String TYPES_DEPRECATION_MESSAGE = "[types removal] Using include_type_name in put " + + public static final String TYPES_DEPRECATION_MESSAGE = "[types removal] Using include_type_name in put " + "mapping requests is deprecated. The parameter will be removed in the next major version."; public RestPutMappingAction(Settings settings, RestController controller) { diff --git a/server/src/test/java/org/elasticsearch/action/admin/indices/mapping/put/PutMappingRequestTests.java b/server/src/test/java/org/elasticsearch/action/admin/indices/mapping/put/PutMappingRequestTests.java index 5243ffd33b39c..6fddf2dd5f85b 100644 --- a/server/src/test/java/org/elasticsearch/action/admin/indices/mapping/put/PutMappingRequestTests.java +++ b/server/src/test/java/org/elasticsearch/action/admin/indices/mapping/put/PutMappingRequestTests.java @@ -38,14 +38,9 @@ public class PutMappingRequestTests extends ESTestCase { public void testValidation() { - PutMappingRequest r = new PutMappingRequest("myindex"); + PutMappingRequest r = new PutMappingRequest("myindex").type(""); ActionRequestValidationException ex = r.validate(); assertNotNull("type validation should fail", ex); - assertTrue(ex.getMessage().contains("type is missing")); - - r.type(""); - ex = r.validate(); - assertNotNull("type validation should fail", ex); assertTrue(ex.getMessage().contains("type is empty")); r.type("mytype"); diff --git a/test/framework/src/main/java/org/elasticsearch/index/RandomCreateIndexGenerator.java b/test/framework/src/main/java/org/elasticsearch/index/RandomCreateIndexGenerator.java index e88a9f0a38d2c..86dbc1847153d 100644 --- a/test/framework/src/main/java/org/elasticsearch/index/RandomCreateIndexGenerator.java +++ b/test/framework/src/main/java/org/elasticsearch/index/RandomCreateIndexGenerator.java @@ -76,6 +76,24 @@ public static Settings randomIndexSettings() { return builder.build(); } + + /** + * Creates a random mapping, with no mention of types. + */ + public static XContentBuilder randomMapping() throws IOException { + XContentBuilder builder = XContentFactory.jsonBuilder(); + builder.startObject(); + + randomMappingFields(builder, true); + + builder.endObject(); + return builder; + } + + /** + * Creates a random mapping, with the mapping definition nested + * under the given type name. + */ public static XContentBuilder randomMapping(String type) throws IOException { XContentBuilder builder = XContentFactory.jsonBuilder(); builder.startObject().startObject(type); From 4b7fb3528ba301842c585a5c4623635088c1290d Mon Sep 17 00:00:00 2001 From: Julie Tibshirani Date: Wed, 16 Jan 2019 11:04:58 -0800 Subject: [PATCH 4/9] Remove PutMappingRequest#source(Object... source), as it is not as useful for the HLRC. --- .../client/indices/PutMappingRequest.java | 68 ------------------- .../elasticsearch/client/IndicesClientIT.java | 2 +- .../IndicesClientDocumentationIT.java | 14 ++-- .../indices/PutMappingRequestTests.java | 11 --- .../high-level/indices/put_mapping.asciidoc | 7 -- 5 files changed, 7 insertions(+), 95 deletions(-) diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/indices/PutMappingRequest.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/indices/PutMappingRequest.java index ed62c41075b95..1b1b9dc357e26 100644 --- a/client/rest-high-level/src/main/java/org/elasticsearch/client/indices/PutMappingRequest.java +++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/indices/PutMappingRequest.java @@ -24,7 +24,6 @@ import org.elasticsearch.action.IndicesRequest; import org.elasticsearch.action.support.IndicesOptions; import org.elasticsearch.client.TimedRequest; -import org.elasticsearch.common.Strings; import org.elasticsearch.common.bytes.BytesArray; import org.elasticsearch.common.bytes.BytesReference; import org.elasticsearch.common.xcontent.ToXContent; @@ -95,73 +94,6 @@ public XContentType xContentType() { return xContentType; } - /** - * A specialized simplified mapping source method, takes the form of simple properties definition: - * ("field1", "type=string,store=true"). - * - * Also supports metadata mapping fields such as `_all` and `_parent` as property definition, these metadata - * mapping fields will automatically be put on the top level mapping object. - */ - public PutMappingRequest source(Object... source) { - return source(buildFromSimplifiedDef(source)); - } - - /** - * @param source A list of objects representing field andproperties pairs (e.g. "field", "type=keyword"). - * - * @throws IllegalArgumentException if the number of the source arguments is not divisible by two. - * @return the mappings definition - */ - private static XContentBuilder buildFromSimplifiedDef(Object... source) { - if (source.length % 2 != 0) { - throw new IllegalArgumentException("mapping source must be pairs of field names and properties definitions."); - } - try { - XContentBuilder builder = XContentFactory.jsonBuilder(); - builder.startObject(); - - for (int i = 0; i < source.length; i++) { - String fieldName = source[i++].toString(); - if (RESERVED_FIELDS.contains(fieldName)) { - builder.startObject(fieldName); - String[] s1 = Strings.splitStringByCommaToArray(source[i].toString()); - for (String s : s1) { - String[] s2 = Strings.split(s, "="); - if (s2.length != 2) { - throw new IllegalArgumentException("malformed " + s); - } - builder.field(s2[0], s2[1]); - } - builder.endObject(); - } - } - - builder.startObject("properties"); - for (int i = 0; i < source.length; i++) { - String fieldName = source[i++].toString(); - if (RESERVED_FIELDS.contains(fieldName)) { - continue; - } - - builder.startObject(fieldName); - String[] s1 = Strings.splitStringByCommaToArray(source[i].toString()); - for (String s : s1) { - String[] s2 = Strings.split(s, "="); - if (s2.length != 2) { - throw new IllegalArgumentException("malformed " + s); - } - builder.field(s2[0], s2[1]); - } - builder.endObject(); - } - builder.endObject(); - builder.endObject(); - return builder; - } catch (Exception e) { - throw new IllegalArgumentException("failed to generate simplified mapping definition", e); - } - } - /** * The mapping source definition. * diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/IndicesClientIT.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/IndicesClientIT.java index 733aa4326aa20..0947547e1bd11 100644 --- a/client/rest-high-level/src/test/java/org/elasticsearch/client/IndicesClientIT.java +++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/IndicesClientIT.java @@ -403,7 +403,7 @@ public void testGetIndexNonExistentIndex() throws IOException { () -> execute(getIndexRequest, highLevelClient().indices()::get, highLevelClient().indices()::getAsync)); assertEquals(RestStatus.NOT_FOUND, exception.status()); } - + public void testPutMapping() throws IOException { String indexName = "mapping_index"; createIndex(indexName, Settings.EMPTY); diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/IndicesClientDocumentationIT.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/IndicesClientDocumentationIT.java index 48fc4a7d193ae..0cdc9b4704d94 100644 --- a/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/IndicesClientDocumentationIT.java +++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/IndicesClientDocumentationIT.java @@ -517,13 +517,6 @@ public void testPutMapping() throws IOException { AcknowledgedResponse putMappingResponse = client.indices().putMapping(request, RequestOptions.DEFAULT); assertTrue(putMappingResponse.isAcknowledged()); } - { - //tag::put-mapping-shortcut - request.source("message", "type=text"); // <1> - //end::put-mapping-shortcut - AcknowledgedResponse putMappingResponse = client.indices().putMapping(request, RequestOptions.DEFAULT); - assertTrue(putMappingResponse.isAcknowledged()); - } // tag::put-mapping-request-timeout request.setTimeout(TimeValue.timeValueMinutes(2)); // <1> @@ -2517,7 +2510,12 @@ public void testAnalyze() throws IOException, InterruptedException { assertTrue(resp.isAcknowledged()); PutMappingRequest pmReq = new PutMappingRequest("my_index") - .source("my_field", "type=text,analyzer=english"); + .source(XContentFactory.jsonBuilder().startObject() + .startObject("my_field") + .field("type", "text") + .field("analyzer", "english") + .endObject() + .endObject()); AcknowledgedResponse pmResp = client.indices().putMapping(pmReq, RequestOptions.DEFAULT); assertTrue(pmResp.isAcknowledged()); diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/indices/PutMappingRequestTests.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/indices/PutMappingRequestTests.java index d00536b7a498f..40b38e40b2647 100644 --- a/client/rest-high-level/src/test/java/org/elasticsearch/client/indices/PutMappingRequestTests.java +++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/indices/PutMappingRequestTests.java @@ -63,15 +63,4 @@ protected void assertEqualInstances(PutMappingRequest expected, PutMappingReques throw new RuntimeException(e); } } - - /** - * Test that {@link PutMappingRequest#source(Object...)} rejects inputs where the - * {@code Object...} varargs of field name and properties are not paired correctly. - */ - public void testSimpleSourceFormat() { - PutMappingRequest request = new PutMappingRequest(); - IllegalArgumentException e = expectThrows(IllegalArgumentException.class, - () -> request.source("only_field")); - assertEquals("mapping source must be pairs of field names and properties definitions.", e.getMessage()); - } } diff --git a/docs/java-rest/high-level/indices/put_mapping.asciidoc b/docs/java-rest/high-level/indices/put_mapping.asciidoc index 7772899a8d4dc..971ad52d62b78 100644 --- a/docs/java-rest/high-level/indices/put_mapping.asciidoc +++ b/docs/java-rest/high-level/indices/put_mapping.asciidoc @@ -45,13 +45,6 @@ include-tagged::{doc-tests-file}[{api}-xcontent] <1> Mapping source provided as an `XContentBuilder` object, the Elasticsearch built-in helpers to generate JSON content -["source","java",subs="attributes,callouts,macros"] --------------------------------------------------- -include-tagged::{doc-tests-file}[{api}-shortcut] --------------------------------------------------- -<1> Mapping source provided as `Object` key-pairs, which gets converted to -JSON format - ==== Optional arguments The following arguments can optionally be provided: From 9aad5dd7d09c048b1c405cde2e9f213972283448 Mon Sep 17 00:00:00 2001 From: Julie Tibshirani Date: Wed, 16 Jan 2019 11:13:35 -0800 Subject: [PATCH 5/9] Make sure to use the right xContent type in PutMappingRequest#toXContent. --- .../org/elasticsearch/client/indices/PutMappingRequest.java | 2 +- .../org/elasticsearch/index/RandomCreateIndexGenerator.java | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/indices/PutMappingRequest.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/indices/PutMappingRequest.java index 1b1b9dc357e26..4607e7a5589ce 100644 --- a/client/rest-high-level/src/main/java/org/elasticsearch/client/indices/PutMappingRequest.java +++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/indices/PutMappingRequest.java @@ -146,7 +146,7 @@ public PutMappingRequest source(BytesReference source, XContentType xContentType public XContentBuilder toXContent(XContentBuilder builder, ToXContent.Params params) throws IOException { if (source != null) { try (InputStream stream = source.streamInput()) { - builder.rawValue(stream, XContentType.JSON); + builder.rawValue(stream, xContentType); } } else { builder.startObject().endObject(); diff --git a/test/framework/src/main/java/org/elasticsearch/index/RandomCreateIndexGenerator.java b/test/framework/src/main/java/org/elasticsearch/index/RandomCreateIndexGenerator.java index 86dbc1847153d..e4836150c6e86 100644 --- a/test/framework/src/main/java/org/elasticsearch/index/RandomCreateIndexGenerator.java +++ b/test/framework/src/main/java/org/elasticsearch/index/RandomCreateIndexGenerator.java @@ -24,6 +24,7 @@ import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentFactory; +import org.elasticsearch.common.xcontent.XContentType; import java.io.IOException; @@ -31,6 +32,7 @@ import static org.elasticsearch.cluster.metadata.IndexMetaData.SETTING_NUMBER_OF_SHARDS; import static org.elasticsearch.test.ESTestCase.randomAlphaOfLength; import static org.elasticsearch.test.ESTestCase.randomBoolean; +import static org.elasticsearch.test.ESTestCase.randomFrom; import static org.elasticsearch.test.ESTestCase.randomIntBetween; public final class RandomCreateIndexGenerator { @@ -81,7 +83,7 @@ public static Settings randomIndexSettings() { * Creates a random mapping, with no mention of types. */ public static XContentBuilder randomMapping() throws IOException { - XContentBuilder builder = XContentFactory.jsonBuilder(); + XContentBuilder builder = XContentFactory.contentBuilder(randomFrom(XContentType.values())); builder.startObject(); randomMappingFields(builder, true); @@ -95,7 +97,7 @@ public static XContentBuilder randomMapping() throws IOException { * under the given type name. */ public static XContentBuilder randomMapping(String type) throws IOException { - XContentBuilder builder = XContentFactory.jsonBuilder(); + XContentBuilder builder = XContentFactory.contentBuilder(randomFrom(XContentType.values())); builder.startObject().startObject(type); randomMappingFields(builder, true); From 6335ca599bc63d0dc9c8b54b91b47044bd84874b Mon Sep 17 00:00:00 2001 From: Julie Tibshirani Date: Thu, 17 Jan 2019 17:32:24 -0800 Subject: [PATCH 6/9] Make sure RestHighLevelClientTests can handle two methods with the same name. --- .../client/RestHighLevelClientTests.java | 83 ++++++++++--------- 1 file changed, 43 insertions(+), 40 deletions(-) diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/RestHighLevelClientTests.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/RestHighLevelClientTests.java index 6995fcf099ad2..95553b9efb26a 100644 --- a/client/rest-high-level/src/test/java/org/elasticsearch/client/RestHighLevelClientTests.java +++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/RestHighLevelClientTests.java @@ -105,6 +105,7 @@ import java.util.stream.Collectors; import java.util.stream.Stream; +import static java.util.stream.Collectors.mapping; import static org.elasticsearch.common.xcontent.XContentHelper.toXContent; import static org.hamcrest.CoreMatchers.endsWith; import static org.hamcrest.CoreMatchers.equalTo; @@ -721,55 +722,57 @@ public void testApiNamingConventions() throws Exception { ClientYamlSuiteRestSpec restSpec = ClientYamlSuiteRestSpec.load("/rest-api-spec/api"); Set apiSpec = restSpec.getApis().stream().map(ClientYamlSuiteRestApi::getName).collect(Collectors.toSet()); + Set apiUnsupported = new HashSet<>(apiSpec); + Set apiNotFound = new HashSet<>(); Set topLevelMethodsExclusions = new HashSet<>(); topLevelMethodsExclusions.add("getLowLevelClient"); topLevelMethodsExclusions.add("close"); - Map methods = Arrays.stream(RestHighLevelClient.class.getMethods()) + Map> methods = Arrays.stream(RestHighLevelClient.class.getMethods()) .filter(method -> method.getDeclaringClass().equals(RestHighLevelClient.class) && topLevelMethodsExclusions.contains(method.getName()) == false) .map(method -> Tuple.tuple(toSnakeCase(method.getName()), method)) .flatMap(tuple -> tuple.v2().getReturnType().getName().endsWith("Client") ? getSubClientMethods(tuple.v1(), tuple.v2().getReturnType()) : Stream.of(tuple)) - .collect(Collectors.toMap(Tuple::v1, Tuple::v2)); - - Set apiNotFound = new HashSet<>(); + .collect(Collectors.groupingBy(Tuple::v1, + Collectors.mapping(Tuple::v2, Collectors.toSet()))); - for (Map.Entry entry : methods.entrySet()) { - Method method = entry.getValue(); + for (Map.Entry> entry : methods.entrySet()) { String apiName = entry.getKey(); - assertTrue("method [" + apiName + "] is not final", + for (Method method : entry.getValue()) { + assertTrue("method [" + apiName + "] is not final", Modifier.isFinal(method.getClass().getModifiers()) || Modifier.isFinal(method.getModifiers())); - assertTrue("method [" + method + "] should be public", Modifier.isPublic(method.getModifiers())); - - //we convert all the method names to snake case, hence we need to look for the '_async' suffix rather than 'Async' - if (apiName.endsWith("_async")) { - assertAsyncMethod(methods, method, apiName); - } else if (isSubmitTaskMethod(apiName)) { - assertSubmitTaskMethod(methods, method, apiName, restSpec); - } else { - assertSyncMethod(method, apiName); - boolean remove = apiSpec.remove(apiName); - if (remove == false) { - if (deprecatedMethods.contains(apiName)) { - assertTrue("method [" + method.getName() + "], api [" + apiName + "] should be deprecated", - method.isAnnotationPresent(Deprecated.class)); - } else { - //TODO xpack api are currently ignored, we need to load xpack yaml spec too - if (apiName.startsWith("xpack.") == false && - apiName.startsWith("license.") == false && - apiName.startsWith("machine_learning.") == false && - apiName.startsWith("rollup.") == false && - apiName.startsWith("watcher.") == false && - apiName.startsWith("graph.") == false && - apiName.startsWith("migration.") == false && - apiName.startsWith("security.") == false && - apiName.startsWith("index_lifecycle.") == false && - apiName.startsWith("ccr.") == false && - apiName.endsWith("freeze") == false) { - apiNotFound.add(apiName); + assertTrue("method [" + method + "] should be public", Modifier.isPublic(method.getModifiers())); + + //we convert all the method names to snake case, hence we need to look for the '_async' suffix rather than 'Async' + if (apiName.endsWith("_async")) { + assertAsyncMethod(methods, method, apiName); + } else if (isSubmitTaskMethod(apiName)) { + assertSubmitTaskMethod(methods, method, apiName, restSpec); + } else { + assertSyncMethod(method, apiName); + apiUnsupported.remove(apiName); + if (apiSpec.contains(apiName) == false) { + if (deprecatedMethods.contains(apiName)) { + assertTrue("method [" + method.getName() + "], api [" + apiName + "] should be deprecated", + method.isAnnotationPresent(Deprecated.class)); + } else { + //TODO xpack api are currently ignored, we need to load xpack yaml spec too + if (apiName.startsWith("xpack.") == false && + apiName.startsWith("license.") == false && + apiName.startsWith("machine_learning.") == false && + apiName.startsWith("rollup.") == false && + apiName.startsWith("watcher.") == false && + apiName.startsWith("graph.") == false && + apiName.startsWith("migration.") == false && + apiName.startsWith("security.") == false && + apiName.startsWith("index_lifecycle.") == false && + apiName.startsWith("ccr.") == false && + apiName.endsWith("freeze") == false) { + apiNotFound.add(apiName); + } } } } @@ -779,11 +782,11 @@ public void testApiNamingConventions() throws Exception { apiNotFound.size(), equalTo(0)); //we decided not to support cat API in the high-level REST client, they are supposed to be used from a low-level client - apiSpec.removeIf(api -> api.startsWith("cat.")); + apiUnsupported.removeIf(api -> api.startsWith("cat.")); Stream.concat(Arrays.stream(notYetSupportedApi), Arrays.stream(notRequiredApi)).forEach( api -> assertTrue(api + " API is either not defined in the spec or already supported by the high-level client", - apiSpec.remove(api))); - assertThat("Some API are not supported but they should be: " + apiSpec, apiSpec.size(), equalTo(0)); + apiUnsupported.remove(api))); + assertThat("Some API are not supported but they should be: " + apiUnsupported, apiUnsupported.size(), equalTo(0)); } private static void assertSyncMethod(Method method, String apiName) { @@ -814,7 +817,7 @@ private static void assertSyncMethod(Method method, String apiName) { } } - private static void assertAsyncMethod(Map methods, Method method, String apiName) { + private static void assertAsyncMethod(Map> methods, Method method, String apiName) { assertTrue("async method [" + method.getName() + "] doesn't have corresponding sync method", methods.containsKey(apiName.substring(0, apiName.length() - 6))); assertThat("async method [" + method + "] should return void", method.getReturnType(), equalTo(Void.TYPE)); @@ -834,7 +837,7 @@ private static void assertAsyncMethod(Map methods, Method method } } - private static void assertSubmitTaskMethod(Map methods, Method method, String apiName, + private static void assertSubmitTaskMethod(Map> methods, Method method, String apiName, ClientYamlSuiteRestSpec restSpec) { String methodName = extractMethodName(apiName); assertTrue("submit task method [" + method.getName() + "] doesn't have corresponding sync method", From 314fb3b87321c0a8b0d27cb685bf67fbf99b958a Mon Sep 17 00:00:00 2001 From: Julie Tibshirani Date: Thu, 17 Jan 2019 17:44:30 -0800 Subject: [PATCH 7/9] Fix static analysis violations. --- .../java/org/elasticsearch/client/RestHighLevelClientTests.java | 1 - 1 file changed, 1 deletion(-) diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/RestHighLevelClientTests.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/RestHighLevelClientTests.java index 95553b9efb26a..fe48c09e2cdfc 100644 --- a/client/rest-high-level/src/test/java/org/elasticsearch/client/RestHighLevelClientTests.java +++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/RestHighLevelClientTests.java @@ -105,7 +105,6 @@ import java.util.stream.Collectors; import java.util.stream.Stream; -import static java.util.stream.Collectors.mapping; import static org.elasticsearch.common.xcontent.XContentHelper.toXContent; import static org.hamcrest.CoreMatchers.endsWith; import static org.hamcrest.CoreMatchers.equalTo; From 393877a64e01027c10470db3bdebca20ca5dd65a Mon Sep 17 00:00:00 2001 From: Julie Tibshirani Date: Thu, 17 Jan 2019 19:10:28 -0800 Subject: [PATCH 8/9] Correct a deprecation comment in IndicesClient. --- .../main/java/org/elasticsearch/client/IndicesClient.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/IndicesClient.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/IndicesClient.java index 92220aa2a658b..d658e1f0682cd 100644 --- a/client/rest-high-level/src/main/java/org/elasticsearch/client/IndicesClient.java +++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/IndicesClient.java @@ -193,8 +193,9 @@ public AcknowledgedResponse putMapping(org.elasticsearch.action.admin.indices.ma * @param options the request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized * @param listener the listener to be notified upon request completion * - * @deprecated This method uses an old request object which still refers to types, a deprecated feature. The method - * {@link #putMapping(PutMappingRequest, RequestOptions)} should be used instead, which accepts a new request object. + * @deprecated This method uses an old request object which still refers to types, a deprecated feature. The + * method {@link #putMappingAsync(PutMappingRequest, RequestOptions, ActionListener)} should be used instead, + * which accepts a new request object. */ @Deprecated public void putMappingAsync(org.elasticsearch.action.admin.indices.mapping.put.PutMappingRequest putMappingRequest, From 8ba19ac02a804bc64752716eb174ce4e67fe40fb Mon Sep 17 00:00:00 2001 From: Julie Tibshirani Date: Thu, 17 Jan 2019 23:35:23 -0800 Subject: [PATCH 9/9] Fix IndicesClientDocumentationIT#testAnalyze. --- .../documentation/IndicesClientDocumentationIT.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/IndicesClientDocumentationIT.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/IndicesClientDocumentationIT.java index 0cdc9b4704d94..71f2573231ed1 100644 --- a/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/IndicesClientDocumentationIT.java +++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/IndicesClientDocumentationIT.java @@ -2511,9 +2511,11 @@ public void testAnalyze() throws IOException, InterruptedException { PutMappingRequest pmReq = new PutMappingRequest("my_index") .source(XContentFactory.jsonBuilder().startObject() - .startObject("my_field") - .field("type", "text") - .field("analyzer", "english") + .startObject("properties") + .startObject("my_field") + .field("type", "text") + .field("analyzer", "english") + .endObject() .endObject() .endObject()); AcknowledgedResponse pmResp = client.indices().putMapping(pmReq, RequestOptions.DEFAULT);