REST API: Consistent get field mapping response

If a get field mapping request is issued, and all but the field can be
found, the response should return an empty JSON object instead of a 404.

Closes #4738
This commit is contained in:
Alexander Reelsen 2014-01-27 22:21:30 +01:00
parent d9699e02f4
commit 5e58f4066e
4 changed files with 44 additions and 8 deletions

View File

@ -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: { '': {}}

View File

@ -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;

View File

@ -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<String, ImmutableMap<String, ImmutableMap<String, FieldMappingMetaData>>> indexMapBuilder = ImmutableMap.builder();
Sets.SetView<String> intersection = Sets.intersection(Sets.newHashSet(concreteIndices), indicesService.indices());
for (String index : intersection) {
@ -114,7 +115,7 @@ public class TransportGetFieldMappingsAction extends TransportClusterInfoAction<
MapBuilder<String, ImmutableMap<String, FieldMappingMetaData>> typeMappings = new MapBuilder<String, ImmutableMap<String, FieldMappingMetaData>>();
for (String type : typeIntersection) {
DocumentMapper documentMapper = indexService.mapperService().documentMapper(type);
ImmutableMap<String, FieldMappingMetaData> fieldMapping = findFieldMappingsByType(documentMapper, fields, includeDefaults);
ImmutableMap<String, FieldMappingMetaData> fieldMapping = findFieldMappingsByType(documentMapper, fields, includeDefaults, isProbablySingleFieldRequest);
if (!fieldMapping.isEmpty()) {
typeMappings.put(type, fieldMapping);
}
@ -170,7 +171,7 @@ public class TransportGetFieldMappingsAction extends TransportClusterInfoAction<
};
private ImmutableMap<String, FieldMappingMetaData> findFieldMappingsByType(DocumentMapper documentMapper, String[] fields,
boolean includeDefaults) throws ElasticsearchException {
boolean includeDefaults, boolean isProbablySingleFieldRequest) throws ElasticsearchException {
MapBuilder<String, FieldMappingMetaData> fieldMappings = new MapBuilder<String, FieldMappingMetaData>();
ImmutableList<FieldMapper> 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);
}
}
}

View File

@ -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<String, ImmutableMap<String, ImmutableMap<String, FieldMappingMetaData>>> 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<String, ImmutableMap<String, ImmutableMap<String, FieldMappingMetaData>>> mappingsByIndex) throws IOException {
if (mappingsByIndex.size() != 1) {
return false;
}
for (ImmutableMap<String, ImmutableMap<String, FieldMappingMetaData>> value : mappingsByIndex.values()) {
for (ImmutableMap<String, FieldMappingMetaData> fieldValue : value.values()) {
for (Map.Entry<String, FieldMappingMetaData> fieldMappingMetaDataEntry : fieldValue.entrySet()) {
if (fieldMappingMetaDataEntry.getValue() == FieldMappingMetaData.NULL) {
return true;
}
}
}
}
return false;
}
}