Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

REST API: Consistent get field mapping response #4822

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
@@ -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:
Expand All @@ -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: { '': {}}
Expand Up @@ -21,6 +21,7 @@

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;
Expand Down Expand Up @@ -88,6 +89,8 @@ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws
}

public static class FieldMappingMetaData implements ToXContent {
public static final FieldMappingMetaData NULL = new FieldMappingMetaData("", BytesArray.EMPTY);

private String fullName;
private BytesReference source;

Expand Down
Expand Up @@ -92,6 +92,7 @@ private ImmutableMap<String, ImmutableMap<String, ImmutableMap<String, FieldMapp
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) {
Expand All @@ -114,7 +115,7 @@ public boolean apply(String type) {
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);
}
Expand Down Expand Up @@ -170,7 +171,7 @@ public Boolean paramAsBooleanOptional(String key, Boolean defaultValue) {
};

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) {
Expand Down Expand Up @@ -215,6 +216,8 @@ private ImmutableMap<String, FieldMappingMetaData> findFieldMappingsByType(Docum
FieldMapper fieldMapper = documentMapper.mappers().smartNameFieldMapper(field);
if (fieldMapper != null) {
addFieldMapper(field, fieldMapper, fieldMappings, includeDefaults);
} else if (isProbablySingleFieldRequest) {
fieldMappings.put(field, FieldMappingMetaData.NULL);
}
}
}
Expand Down
Expand Up @@ -35,10 +35,12 @@
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;

/**
*
Expand Down Expand Up @@ -70,14 +72,21 @@ public void handleRequest(final RestRequest request, final RestChannel channel)
@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));
Expand All @@ -97,4 +106,25 @@ public void onFailure(Throwable e) {
});
}

/**
*
* 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;
}
}