diff --git a/rest-api-spec/test/indices.get_field_mapping/20_missing_field.yaml b/rest-api-spec/test/indices.get_field_mapping/20_missing_field.yaml index 0a3dd47c665..a9eddc9696e 100644 --- a/rest-api-spec/test/indices.get_field_mapping/20_missing_field.yaml +++ b/rest-api-spec/test/indices.get_field_mapping/20_missing_field.yaml @@ -1,5 +1,5 @@ --- -"Raise 404 when field doesn't exist": +"Return empty object if field doesn't exist, but type and index do": - do: indices.create: @@ -13,9 +13,9 @@ analyzer: whitespace - do: - catch: missing indices.get_field_mapping: index: test_index type: test_type - field: not_text + field: not_existent + - match: { '': {}} diff --git a/src/main/java/org/elasticsearch/action/admin/indices/mapping/get/GetFieldMappingsResponse.java b/src/main/java/org/elasticsearch/action/admin/indices/mapping/get/GetFieldMappingsResponse.java index a62ea0d353b..470ed6c4e24 100644 --- a/src/main/java/org/elasticsearch/action/admin/indices/mapping/get/GetFieldMappingsResponse.java +++ b/src/main/java/org/elasticsearch/action/admin/indices/mapping/get/GetFieldMappingsResponse.java @@ -21,6 +21,7 @@ package org.elasticsearch.action.admin.indices.mapping.get; import com.google.common.collect.ImmutableMap; import org.elasticsearch.action.ActionResponse; +import org.elasticsearch.common.bytes.BytesArray; import org.elasticsearch.common.bytes.BytesReference; import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamOutput; @@ -88,6 +89,8 @@ public class GetFieldMappingsResponse extends ActionResponse implements ToXConte } public static class FieldMappingMetaData implements ToXContent { + public static final FieldMappingMetaData NULL = new FieldMappingMetaData("", BytesArray.EMPTY); + private String fullName; private BytesReference source; diff --git a/src/main/java/org/elasticsearch/action/admin/indices/mapping/get/TransportGetFieldMappingsAction.java b/src/main/java/org/elasticsearch/action/admin/indices/mapping/get/TransportGetFieldMappingsAction.java index 3345f40b8e4..f52d5f50e9b 100644 --- a/src/main/java/org/elasticsearch/action/admin/indices/mapping/get/TransportGetFieldMappingsAction.java +++ b/src/main/java/org/elasticsearch/action/admin/indices/mapping/get/TransportGetFieldMappingsAction.java @@ -92,6 +92,7 @@ public class TransportGetFieldMappingsAction extends TransportClusterInfoAction< return ImmutableMap.of(); } + boolean isProbablySingleFieldRequest = concreteIndices.length == 1 && types.length == 1 && fields.length == 1; ImmutableMap.Builder>> indexMapBuilder = ImmutableMap.builder(); Sets.SetView intersection = Sets.intersection(Sets.newHashSet(concreteIndices), indicesService.indices()); for (String index : intersection) { @@ -114,7 +115,7 @@ public class TransportGetFieldMappingsAction extends TransportClusterInfoAction< MapBuilder> typeMappings = new MapBuilder>(); for (String type : typeIntersection) { DocumentMapper documentMapper = indexService.mapperService().documentMapper(type); - ImmutableMap fieldMapping = findFieldMappingsByType(documentMapper, fields, includeDefaults); + ImmutableMap fieldMapping = findFieldMappingsByType(documentMapper, fields, includeDefaults, isProbablySingleFieldRequest); if (!fieldMapping.isEmpty()) { typeMappings.put(type, fieldMapping); } @@ -170,7 +171,7 @@ public class TransportGetFieldMappingsAction extends TransportClusterInfoAction< }; private ImmutableMap findFieldMappingsByType(DocumentMapper documentMapper, String[] fields, - boolean includeDefaults) throws ElasticsearchException { + boolean includeDefaults, boolean isProbablySingleFieldRequest) throws ElasticsearchException { MapBuilder fieldMappings = new MapBuilder(); ImmutableList allFieldMappers = documentMapper.mappers().mappers(); for (String field : fields) { @@ -215,6 +216,8 @@ public class TransportGetFieldMappingsAction extends TransportClusterInfoAction< FieldMapper fieldMapper = documentMapper.mappers().smartNameFieldMapper(field); if (fieldMapper != null) { addFieldMapper(field, fieldMapper, fieldMappings, includeDefaults); + } else if (isProbablySingleFieldRequest) { + fieldMappings.put(field, FieldMappingMetaData.NULL); } } } diff --git a/src/main/java/org/elasticsearch/rest/action/admin/indices/mapping/get/RestGetFieldMappingAction.java b/src/main/java/org/elasticsearch/rest/action/admin/indices/mapping/get/RestGetFieldMappingAction.java index ee32475ee88..43969c690a8 100644 --- a/src/main/java/org/elasticsearch/rest/action/admin/indices/mapping/get/RestGetFieldMappingAction.java +++ b/src/main/java/org/elasticsearch/rest/action/admin/indices/mapping/get/RestGetFieldMappingAction.java @@ -35,10 +35,12 @@ import org.elasticsearch.rest.*; import org.elasticsearch.rest.action.support.RestXContentBuilder; import java.io.IOException; +import java.util.Map; import static org.elasticsearch.rest.RestRequest.Method.GET; import static org.elasticsearch.rest.RestStatus.NOT_FOUND; import static org.elasticsearch.rest.RestStatus.OK; +import static org.elasticsearch.rest.action.support.RestXContentBuilder.emptyBuilder; /** * @@ -70,14 +72,21 @@ public class RestGetFieldMappingAction extends BaseRestHandler { @Override public void onResponse(GetFieldMappingsResponse response) { try { - XContentBuilder builder = RestXContentBuilder.restContentBuilder(request); - builder.startObject(); - ImmutableMap>> mappingsByIndex = response.mappings(); + + boolean isPossibleSingleFieldRequest = indices.length == 1 && types.length == 1 && fields.length == 1; + if (isPossibleSingleFieldRequest && isFieldMappingMissingField(mappingsByIndex)) { + channel.sendResponse(new XContentRestResponse(request, OK, emptyBuilder(request))); + return; + } + RestStatus status = OK; if (mappingsByIndex.isEmpty() && fields.length > 0) { status = NOT_FOUND; } + + XContentBuilder builder = RestXContentBuilder.restContentBuilder(request); + builder.startObject(); response.toXContent(builder, ToXContent.EMPTY_PARAMS); builder.endObject(); channel.sendResponse(new XContentRestResponse(request, status, builder)); @@ -97,4 +106,25 @@ public class RestGetFieldMappingAction extends BaseRestHandler { }); } + /** + * + * Helper method to find out if the only included fieldmapping metadata is typed NULL, which means + * that type and index exist, but the field did not + */ + private boolean isFieldMappingMissingField(ImmutableMap>> mappingsByIndex) throws IOException { + if (mappingsByIndex.size() != 1) { + return false; + } + + for (ImmutableMap> value : mappingsByIndex.values()) { + for (ImmutableMap fieldValue : value.values()) { + for (Map.Entry fieldMappingMetaDataEntry : fieldValue.entrySet()) { + if (fieldMappingMetaDataEntry.getValue() == FieldMappingMetaData.NULL) { + return true; + } + } + } + } + return false; + } }