Skip to content

Commit b7ef75f

Browse files
Add get field mappings to High Level REST API Client (#31423)
Add get field mappings to High Level REST API Client Relates to #27205
1 parent b6cc6fc commit b7ef75f

File tree

9 files changed

+562
-8
lines changed

9 files changed

+562
-8
lines changed

client/rest-high-level/src/main/java/org/elasticsearch/client/IndicesClient.java

+31
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@
3737
import org.elasticsearch.action.admin.indices.forcemerge.ForceMergeRequest;
3838
import org.elasticsearch.action.admin.indices.forcemerge.ForceMergeResponse;
3939
import org.elasticsearch.action.admin.indices.get.GetIndexRequest;
40+
import org.elasticsearch.action.admin.indices.mapping.get.GetFieldMappingsRequest;
41+
import org.elasticsearch.action.admin.indices.mapping.get.GetFieldMappingsResponse;
4042
import org.elasticsearch.action.admin.indices.mapping.get.GetMappingsRequest;
4143
import org.elasticsearch.action.admin.indices.mapping.get.GetMappingsResponse;
4244
import org.elasticsearch.action.admin.indices.mapping.put.PutMappingRequest;
@@ -188,6 +190,35 @@ public void getMappingsAsync(GetMappingsRequest getMappingsRequest, RequestOptio
188190
GetMappingsResponse::fromXContent, listener, emptySet());
189191
}
190192

