Consistent APIs: Get field mapping API includes 'mappings'

The get field mapping API now includes a mappings element after the index in its JSON

Added more consistent endpoint /{index}/_mapping/{type}/field/{fields}
and added endpoint /_mapping/{type}/field/{fields}
which are also used in tests

Added rest spec tests for wildcards and _all

Relates #4071

NOTE: This is not yet complete for 1.0. We need to return an empty JSON document instead
of a 404 if the field of an existing index and type is not found. However this is not
possible with the current data structure being returned. Needs to be finished for 1.0.
This commit is contained in:
Alexander Reelsen 2014-01-14 22:39:28 +01:00
parent 349a8be4fd
commit a3abcdc93a
5 changed files with 112 additions and 26 deletions

View File

@ -4,7 +4,7 @@
"methods": ["GET"], "methods": ["GET"],
"url": { "url": {
"path": "/_mapping/field/{field}", "path": "/_mapping/field/{field}",
"paths": ["/_mapping/field/{field}", "/{index}/_mapping/field/{field}", "/{index}/{type}/_mapping/field/{field}"], "paths": ["/_mapping/field/{field}", "/{index}/_mapping/field/{field}", "/_mapping/{type}/field/{field}", "/{index}/_mapping/{type}/field/{field}"],
"parts": { "parts": {
"index": { "index": {
"type" : "list", "type" : "list",

View File

@ -17,7 +17,7 @@ setup:
indices.get_field_mapping: indices.get_field_mapping:
field: text field: text
- match: {test_index.test_type.text.mapping.text.type: string} - match: {test_index.mappings.test_type.text.mapping.text.type: string}
--- ---
"Get field mapping by index only": "Get field mapping by index only":
@ -26,7 +26,7 @@ setup:
index: test_index index: test_index
field: text field: text
- match: {test_index.test_type.text.mapping.text.type: string} - match: {test_index.mappings.test_type.text.mapping.text.type: string}
--- ---
"Get field mapping by type & field": "Get field mapping by type & field":
@ -37,7 +37,7 @@ setup:
type: test_type type: test_type
field: text field: text
- match: {test_index.test_type.text.mapping.text.type: string} - match: {test_index.mappings.test_type.text.mapping.text.type: string}
--- ---
"Get field mapping by type & field, with another field that doesn't exist": "Get field mapping by type & field, with another field that doesn't exist":
@ -48,8 +48,8 @@ setup:
type: test_type type: test_type
field: [ text , text1 ] field: [ text , text1 ]
- match: {test_index.test_type.text.mapping.text.type: string} - match: {test_index.mappings.test_type.text.mapping.text.type: string}
- is_false: test_index.test_type.text1 - is_false: test_index.mappings.test_type.text1
--- ---
"Get field mapping with include_defaults": "Get field mapping with include_defaults":
@ -61,5 +61,16 @@ setup:
field: text field: text
include_defaults: true include_defaults: true
- match: {test_index.test_type.text.mapping.text.type: string} - match: {test_index.mappings.test_type.text.mapping.text.type: string}
- match: {test_index.test_type.text.mapping.text.analyzer: default} - match: {test_index.mappings.test_type.text.mapping.text.analyzer: default}
---
"Get field mapping should work without index specifying type and field":
- do:
indices.get_field_mapping:
type: test_type
field: text
- match: {test_index.mappings.test_type.text.mapping.text.type: string}

View File

@ -23,6 +23,29 @@ setup:
type: string type: string
index_name: t3 index_name: t3
- do:
indices.create:
index: test_index_2
body:
mappings:
test_type_2:
properties:
t1:
type: string
t2:
type: string
obj:
path: just_name
properties:
t1:
type: string
i_t1:
type: string
index_name: t1
i_t3:
type: string
index_name: t3
--- ---
"Get field mapping with * for fields": "Get field mapping with * for fields":
@ -30,43 +53,92 @@ setup:
indices.get_field_mapping: indices.get_field_mapping:
field: "*" field: "*"
- match: {test_index.test_type.t1.full_name: t1 } - match: {test_index.mappings.test_type.t1.full_name: t1 }
- match: {test_index.test_type.t2.full_name: t2 } - match: {test_index.mappings.test_type.t2.full_name: t2 }
- match: {test_index.test_type.obj\.t1.full_name: obj.t1 } - match: {test_index.mappings.test_type.obj\.t1.full_name: obj.t1 }
- match: {test_index.test_type.obj\.i_t1.full_name: obj.i_t1 } - match: {test_index.mappings.test_type.obj\.i_t1.full_name: obj.i_t1 }
- match: {test_index.test_type.obj\.i_t3.full_name: obj.i_t3 } - match: {test_index.mappings.test_type.obj\.i_t3.full_name: obj.i_t3 }
--- ---
"Get field mapping with t* for fields": "Get field mapping with t* for fields":
- do: - do:
indices.get_field_mapping: indices.get_field_mapping:
index: test_index
field: "t*" field: "t*"
# i_t1 matches the pattern using it's index name, but t1 already means a full name # i_t1 matches the pattern using it's index name, but t1 already means a full name
# of a field and thus takes precedence. # of a field and thus takes precedence.
- match: {test_index.test_type.t1.full_name: t1 } - match: {test_index.mappings.test_type.t1.full_name: t1 }
- match: {test_index.test_type.t2.full_name: t2 } - match: {test_index.mappings.test_type.t2.full_name: t2 }
- match: {test_index.test_type.t3.full_name: obj.i_t3 } - match: {test_index.mappings.test_type.t3.full_name: obj.i_t3 }
- length: {test_index.test_type: 3} - length: {test_index.mappings.test_type: 3}
--- ---
"Get field mapping with *t1 for fields": "Get field mapping with *t1 for fields":
- do: - do:
indices.get_field_mapping: indices.get_field_mapping:
index: test_index
field: "*t1" field: "*t1"
- match: {test_index.test_type.t1.full_name: t1 } - match: {test_index.mappings.test_type.t1.full_name: t1 }
- match: {test_index.test_type.obj\.t1.full_name: obj.t1 } - match: {test_index.mappings.test_type.obj\.t1.full_name: obj.t1 }
- match: {test_index.test_type.obj\.i_t1.full_name: obj.i_t1 } - match: {test_index.mappings.test_type.obj\.i_t1.full_name: obj.i_t1 }
- length: {test_index.test_type: 3} - length: {test_index.mappings.test_type: 3}
--- ---
"Get field mapping with wildcarded relative names": "Get field mapping with wildcarded relative names":
- do: - do:
indices.get_field_mapping: indices.get_field_mapping:
index: test_index
field: "i_*" field: "i_*"
- match: {test_index.test_type.i_t1.full_name: obj.i_t1 } - match: {test_index.mappings.test_type.i_t1.full_name: obj.i_t1 }
- match: {test_index.test_type.i_t3.full_name: obj.i_t3 } - match: {test_index.mappings.test_type.i_t3.full_name: obj.i_t3 }
- length: {test_index.test_type: 2} - length: {test_index.mappings.test_type: 2}
---
"Get field mapping should work using '_all' for indices and types":
- do:
indices.get_field_mapping:
index: _all
type: _all
field: "i_*"
- match: {test_index.mappings.test_type.i_t1.full_name: obj.i_t1 }
- match: {test_index.mappings.test_type.i_t3.full_name: obj.i_t3 }
- length: {test_index.mappings.test_type: 2}
- match: {test_index_2.mappings.test_type_2.i_t1.full_name: obj.i_t1 }
- match: {test_index_2.mappings.test_type_2.i_t3.full_name: obj.i_t3 }
- length: {test_index_2.mappings.test_type_2: 2}
---
"Get field mapping should work using '*' for indices and types":
- do:
indices.get_field_mapping:
index: '*'
type: '*'
field: "i_*"
- match: {test_index.mappings.test_type.i_t1.full_name: obj.i_t1 }
- match: {test_index.mappings.test_type.i_t3.full_name: obj.i_t3 }
- length: {test_index.mappings.test_type: 2}
- match: {test_index_2.mappings.test_type_2.i_t1.full_name: obj.i_t1 }
- match: {test_index_2.mappings.test_type_2.i_t3.full_name: obj.i_t3 }
- length: {test_index_2.mappings.test_type_2: 2}
---
"Get field mapping should work using comma_separated values for indices and types":
- do:
indices.get_field_mapping:
index: 'test_index,test_index_2'
type: 'test_type,test_type_2'
field: "i_*"
- match: {test_index.mappings.test_type.i_t1.full_name: obj.i_t1 }
- match: {test_index.mappings.test_type.i_t3.full_name: obj.i_t3 }
- length: {test_index.mappings.test_type: 2}
- match: {test_index_2.mappings.test_type_2.i_t1.full_name: obj.i_t1 }
- match: {test_index_2.mappings.test_type_2.i_t3.full_name: obj.i_t3 }
- length: {test_index_2.mappings.test_type_2: 2}

View File

@ -71,6 +71,7 @@ public class GetFieldMappingsResponse extends ActionResponse implements ToXConte
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
for (Map.Entry<String, ImmutableMap<String, ImmutableMap<String, FieldMappingMetaData>>> indexEntry : mappings.entrySet()) { for (Map.Entry<String, ImmutableMap<String, ImmutableMap<String, FieldMappingMetaData>>> indexEntry : mappings.entrySet()) {
builder.startObject(indexEntry.getKey(), XContentBuilder.FieldCaseConversion.NONE); builder.startObject(indexEntry.getKey(), XContentBuilder.FieldCaseConversion.NONE);
builder.startObject("mappings");
for (Map.Entry<String, ImmutableMap<String, FieldMappingMetaData>> typeEntry : indexEntry.getValue().entrySet()) { for (Map.Entry<String, ImmutableMap<String, FieldMappingMetaData>> typeEntry : indexEntry.getValue().entrySet()) {
builder.startObject(typeEntry.getKey(), XContentBuilder.FieldCaseConversion.NONE); builder.startObject(typeEntry.getKey(), XContentBuilder.FieldCaseConversion.NONE);
for (Map.Entry<String, FieldMappingMetaData> fieldEntry : typeEntry.getValue().entrySet()) { for (Map.Entry<String, FieldMappingMetaData> fieldEntry : typeEntry.getValue().entrySet()) {
@ -81,6 +82,7 @@ public class GetFieldMappingsResponse extends ActionResponse implements ToXConte
builder.endObject(); builder.endObject();
} }
builder.endObject(); builder.endObject();
builder.endObject();
} }
return builder; return builder;
} }

View File

@ -49,17 +49,18 @@ public class RestGetFieldMappingAction extends BaseRestHandler {
public RestGetFieldMappingAction(Settings settings, Client client, RestController controller) { public RestGetFieldMappingAction(Settings settings, Client client, RestController controller) {
super(settings, client); super(settings, client);
controller.registerHandler(GET, "/_mapping/field/{fields}", this); controller.registerHandler(GET, "/_mapping/field/{fields}", this);
controller.registerHandler(GET, "/_mapping/{type}/field/{fields}", this);
controller.registerHandler(GET, "/{index}/_mapping/field/{fields}", this); controller.registerHandler(GET, "/{index}/_mapping/field/{fields}", this);
controller.registerHandler(GET, "/{index}/{type}/_mapping/field/{fields}", this); controller.registerHandler(GET, "/{index}/{type}/_mapping/field/{fields}", this);
controller.registerHandler(GET, "/{index}/_mapping/{type}/field/{fields}", this);
} }
@Override @Override
public void handleRequest(final RestRequest request, final RestChannel channel) { public void handleRequest(final RestRequest request, final RestChannel channel) {
final String[] indices = Strings.splitStringByCommaToArray(request.param("index")); final String[] indices = Strings.splitStringByCommaToArray(request.param("index"));
final String[] types = Strings.splitStringByCommaToArray(request.param("type")); final String[] types = request.paramAsStringArrayOrEmptyIfAll("type");
boolean local = request.paramAsBooleanOptional("local", false); boolean local = request.paramAsBooleanOptional("local", false);
final String[] fields = Strings.splitStringByCommaToArray(request.param("fields")); final String[] fields = Strings.splitStringByCommaToArray(request.param("fields"));
GetFieldMappingsRequest getMappingsRequest = new GetFieldMappingsRequest(); GetFieldMappingsRequest getMappingsRequest = new GetFieldMappingsRequest();
getMappingsRequest.indices(indices).types(types).local(local).fields(fields).includeDefaults(request.paramAsBoolean("include_defaults", false)); getMappingsRequest.indices(indices).types(types).local(local).fields(fields).includeDefaults(request.paramAsBoolean("include_defaults", false));
getMappingsRequest.indicesOptions(IndicesOptions.fromRequest(request, getMappingsRequest.indicesOptions())); getMappingsRequest.indicesOptions(IndicesOptions.fromRequest(request, getMappingsRequest.indicesOptions()));