Deprecate types in get field mapping API (#37667)

- Add deprecation warning to RestGetFieldMappingAction
- Add two new java HRLC classes GetFieldMappingsRequest and
GetFieldMappingsResponse. These classes use new typeless forms
of a request and response, and differ in that from the server
versions.

Relates to #35190
This commit is contained in:
Mayya Sharipova 2019-01-23 14:24:35 -05:00 committed by GitHub
parent f45b5fedb5
commit c8565fe692
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 591 additions and 33 deletions

View File

@ -37,8 +37,8 @@ import org.elasticsearch.action.admin.indices.forcemerge.ForceMergeRequest;
import org.elasticsearch.action.admin.indices.forcemerge.ForceMergeResponse;
import org.elasticsearch.action.admin.indices.get.GetIndexRequest;
import org.elasticsearch.action.admin.indices.get.GetIndexResponse;
import org.elasticsearch.action.admin.indices.mapping.get.GetFieldMappingsRequest;
import org.elasticsearch.action.admin.indices.mapping.get.GetFieldMappingsResponse;
import org.elasticsearch.client.indices.GetFieldMappingsRequest;
import org.elasticsearch.client.indices.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.open.OpenIndexRequest;
@ -241,11 +241,16 @@ public final class IndicesClient {
* @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 #getFieldMapping(GetFieldMappingsRequest, RequestOptions)} should be used instead, which accepts a new request object.
*/
public GetFieldMappingsResponse getFieldMapping(GetFieldMappingsRequest getFieldMappingsRequest,
RequestOptions options) throws IOException {
return restHighLevelClient.performRequestAndParseEntity(getFieldMappingsRequest, IndicesRequestConverters::getFieldMapping, options,
GetFieldMappingsResponse::fromXContent, emptySet());
@Deprecated
public org.elasticsearch.action.admin.indices.mapping.get.GetFieldMappingsResponse getFieldMapping(
org.elasticsearch.action.admin.indices.mapping.get.GetFieldMappingsRequest getFieldMappingsRequest,
RequestOptions options) throws IOException {
return restHighLevelClient.performRequestAndParseEntity(getFieldMappingsRequest, IndicesRequestConverters::getFieldMapping,
options, org.elasticsearch.action.admin.indices.mapping.get.GetFieldMappingsResponse::fromXContent, emptySet());
}
/**
@ -255,9 +260,45 @@ public final class IndicesClient {
* @param getFieldMappingsRequest 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 #getFieldMappingAsync(GetFieldMappingsRequest, RequestOptions, ActionListener)} should be used instead,
* which accepts a new request object.
*/
public void getFieldMappingAsync(GetFieldMappingsRequest getFieldMappingsRequest, RequestOptions options,
ActionListener<GetFieldMappingsResponse> listener) {
@Deprecated
public void getFieldMappingAsync(org.elasticsearch.action.admin.indices.mapping.get.GetFieldMappingsRequest getFieldMappingsRequest,
RequestOptions options,
ActionListener<org.elasticsearch.action.admin.indices.mapping.get.GetFieldMappingsResponse> listener) {
restHighLevelClient.performRequestAsyncAndParseEntity(getFieldMappingsRequest, IndicesRequestConverters::getFieldMapping, options,
org.elasticsearch.action.admin.indices.mapping.get.GetFieldMappingsResponse::fromXContent, listener, emptySet());
}
/**
* Retrieves the field mappings on an index or indices using the Get Field Mapping API.
* See <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-get-field-mapping.html">
* Get Field Mapping API on elastic.co</a>
* @param getFieldMappingsRequest 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
*/
public GetFieldMappingsResponse getFieldMapping(GetFieldMappingsRequest getFieldMappingsRequest,
RequestOptions options) throws IOException {
return restHighLevelClient.performRequestAndParseEntity(getFieldMappingsRequest, IndicesRequestConverters::getFieldMapping,
options, GetFieldMappingsResponse::fromXContent, emptySet()
);
}
/**
* Asynchronously retrieves the field mappings on an index or indices using the Get Field Mapping API.
* See <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-get-field-mapping.html">
* Get Field Mapping API on elastic.co</a>
* @param getFieldMappingsRequest 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
*/
public void getFieldMappingAsync(GetFieldMappingsRequest getFieldMappingsRequest,
RequestOptions options, ActionListener<GetFieldMappingsResponse> listener) {
restHighLevelClient.performRequestAsyncAndParseEntity(getFieldMappingsRequest, IndicesRequestConverters::getFieldMapping, options,
GetFieldMappingsResponse::fromXContent, listener, emptySet());
}

View File

@ -35,7 +35,7 @@ import org.elasticsearch.action.admin.indices.flush.FlushRequest;
import org.elasticsearch.action.admin.indices.flush.SyncedFlushRequest;
import org.elasticsearch.action.admin.indices.forcemerge.ForceMergeRequest;
import org.elasticsearch.action.admin.indices.get.GetIndexRequest;
import org.elasticsearch.action.admin.indices.mapping.get.GetFieldMappingsRequest;
import org.elasticsearch.client.indices.GetFieldMappingsRequest;
import org.elasticsearch.action.admin.indices.mapping.get.GetMappingsRequest;
import org.elasticsearch.action.admin.indices.open.OpenIndexRequest;
import org.elasticsearch.action.admin.indices.refresh.RefreshRequest;
@ -165,7 +165,28 @@ final class IndicesRequestConverters {
return request;
}
static Request getFieldMapping(GetFieldMappingsRequest getFieldMappingsRequest) throws IOException {
static Request getFieldMapping(GetFieldMappingsRequest getFieldMappingsRequest) {
String[] indices = getFieldMappingsRequest.indices() == null ? Strings.EMPTY_ARRAY : getFieldMappingsRequest.indices();
String[] fields = getFieldMappingsRequest.fields() == null ? Strings.EMPTY_ARRAY : getFieldMappingsRequest.fields();
String endpoint = new RequestConverters.EndpointBuilder()
.addCommaSeparatedPathParts(indices)
.addPathPartAsIs("_mapping")
.addPathPartAsIs("field")
.addCommaSeparatedPathParts(fields)
.build();
Request request = new Request(HttpGet.METHOD_NAME, endpoint);
RequestConverters.Params parameters = new RequestConverters.Params(request);
parameters.withIndicesOptions(getFieldMappingsRequest.indicesOptions());
parameters.withIncludeDefaults(getFieldMappingsRequest.includeDefaults());
parameters.withLocal(getFieldMappingsRequest.local());
return request;
}
static Request getFieldMapping(org.elasticsearch.action.admin.indices.mapping.get.GetFieldMappingsRequest getFieldMappingsRequest) {
String[] indices = getFieldMappingsRequest.indices() == null ? Strings.EMPTY_ARRAY : getFieldMappingsRequest.indices();
String[] types = getFieldMappingsRequest.types() == null ? Strings.EMPTY_ARRAY : getFieldMappingsRequest.types();
String[] fields = getFieldMappingsRequest.fields() == null ? Strings.EMPTY_ARRAY : getFieldMappingsRequest.fields();

View File

@ -0,0 +1,90 @@
/*
* 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.action.support.IndicesOptions;
import org.elasticsearch.client.Validatable;
import org.elasticsearch.common.Strings;
/** Request the mappings of specific fields */
public class GetFieldMappingsRequest implements Validatable {
private boolean local = false;
private String[] fields = Strings.EMPTY_ARRAY;
private boolean includeDefaults = false;
private String[] indices = Strings.EMPTY_ARRAY;
private IndicesOptions indicesOptions = IndicesOptions.strictExpandOpen();
/**
* Indicate whether the receiving node should operate based on local index information or forward requests,
* where needed, to other nodes. If running locally, request will not raise errors if running locally &amp; missing indices.
*/
public GetFieldMappingsRequest local(boolean local) {
this.local = local;
return this;
}
public boolean local() {
return local;
}
public GetFieldMappingsRequest indices(String... indices) {
this.indices = indices;
return this;
}
public GetFieldMappingsRequest indicesOptions(IndicesOptions indicesOptions) {
this.indicesOptions = indicesOptions;
return this;
}
public String[] indices() {
return indices;
}
public IndicesOptions indicesOptions() {
return indicesOptions;
}
/** @param fields a list of fields to retrieve the mapping for */
public GetFieldMappingsRequest fields(String... fields) {
this.fields = fields;
return this;
}
public String[] fields() {
return fields;
}
public boolean includeDefaults() {
return includeDefaults;
}
/** Indicates whether default mapping settings should be returned */
public GetFieldMappingsRequest includeDefaults(boolean includeDefaults) {
this.includeDefaults = includeDefaults;
return this;
}
}

View File

@ -0,0 +1,190 @@
/*
* 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.ParseField;
import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.xcontent.ConstructingObjectParser;
import org.elasticsearch.common.xcontent.ObjectParser;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentHelper;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.mapper.Mapper;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import static org.elasticsearch.common.xcontent.ConstructingObjectParser.optionalConstructorArg;
import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
import static org.elasticsearch.common.xcontent.XContentParserUtils.ensureExpectedToken;
/** Response object for {@link GetFieldMappingsRequest} API */
public class GetFieldMappingsResponse {
private static final ParseField MAPPINGS = new ParseField("mappings");
private static final ObjectParser<Map<String, FieldMappingMetaData>, String> PARSER =
new ObjectParser<>(MAPPINGS.getPreferredName(), true, HashMap::new);
static {
PARSER.declareField((p, fieldMappings, index) -> {
p.nextToken();
while (p.currentToken() == XContentParser.Token.FIELD_NAME) {
final String fieldName = p.currentName();
final FieldMappingMetaData fieldMappingMetaData = FieldMappingMetaData.fromXContent(p);
fieldMappings.put(fieldName, fieldMappingMetaData);
p.nextToken();
}
}, MAPPINGS, ObjectParser.ValueType.OBJECT);
}
private Map<String, Map<String, FieldMappingMetaData>> mappings;
GetFieldMappingsResponse(Map<String, Map<String, FieldMappingMetaData>> mappings) {
this.mappings = mappings;
}
/**
* Returns the fields mapping. The return map keys are indexes and fields (as specified in the request).
*/
public Map<String, Map<String, FieldMappingMetaData>> mappings() {
return mappings;
}
/**
* Returns the mappings of a specific index and field.
*
* @param field field name as specified in the {@link GetFieldMappingsRequest}
* @return FieldMappingMetaData for the requested field or null if not found.
*/
public FieldMappingMetaData fieldMappings(String index, String field) {
Map<String, FieldMappingMetaData> indexMapping = mappings.get(index);
if (indexMapping == null) {
return null;
}
return indexMapping.get(field);
}
public static GetFieldMappingsResponse fromXContent(XContentParser parser) throws IOException {
ensureExpectedToken(XContentParser.Token.START_OBJECT, parser.nextToken(), parser::getTokenLocation);
final Map<String, Map<String, FieldMappingMetaData>> mappings = new HashMap<>();
if (parser.nextToken() == XContentParser.Token.FIELD_NAME) {
while (parser.currentToken() == XContentParser.Token.FIELD_NAME) {
final String index = parser.currentName();
final Map<String, FieldMappingMetaData> fieldMappings = PARSER.parse(parser, index);
mappings.put(index, fieldMappings);
parser.nextToken();
}
}
return new GetFieldMappingsResponse(mappings);
}
public static class FieldMappingMetaData {
private static final ParseField FULL_NAME = new ParseField("full_name");
private static final ParseField MAPPING = new ParseField("mapping");
private static final ConstructingObjectParser<FieldMappingMetaData, String> PARSER =
new ConstructingObjectParser<>("field_mapping_meta_data", true,
a -> new FieldMappingMetaData((String)a[0], (BytesReference)a[1])
);
static {
PARSER.declareField(optionalConstructorArg(),
(p, c) -> p.text(), FULL_NAME, ObjectParser.ValueType.STRING);
PARSER.declareField(optionalConstructorArg(),
(p, c) -> {
final XContentBuilder jsonBuilder = jsonBuilder().copyCurrentStructure(p);
final BytesReference bytes = BytesReference.bytes(jsonBuilder);
return bytes;
}, MAPPING, ObjectParser.ValueType.OBJECT);
}
private String fullName;
private BytesReference source;
public FieldMappingMetaData(String fullName, BytesReference source) {
this.fullName = fullName;
this.source = source;
}
public String fullName() {
return fullName;
}
/**
* Returns the mappings as a map. Note that the returned map has a single key which is always the field's {@link Mapper#name}.
*/
public Map<String, Object> sourceAsMap() {
return XContentHelper.convertToMap(source, true, XContentType.JSON).v2();
}
//pkg-private for testing
BytesReference getSource() {
return source;
}
public static FieldMappingMetaData fromXContent(XContentParser parser) throws IOException {
return PARSER.parse(parser, null);
}
@Override
public String toString() {
return "FieldMappingMetaData{fullName='" + fullName + '\'' + ", source=" + source + '}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof FieldMappingMetaData)) return false;
FieldMappingMetaData that = (FieldMappingMetaData) o;
return Objects.equals(fullName, that.fullName) && Objects.equals(source, that.source);
}
@Override
public int hashCode() {
return Objects.hash(fullName, source);
}
}
@Override
public String toString() {
return "GetFieldMappingsResponse{" + "mappings=" + mappings + '}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof GetFieldMappingsResponse)) return false;
GetFieldMappingsResponse that = (GetFieldMappingsResponse) o;
return Objects.equals(mappings, that.mappings);
}
@Override
public int hashCode() {
return Objects.hash(mappings);
}
}

View File

@ -43,8 +43,8 @@ import org.elasticsearch.action.admin.indices.forcemerge.ForceMergeRequest;
import org.elasticsearch.action.admin.indices.forcemerge.ForceMergeResponse;
import org.elasticsearch.action.admin.indices.get.GetIndexRequest;
import org.elasticsearch.action.admin.indices.get.GetIndexResponse;
import org.elasticsearch.action.admin.indices.mapping.get.GetFieldMappingsRequest;
import org.elasticsearch.action.admin.indices.mapping.get.GetFieldMappingsResponse;
import org.elasticsearch.client.indices.GetFieldMappingsRequest;
import org.elasticsearch.client.indices.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.open.OpenIndexRequest;
@ -93,6 +93,7 @@ import org.elasticsearch.index.mapper.MapperService;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.rest.RestStatus;
import org.elasticsearch.rest.action.admin.indices.RestGetFieldMappingAction;
import org.elasticsearch.rest.action.admin.indices.RestPutMappingAction;
import java.io.IOException;
@ -500,7 +501,6 @@ public class IndicesClientIT extends ESRestHighLevelClientTestCase {
GetFieldMappingsRequest getFieldMappingsRequest = new GetFieldMappingsRequest()
.indices(indexName)
.types("_doc")
.fields("field");
GetFieldMappingsResponse getFieldMappingsResponse =
@ -509,7 +509,7 @@ public class IndicesClientIT extends ESRestHighLevelClientTestCase {
highLevelClient().indices()::getFieldMappingAsync);
final Map<String, GetFieldMappingsResponse.FieldMappingMetaData> fieldMappingMap =
getFieldMappingsResponse.mappings().get(indexName).get("_doc");
getFieldMappingsResponse.mappings().get(indexName);
final GetFieldMappingsResponse.FieldMappingMetaData metaData =
new GetFieldMappingsResponse.FieldMappingMetaData("field",
@ -517,6 +517,42 @@ public class IndicesClientIT extends ESRestHighLevelClientTestCase {
assertThat(fieldMappingMap, equalTo(Collections.singletonMap("field", metaData)));
}
public void testGetFieldMappingWithTypes() throws IOException {
String indexName = "test";
createIndex(indexName, Settings.EMPTY);
PutMappingRequest putMappingRequest = new PutMappingRequest(indexName);
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);
assertTrue(putMappingResponse.isAcknowledged());
org.elasticsearch.action.admin.indices.mapping.get.GetFieldMappingsRequest getFieldMappingsRequest =
new org.elasticsearch.action.admin.indices.mapping.get.GetFieldMappingsRequest()
.indices(indexName)
.types("_doc")
.fields("field");
org.elasticsearch.action.admin.indices.mapping.get.GetFieldMappingsResponse getFieldMappingsResponse =
execute(getFieldMappingsRequest,
highLevelClient().indices()::getFieldMapping,
highLevelClient().indices()::getFieldMappingAsync,
expectWarnings(RestGetFieldMappingAction.TYPES_DEPRECATION_MESSAGE));
final Map<String, org.elasticsearch.action.admin.indices.mapping.get.GetFieldMappingsResponse.FieldMappingMetaData>
fieldMappingMap = getFieldMappingsResponse.mappings().get(indexName).get("_doc");
final org.elasticsearch.action.admin.indices.mapping.get.GetFieldMappingsResponse.FieldMappingMetaData metaData =
new org.elasticsearch.action.admin.indices.mapping.get.GetFieldMappingsResponse.FieldMappingMetaData("field",
new BytesArray("{\"field\":{\"type\":\"text\"}}"));
assertThat(fieldMappingMap, equalTo(Collections.singletonMap("field", metaData)));
}
public void testDeleteIndex() throws IOException {
{
// Delete index if exists

View File

@ -38,7 +38,6 @@ import org.elasticsearch.action.admin.indices.flush.FlushRequest;
import org.elasticsearch.action.admin.indices.flush.SyncedFlushRequest;
import org.elasticsearch.action.admin.indices.forcemerge.ForceMergeRequest;
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.open.OpenIndexRequest;
import org.elasticsearch.action.admin.indices.refresh.RefreshRequest;
@ -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.client.indices.GetFieldMappingsRequest;
import org.elasticsearch.common.CheckedFunction;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.settings.Settings;
@ -258,7 +258,7 @@ public class IndicesRequestConvertersTests extends ESTestCase {
Assert.assertThat(HttpGet.METHOD_NAME, equalTo(request.getMethod()));
}
public void testGetFieldMapping() throws IOException {
public void testGetFieldMapping() {
GetFieldMappingsRequest getFieldMappingsRequest = new GetFieldMappingsRequest();
String[] indices = Strings.EMPTY_ARRAY;
@ -269,6 +269,50 @@ public class IndicesRequestConvertersTests extends ESTestCase {
getFieldMappingsRequest.indices((String[]) null);
}
String[] fields = null;
if (ESTestCase.randomBoolean()) {
fields = new String[ESTestCase.randomIntBetween(1, 5)];
for (int i = 0; i < fields.length; i++) {
fields[i] = ESTestCase.randomAlphaOfLengthBetween(3, 10);
}
getFieldMappingsRequest.fields(fields);
} else if (ESTestCase.randomBoolean()) {
getFieldMappingsRequest.fields((String[]) null);
}
Map<String, String> expectedParams = new HashMap<>();
RequestConvertersTests.setRandomIndicesOptions(getFieldMappingsRequest::indicesOptions, getFieldMappingsRequest::indicesOptions,
expectedParams);
RequestConvertersTests.setRandomLocal(getFieldMappingsRequest::local, expectedParams);
Request request = IndicesRequestConverters.getFieldMapping(getFieldMappingsRequest);
StringJoiner endpoint = new StringJoiner("/", "/", "");
String index = String.join(",", indices);
if (Strings.hasLength(index)) {
endpoint.add(index);
}
endpoint.add("_mapping");
endpoint.add("field");
if (fields != null) {
endpoint.add(String.join(",", fields));
}
Assert.assertThat(endpoint.toString(), equalTo(request.getEndpoint()));
Assert.assertThat(expectedParams, equalTo(request.getParameters()));
Assert.assertThat(HttpGet.METHOD_NAME, equalTo(request.getMethod()));
}
public void testGetFieldMappingWithTypes() {
org.elasticsearch.action.admin.indices.mapping.get.GetFieldMappingsRequest getFieldMappingsRequest =
new org.elasticsearch.action.admin.indices.mapping.get.GetFieldMappingsRequest();
String[] indices = Strings.EMPTY_ARRAY;
if (ESTestCase.randomBoolean()) {
indices = RequestConvertersTests.randomIndicesNames(0, 5);
getFieldMappingsRequest.indices(indices);
} else if (ESTestCase.randomBoolean()) {
getFieldMappingsRequest.indices((String[]) null);
}
String type = null;
if (ESTestCase.randomBoolean()) {
type = ESTestCase.randomAlphaOfLengthBetween(3, 10);

View File

@ -42,8 +42,8 @@ import org.elasticsearch.action.admin.indices.forcemerge.ForceMergeRequest;
import org.elasticsearch.action.admin.indices.forcemerge.ForceMergeResponse;
import org.elasticsearch.action.admin.indices.get.GetIndexRequest;
import org.elasticsearch.action.admin.indices.get.GetIndexResponse;
import org.elasticsearch.action.admin.indices.mapping.get.GetFieldMappingsRequest;
import org.elasticsearch.action.admin.indices.mapping.get.GetFieldMappingsResponse;
import org.elasticsearch.client.indices.GetFieldMappingsRequest;
import org.elasticsearch.client.indices.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.open.OpenIndexRequest;
@ -725,8 +725,7 @@ public class IndicesClientDocumentationIT extends ESRestHighLevelClientTestCase
// tag::get-field-mappings-request
GetFieldMappingsRequest request = new GetFieldMappingsRequest(); // <1>
request.indices("twitter"); // <2>
request.types("_doc"); // <3>
request.fields("message", "timestamp"); // <4>
request.fields("message", "timestamp"); // <3>
// end::get-field-mappings-request
// tag::get-field-mappings-request-indicesOptions
@ -745,12 +744,12 @@ public class IndicesClientDocumentationIT extends ESRestHighLevelClientTestCase
// end::get-field-mappings-execute
// tag::get-field-mappings-response
final Map<String, Map<String, Map<String, GetFieldMappingsResponse.FieldMappingMetaData>>> mappings =
final Map<String, Map<String, GetFieldMappingsResponse.FieldMappingMetaData>> mappings =
response.mappings();// <1>
final Map<String, GetFieldMappingsResponse.FieldMappingMetaData> typeMappings =
mappings.get("twitter").get("_doc"); // <2>
final Map<String, GetFieldMappingsResponse.FieldMappingMetaData> fieldMappings =
mappings.get("twitter"); // <2>
final GetFieldMappingsResponse.FieldMappingMetaData metaData =
typeMappings.get("message");// <3>
fieldMappings.get("message");// <3>
final String fullName = metaData.fullName();// <4>
final Map<String, Object> source = metaData.sourceAsMap(); // <5>
@ -777,11 +776,11 @@ public class IndicesClientDocumentationIT extends ESRestHighLevelClientTestCase
final CountDownLatch latch = new CountDownLatch(1);
final ActionListener<GetFieldMappingsResponse> latchListener = new LatchedActionListener<>(listener, latch);
listener = ActionListener.wrap(r -> {
final Map<String, Map<String, Map<String, GetFieldMappingsResponse.FieldMappingMetaData>>> mappings =
final Map<String, Map<String, GetFieldMappingsResponse.FieldMappingMetaData>> mappings =
r.mappings();
final Map<String, GetFieldMappingsResponse.FieldMappingMetaData> typeMappings =
mappings.get("twitter").get("_doc");
final GetFieldMappingsResponse.FieldMappingMetaData metaData1 = typeMappings.get("message");
final Map<String, GetFieldMappingsResponse.FieldMappingMetaData> fieldMappings =
mappings.get("twitter");
final GetFieldMappingsResponse.FieldMappingMetaData metaData1 = fieldMappings.get("message");
final String fullName = metaData1.fullName();
final Map<String, Object> source = metaData1.sourceAsMap();

View File

@ -0,0 +1,92 @@
/*
* 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.client.indices.GetFieldMappingsResponse.FieldMappingMetaData;
import org.elasticsearch.common.bytes.BytesArray;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.test.ESTestCase;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Predicate;
import static org.elasticsearch.test.AbstractXContentTestCase.xContentTester;
public class GetFieldMappingsResponseTests extends ESTestCase {
public void testFromXContent() throws IOException {
xContentTester(
this::createParser,
GetFieldMappingsResponseTests::createTestInstance,
GetFieldMappingsResponseTests::toXContent,
GetFieldMappingsResponse::fromXContent)
.supportsUnknownFields(true)
.randomFieldsExcludeFilter(getRandomFieldsExcludeFilter())
.test();
}
Predicate<String> getRandomFieldsExcludeFilter() {
// allow random fields at the level of `index` and `index.mappings.field`
// otherwise random field could be evaluated as index name or type name
return s -> false == (s.matches("(?<index>[^.]+)")
|| s.matches("(?<index>[^.]+)\\.mappings\\.(?<field>[^.]+)"));
}
static GetFieldMappingsResponse createTestInstance() {
Map<String, Map<String, FieldMappingMetaData>> mappings = new HashMap<>();
// if mappings is empty, means that fields are not found
if (randomBoolean()) {
int indices = randomInt(10);
for (int i = 0; i < indices; i++) {
Map<String, FieldMappingMetaData> fieldMappings = new HashMap<>();
int fields = randomInt(10);
for (int k = 0; k < fields; k++) {
final String mapping = randomBoolean() ? "{\"type\":\"string\"}" : "{\"type\":\"keyword\"}";
final String fieldName = randomAlphaOfLength(8);
FieldMappingMetaData metaData = new FieldMappingMetaData(fieldName, new BytesArray(mapping));
fieldMappings.put(fieldName, metaData);
}
mappings.put(randomAlphaOfLength(8), fieldMappings);
}
}
return new GetFieldMappingsResponse(mappings);
}
// As the client class GetFieldMappingsResponse doesn't have toXContent method, adding this method here only for the test
static void toXContent(GetFieldMappingsResponse response, XContentBuilder builder) throws IOException {
builder.startObject();
for (Map.Entry<String, Map<String, FieldMappingMetaData>> indexEntry : response.mappings().entrySet()) {
builder.startObject(indexEntry.getKey());
builder.startObject("mappings");
Map<String, FieldMappingMetaData> mappings = null;
for (Map.Entry<String, FieldMappingMetaData> fieldEntry : indexEntry.getValue().entrySet()) {
builder.startObject(fieldEntry.getKey());
builder.field("full_name", fieldEntry.getValue().fullName());
builder.field("mapping", fieldEntry.getValue().sourceAsMap());
builder.endObject();
}
builder.endObject();
builder.endObject();
}
builder.endObject();
}
}

View File

@ -18,8 +18,7 @@ include-tagged::{doc-tests-file}[{api}-request]
--------------------------------------------------
<1> An empty request
<2> Setting the indices to fetch mapping for
<3> The types to be returned
<4> The fields to be returned
<3> The fields to be returned
==== Optional arguments
The following arguments can also optionally be provided:
@ -53,7 +52,7 @@ executed operation as follows:
include-tagged::{doc-tests-file}[{api}-response]
--------------------------------------------------
<1> Returning all requested indices fields' mappings
<2> Retrieving the mappings for a particular index and type
<2> Retrieving the mappings for a particular index
<3> Getting the mappings metadata for the `message` field
<4> Getting the full name of the field
<5> Getting the mapping source of the field

View File

@ -29,7 +29,12 @@ import org.elasticsearch.common.io.stream.StreamOutput;
import java.io.IOException;
/** Request the mappings of specific fields */
/**
* Request the mappings of specific fields
*
* Note: there is a new class with the same name for the Java HLRC that uses a typeless format.
* Any changes done to this class should go to that client class as well.
*/
public class GetFieldMappingsRequest extends ActionRequest implements IndicesRequest.Replaceable {
protected boolean local = false;

View File

@ -50,7 +50,12 @@ import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
import static org.elasticsearch.common.xcontent.XContentParserUtils.ensureExpectedToken;
import static org.elasticsearch.rest.BaseRestHandler.DEFAULT_INCLUDE_TYPE_NAME_POLICY;
/** Response object for {@link GetFieldMappingsRequest} API */
/**
* Response object for {@link GetFieldMappingsRequest} API
*
* Note: there is a new class with the same name for the Java HLRC that uses a typeless format.
* Any changes done to this class should go to that client class as well.
*/
public class GetFieldMappingsResponse extends ActionResponse implements ToXContentObject {
private static final ParseField MAPPINGS = new ParseField("mappings");

View File

@ -19,12 +19,14 @@
package org.elasticsearch.rest.action.admin.indices;
import org.apache.logging.log4j.LogManager;
import org.elasticsearch.action.admin.indices.mapping.get.GetFieldMappingsRequest;
import org.elasticsearch.action.admin.indices.mapping.get.GetFieldMappingsResponse;
import org.elasticsearch.action.admin.indices.mapping.get.GetFieldMappingsResponse.FieldMappingMetaData;
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.common.xcontent.XContentBuilder;
import org.elasticsearch.rest.BaseRestHandler;
@ -43,6 +45,12 @@ import static org.elasticsearch.rest.RestStatus.NOT_FOUND;
import static org.elasticsearch.rest.RestStatus.OK;
public class RestGetFieldMappingAction extends BaseRestHandler {
private static final DeprecationLogger deprecationLogger = new DeprecationLogger(
LogManager.getLogger(RestPutMappingAction.class));
public static final String TYPES_DEPRECATION_MESSAGE = "[types removal] Using include_type_name in get " +
"field mapping requests is deprecated. The parameter will be removed in the next major version.";
public RestGetFieldMappingAction(Settings settings, RestController controller) {
super(settings);
controller.registerHandler(GET, "/_mapping/field/{fields}", this);
@ -68,6 +76,9 @@ public class RestGetFieldMappingAction extends BaseRestHandler {
throw new IllegalArgumentException("Types cannot be specified unless include_type_name" +
" is set to true.");
}
if (request.hasParam(INCLUDE_TYPE_NAME_PARAMETER)) {
deprecationLogger.deprecatedAndMaybeLog("get_field_mapping_with_types", TYPES_DEPRECATION_MESSAGE);
}
GetFieldMappingsRequest getMappingsRequest = new GetFieldMappingsRequest();
getMappingsRequest.indices(indices).types(types).fields(fields).includeDefaults(request.paramAsBoolean("include_defaults", false));

View File

@ -40,6 +40,31 @@ public class RestGetFieldMappingActionTests extends RestActionTestCase {
new RestGetFieldMappingAction(Settings.EMPTY, controller());
}
public void testIncludeTypeName() {
Map<String, String> params = new HashMap<>();
String path;
if (randomBoolean()) {
params.put(INCLUDE_TYPE_NAME_PARAMETER, "true");
path = "some_index/some_type/_mapping/field/some_field";
} else {
params.put(INCLUDE_TYPE_NAME_PARAMETER, "false");
path = "some_index/_mapping/field/some_field";
}
RestRequest deprecatedRequest = new FakeRestRequest.Builder(xContentRegistry())
.withMethod(RestRequest.Method.GET)
.withPath(path)
.withParams(params)
.build();
dispatchRequest(deprecatedRequest);
assertWarnings(RestGetFieldMappingAction.TYPES_DEPRECATION_MESSAGE);
RestRequest validRequest = new FakeRestRequest.Builder(xContentRegistry())
.withMethod(RestRequest.Method.GET)
.withPath("some_index/_mapping/field/some_field")
.build();
dispatchRequest(validRequest);
}
public void testTypeInPath() {
// Test that specifying a type while setting include_type_name to false
// results in an illegal argument exception.