193+
/**
194+
* Retrieves the field mappings on an index or indices using the Get Field Mapping API.
195+
* See <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-get-field-mapping.html">
196+
* Get Field Mapping API on elastic.co</a>
197+
* @param getFieldMappingsRequest the request
198+
* @param options the request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized
199+
* @return the response
200+
* @throws IOException in case there is a problem sending the request or parsing back the response
201+
*/
202+
public GetFieldMappingsResponse getFieldMapping(GetFieldMappingsRequest getFieldMappingsRequest,
203+
RequestOptions options) throws IOException {
204+
return restHighLevelClient.performRequestAndParseEntity(getFieldMappingsRequest, RequestConverters::getFieldMapping, options,
205+
GetFieldMappingsResponse::fromXContent, emptySet());
206+
}
207+
208+
/**
209+
* Asynchronously retrieves the field mappings on an index on indices using the Get Field Mapping API.
210+
* See <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-get-field-mapping.html">
211+
* Get Field Mapping API on elastic.co</a>
212+
* @param getFieldMappingsRequest the request
213+
* @param options the request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized
214+
* @param listener the listener to be notified upon request completion
215+
*/
216+
public void getFieldMappingAsync(GetFieldMappingsRequest getFieldMappingsRequest, RequestOptions options,
217+
ActionListener<GetFieldMappingsResponse> listener) {
218+
restHighLevelClient.performRequestAsyncAndParseEntity(getFieldMappingsRequest, RequestConverters::getFieldMapping, options,
219+
GetFieldMappingsResponse::fromXContent, listener, emptySet());
220+
}
221+
191222
/**
192223
* Updates aliases using the Index Aliases API.
193224
* See <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-aliases.html">

client/rest-high-level/src/main/java/org/elasticsearch/client/RequestConverters.java

+20
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@
5050
import org.elasticsearch.action.admin.indices.flush.SyncedFlushRequest;
5151
import org.elasticsearch.action.admin.indices.forcemerge.ForceMergeRequest;
5252
import org.elasticsearch.action.admin.indices.get.GetIndexRequest;
53+
import org.elasticsearch.action.admin.indices.mapping.get.GetFieldMappingsRequest;
5354
import org.elasticsearch.action.admin.indices.mapping.get.GetMappingsRequest;
5455
import org.elasticsearch.action.admin.indices.mapping.put.PutMappingRequest;
5556
import org.elasticsearch.action.admin.indices.open.OpenIndexRequest;
@@ -230,6 +231,25 @@ static Request getMappings(GetMappingsRequest getMappingsRequest) throws IOExcep
230231
return request;
231232
}
232233

234+
static Request getFieldMapping(GetFieldMappingsRequest getFieldMappingsRequest) throws IOException {
235+
String[] indices = getFieldMappingsRequest.indices() == null ? Strings.EMPTY_ARRAY : getFieldMappingsRequest.indices();
236+
String[] types = getFieldMappingsRequest.types() == null ? Strings.EMPTY_ARRAY : getFieldMappingsRequest.types();
237+
String[] fields = getFieldMappingsRequest.fields() == null ? Strings.EMPTY_ARRAY : getFieldMappingsRequest.fields();
238+
239+
String endpoint = new EndpointBuilder().addCommaSeparatedPathParts(indices)
240+
.addPathPartAsIs("_mapping").addCommaSeparatedPathParts(types)
241+
.addPathPartAsIs("field").addCommaSeparatedPathParts(fields)
242+
.build();
243+
244+
Request request = new Request(HttpGet.METHOD_NAME, endpoint);
245+
246+
Params parameters = new Params(request);
247+
parameters.withIndicesOptions(getFieldMappingsRequest.indicesOptions());
248+
parameters.withIncludeDefaults(getFieldMappingsRequest.includeDefaults());
249+
parameters.withLocal(getFieldMappingsRequest.local());
250+
return request;
251+
}
252+
233253
static Request refresh(RefreshRequest refreshRequest) {
234254
String[] indices = refreshRequest.indices() == null ? Strings.EMPTY_ARRAY : refreshRequest.indices();
235255
Request request = new Request(HttpPost.METHOD_NAME, endpoint(indices, "_refresh"));

client/rest-high-level/src/test/java/org/elasticsearch/client/IndicesClientIT.java

+38
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@
4343
import org.elasticsearch.action.admin.indices.forcemerge.ForceMergeRequest;
4444
import org.elasticsearch.action.admin.indices.forcemerge.ForceMergeResponse;
4545
import org.elasticsearch.action.admin.indices.get.GetIndexRequest;
46+
import org.elasticsearch.action.admin.indices.mapping.get.GetFieldMappingsRequest;
47+
import org.elasticsearch.action.admin.indices.mapping.get.GetFieldMappingsResponse;
4648
import org.elasticsearch.action.admin.indices.mapping.get.GetMappingsRequest;
4749
import org.elasticsearch.action.admin.indices.mapping.get.GetMappingsResponse;
4850
import org.elasticsearch.action.admin.indices.mapping.put.PutMappingRequest;
@@ -74,6 +76,7 @@
7476
import org.elasticsearch.cluster.metadata.IndexMetaData;
7577
import org.elasticsearch.cluster.metadata.IndexTemplateMetaData;
7678
import org.elasticsearch.common.ValidationException;
79+
import org.elasticsearch.common.bytes.BytesArray;
7780
import org.elasticsearch.common.settings.Setting;
7881
import org.elasticsearch.common.settings.Settings;
7982
import org.elasticsearch.common.unit.ByteSizeUnit;
@@ -378,6 +381,41 @@ public void testGetMapping() throws IOException {
378381
assertThat(mappings, equalTo(expected));
379382
}
380383

384+
public void testGetFieldMapping() throws IOException {
385+
String indexName = "test";
386+
createIndex(indexName, Settings.EMPTY);
387+
388+
PutMappingRequest putMappingRequest = new PutMappingRequest(indexName);
389+
putMappingRequest.type("_doc");
390+
XContentBuilder mappingBuilder = JsonXContent.contentBuilder();
391+
mappingBuilder.startObject().startObject("properties").startObject("field");
392+
mappingBuilder.field("type", "text");
393+
mappingBuilder.endObject().endObject().endObject();
394+
putMappingRequest.source(mappingBuilder);
395+
396+
PutMappingResponse putMappingResponse =
397+
execute(putMappingRequest, highLevelClient().indices()::putMapping, highLevelClient().indices()::putMappingAsync);
398+
assertTrue(putMappingResponse.isAcknowledged());
399+
400+
GetFieldMappingsRequest getFieldMappingsRequest = new GetFieldMappingsRequest()
401+
.indices(indexName)
402+
.types("_doc")
403+
.fields("field");
404+
405+
GetFieldMappingsResponse getFieldMappingsResponse =
406+
execute(getFieldMappingsRequest,
407+
highLevelClient().indices()::getFieldMapping,
408+
highLevelClient().indices()::getFieldMappingAsync);
409+
410+
final Map<String, GetFieldMappingsResponse.FieldMappingMetaData> fieldMappingMap =
411+
getFieldMappingsResponse.mappings().get(indexName).get("_doc");
412+
413+
final GetFieldMappingsResponse.FieldMappingMetaData metaData =
414+
new GetFieldMappingsResponse.FieldMappingMetaData("field",
415+
new BytesArray("{\"field\":{\"type\":\"text\"}}"));
416+
assertThat(fieldMappingMap, equalTo(Collections.singletonMap("field", metaData)));
417+
}
418+
381419
public void testDeleteIndex() throws IOException {
382420
{
383421
// Delete index if exists

client/rest-high-level/src/test/java/org/elasticsearch/client/RequestConvertersTests.java

+62-2
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252
import org.elasticsearch.action.admin.indices.flush.SyncedFlushRequest;
5353
import org.elasticsearch.action.admin.indices.forcemerge.ForceMergeRequest;
5454
import org.elasticsearch.action.admin.indices.get.GetIndexRequest;
55+
import org.elasticsearch.action.admin.indices.mapping.get.GetFieldMappingsRequest;
5556
import org.elasticsearch.action.admin.indices.mapping.get.GetMappingsRequest;
5657
import org.elasticsearch.action.admin.indices.mapping.put.PutMappingRequest;
5758
import org.elasticsearch.action.admin.indices.open.OpenIndexRequest;
@@ -457,6 +458,61 @@ public void testGetMapping() throws IOException {
457458
assertThat(HttpGet.METHOD_NAME, equalTo(request.getMethod()));
458459
}
459460

461+
public void testGetFieldMapping() throws IOException {
462+
GetFieldMappingsRequest getFieldMappingsRequest = new GetFieldMappingsRequest();
463+
464+
String[] indices = Strings.EMPTY_ARRAY;
465+
if (randomBoolean()) {
466+
indices = randomIndicesNames(0, 5);
467+
getFieldMappingsRequest.indices(indices);
468+
} else if (randomBoolean()) {
469+
getFieldMappingsRequest.indices((String[]) null);
470+
}
471+
472+
String type = null;
473+
if (randomBoolean()) {
474+
type = randomAlphaOfLengthBetween(3, 10);
475+
getFieldMappingsRequest.types(type);
476+
} else if (randomBoolean()) {
477+
getFieldMappingsRequest.types((String[]) null);
478+
}
479+
480+
String[] fields = null;
481+
if (randomBoolean()) {
482+
fields = new String[randomIntBetween(1, 5)];
483+
for (int i = 0; i < fields.length; i++) {
484+
fields[i] = randomAlphaOfLengthBetween(3, 10);
485+
}
486+
getFieldMappingsRequest.fields(fields);
487+
} else if (randomBoolean()) {
488+
getFieldMappingsRequest.fields((String[]) null);
489+
}
490+
491+
Map<String, String> expectedParams = new HashMap<>();
492+
493+
setRandomIndicesOptions(getFieldMappingsRequest::indicesOptions, getFieldMappingsRequest::indicesOptions, expectedParams);
494+
setRandomLocal(getFieldMappingsRequest::local, expectedParams);
495+
496+
Request request = RequestConverters.getFieldMapping(getFieldMappingsRequest);
497+
StringJoiner endpoint = new StringJoiner("/", "/", "");
498+
String index = String.join(",", indices);
499+
if (Strings.hasLength(index)) {
500+
endpoint.add(index);
501+
}
502+
endpoint.add("_mapping");
503+
if (type != null) {
504+
endpoint.add(type);
505+
}
506+
endpoint.add("field");
507+
if (fields != null) {
508+
endpoint.add(String.join(",", fields));
509+
}
510+
assertThat(endpoint.toString(), equalTo(request.getEndpoint()));
511+
512+
assertThat(expectedParams, equalTo(request.getParameters()));
513+
assertThat(HttpGet.METHOD_NAME, equalTo(request.getMethod()));
514+
}
515+
460516
public void testDeleteIndex() {
461517
String[] indices = randomIndicesNames(0, 5);
462518
DeleteIndexRequest deleteIndexRequest = new DeleteIndexRequest(indices);
@@ -2268,16 +2324,20 @@ private static void setRandomHumanReadable(GetIndexRequest request, Map<String,
22682324
}
22692325
}
22702326

2271-
private static void setRandomLocal(MasterNodeReadRequest<?> request, Map<String, String> expectedParams) {
2327+
private static void setRandomLocal(Consumer<Boolean> setter, Map<String, String> expectedParams) {
22722328
if (randomBoolean()) {
22732329
boolean local = randomBoolean();
2274-
request.local(local);
2330+
setter.accept(local);
22752331
if (local) {
22762332
expectedParams.put("local", String.valueOf(local));
22772333
}
22782334
}
22792335
}
22802336

2337+
private static void setRandomLocal(MasterNodeReadRequest<?> request, Map<String, String> expectedParams) {
2338+
setRandomLocal(request::local, expectedParams);
2339+
}
2340+
22812341
private static void setRandomTimeout(Consumer<String> setter, TimeValue defaultTimeout, Map<String, String> expectedParams) {
22822342
if (randomBoolean()) {
22832343
String timeout = randomTimeValue();

client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/IndicesClientDocumentationIT.java

+106
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@
4141
import org.elasticsearch.action.admin.indices.forcemerge.ForceMergeRequest;
4242
import org.elasticsearch.action.admin.indices.forcemerge.ForceMergeResponse;
4343
import org.elasticsearch.action.admin.indices.get.GetIndexRequest;
44+
import org.elasticsearch.action.admin.indices.mapping.get.GetFieldMappingsRequest;
45+
import org.elasticsearch.action.admin.indices.mapping.get.GetFieldMappingsResponse;
4446
import org.elasticsearch.action.admin.indices.mapping.get.GetMappingsRequest;
4547
import org.elasticsearch.action.admin.indices.mapping.get.GetMappingsResponse;
4648
import org.elasticsearch.action.admin.indices.mapping.put.PutMappingRequest;
@@ -703,6 +705,110 @@ public void onFailure(Exception e) {
703705
}
704706
}
705707

708+
public void testGetFieldMapping() throws IOException, InterruptedException {
709+
RestHighLevelClient client = highLevelClient();
710+
711+
{
712+
CreateIndexResponse createIndexResponse = client.indices().create(new CreateIndexRequest("twitter"), RequestOptions.DEFAULT);
713+
assertTrue(createIndexResponse.isAcknowledged());
714+
PutMappingRequest request = new PutMappingRequest("twitter");
715+
request.type("tweet");
716+
request.source(
717+
"{\n" +
718+
" \"properties\": {\n" +
719+
" \"message\": {\n" +
720+
" \"type\": \"text\"\n" +
721+
" },\n" +
722+
" \"timestamp\": {\n" +
723+
" \"type\": \"date\"\n" +
724+
" }\n" +
725+
" }\n" +
726+
"}", // <1>
727+
XContentType.JSON);
728+
PutMappingResponse putMappingResponse = client.indices().putMapping(request, RequestOptions.DEFAULT);
729+
assertTrue(putMappingResponse.isAcknowledged());
730+
}
731+
732+
// tag::get-field-mapping-request
733+
GetFieldMappingsRequest request = new GetFieldMappingsRequest(); // <1>
734+
request.indices("twitter"); // <2>
735+
request.types("tweet"); // <3>
736+
request.fields("message", "timestamp"); // <4>
737+
// end::get-field-mapping-request
738+
739+
// tag::get-field-mapping-request-indicesOptions
740+
request.indicesOptions(IndicesOptions.lenientExpandOpen()); // <1>
741+
// end::get-field-mapping-request-indicesOptions
742+
743+
// tag::get-field-mapping-request-local
744+
request.local(true); // <1>
745+
// end::get-field-mapping-request-local
746+
747+
{
748+
749+
// tag::get-field-mapping-execute
750+
GetFieldMappingsResponse response =
751+
client.indices().getFieldMapping(request, RequestOptions.DEFAULT);
752+
// end::get-field-mapping-execute
753+
754+
// tag::get-field-mapping-response
755+
final Map<String, Map<String, Map<String, GetFieldMappingsResponse.FieldMappingMetaData>>> mappings =
756+
response.mappings();// <1>
757+
final Map<String, GetFieldMappingsResponse.FieldMappingMetaData> typeMappings =
758+
mappings.get("twitter").get("tweet"); // <2>
759+
final GetFieldMappingsResponse.FieldMappingMetaData metaData =
760+
typeMappings.get("message");// <3>
761+
762+
final String fullName = metaData.fullName();// <4>
763+
final Map<String, Object> source = metaData.sourceAsMap(); // <5>
764+
// end::get-field-mapping-response
765+
}
766+
767+
{
768+
// tag::get-field-mapping-execute-listener
769+
ActionListener<GetFieldMappingsResponse> listener =
770+
new ActionListener<GetFieldMappingsResponse>() {
771+
@Override
772+
public void onResponse(GetFieldMappingsResponse putMappingResponse) {
773+
// <1>
774+
}
775+
776+
@Override
777+
public void onFailure(Exception e) {
778+
// <2>
779+
}
780+
};
781+
// end::get-field-mapping-execute-listener
782+
783+
// Replace the empty listener by a blocking listener in test
784+
final CountDownLatch latch = new CountDownLatch(1);
785+
final ActionListener<GetFieldMappingsResponse> latchListener = new LatchedActionListener<>(listener, latch);
786+
listener = ActionListener.wrap(r -> {
787+
final Map<String, Map<String, Map<String, GetFieldMappingsResponse.FieldMappingMetaData>>> mappings =
788+
r.mappings();
789+
final Map<String, GetFieldMappingsResponse.FieldMappingMetaData> typeMappings =
790+
mappings.get("twitter").get("tweet");
791+
final GetFieldMappingsResponse.FieldMappingMetaData metaData1 = typeMappings.get("message");
792+
793+
final String fullName = metaData1.fullName();
794+
final Map<String, Object> source = metaData1.sourceAsMap();
795+
latchListener.onResponse(r);
796+
}, e -> {
797+
latchListener.onFailure(e);
798+
fail("should not fail");
799+
});
800+
801+
// tag::get-field-mapping-execute-async
802+
client.indices().getFieldMappingAsync(request, RequestOptions.DEFAULT, listener); // <1>
803+
// end::get-field-mapping-execute-async
804+
805+
assertTrue(latch.await(30L, TimeUnit.SECONDS));
806+
}
807+
808+
809+
}
810+
811+
706812
public void testOpenIndex() throws Exception {
707813
RestHighLevelClient client = highLevelClient();
708814

0 commit comments

Comments
 (0)