Skip to content

Commit b4b548f

Browse files
committed
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 elastic#4738
1 parent dae47fc commit b4b548f

File tree

4 files changed

+44
-8
lines changed

4 files changed

+44
-8
lines changed

rest-api-spec/test/indices.get_field_mapping/20_missing_field.yaml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
---
2-
"Raise 404 when field doesn't exist":
2+
"Return empty object if field doesn't exist, but type and index do":
33

44
- do:
55
indices.create:
@@ -13,9 +13,9 @@
1313
analyzer: whitespace
1414

1515
- do:
16-
catch: missing
1716
indices.get_field_mapping:
1817
index: test_index
1918
type: test_type
20-
field: not_text
19+
field: not_existent
2120

21+
- match: { '': {}}

src/main/java/org/elasticsearch/action/admin/indices/mapping/get/GetFieldMappingsResponse.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121

2222
import com.google.common.collect.ImmutableMap;
2323
import org.elasticsearch.action.ActionResponse;
24+
import org.elasticsearch.common.bytes.BytesArray;
2425
import org.elasticsearch.common.bytes.BytesReference;
2526
import org.elasticsearch.common.io.stream.StreamInput;
2627
import org.elasticsearch.common.io.stream.StreamOutput;
@@ -88,6 +89,8 @@ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws
8889
}
8990

9091
public static class FieldMappingMetaData implements ToXContent {
92+
public static final FieldMappingMetaData NULL = new FieldMappingMetaData("", BytesArray.EMPTY);
93+
9194
private String fullName;
9295
private BytesReference source;
9396

src/main/java/org/elasticsearch/action/admin/indices/mapping/get/TransportGetFieldMappingsAction.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ private ImmutableMap<String, ImmutableMap<String, ImmutableMap<String, FieldMapp
9292
return ImmutableMap.of();
9393
}
9494

95+
boolean isProbablySingleFieldRequest = concreteIndices.length == 1 && types.length == 1 && fields.length == 1;
9596
ImmutableMap.Builder<String, ImmutableMap<String, ImmutableMap<String, FieldMappingMetaData>>> indexMapBuilder = ImmutableMap.builder();
9697
Sets.SetView<String> intersection = Sets.intersection(Sets.newHashSet(concreteIndices), indicesService.indices());
9798
for (String index : intersection) {
@@ -114,7 +115,7 @@ public boolean apply(String type) {
114115
MapBuilder<String, ImmutableMap<String, FieldMappingMetaData>> typeMappings = new MapBuilder<String, ImmutableMap<String, FieldMappingMetaData>>();
115116
for (String type : typeIntersection) {
116117
DocumentMapper documentMapper = indexService.mapperService().documentMapper(type);
117-
ImmutableMap<String, FieldMappingMetaData> fieldMapping = findFieldMappingsByType(documentMapper, fields, includeDefaults);
118+
ImmutableMap<String, FieldMappingMetaData> fieldMapping = findFieldMappingsByType(documentMapper, fields, includeDefaults, isProbablySingleFieldRequest);
118119
if (!fieldMapping.isEmpty()) {
119120
typeMappings.put(type, fieldMapping);
120121
}
@@ -170,7 +171,7 @@ public Boolean paramAsBooleanOptional(String key, Boolean defaultValue) {
170171
};
171172

172173
private ImmutableMap<String, FieldMappingMetaData> findFieldMappingsByType(DocumentMapper documentMapper, String[] fields,
173-
boolean includeDefaults) throws ElasticsearchException {
174+
boolean includeDefaults, boolean isProbablySingleFieldRequest) throws ElasticsearchException {
174175
MapBuilder<String, FieldMappingMetaData> fieldMappings = new MapBuilder<String, FieldMappingMetaData>();
175176
ImmutableList<FieldMapper> allFieldMappers = documentMapper.mappers().mappers();
176177
for (String field : fields) {
@@ -215,6 +216,8 @@ private ImmutableMap<String, FieldMappingMetaData> findFieldMappingsByType(Docum
215216
FieldMapper fieldMapper = documentMapper.mappers().smartNameFieldMapper(field);
216217
if (fieldMapper != null) {
217218
addFieldMapper(field, fieldMapper, fieldMappings, includeDefaults);
219+
} else if (isProbablySingleFieldRequest) {
220+
fieldMappings.put(field, FieldMappingMetaData.NULL);
218221
}
219222
}
220223
}

src/main/java/org/elasticsearch/rest/action/admin/indices/mapping/get/RestGetFieldMappingAction.java

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,10 +35,12 @@
3535
import org.elasticsearch.rest.action.support.RestXContentBuilder;
3636

3737
import java.io.IOException;
38+
import java.util.Map;
3839

3940
import static org.elasticsearch.rest.RestRequest.Method.GET;
4041
import static org.elasticsearch.rest.RestStatus.NOT_FOUND;
4142
import static org.elasticsearch.rest.RestStatus.OK;
43+
import static org.elasticsearch.rest.action.support.RestXContentBuilder.emptyBuilder;
4244

4345
/**
4446
*
@@ -70,14 +72,21 @@ public void handleRequest(final RestRequest request, final RestChannel channel)
7072
@Override
7173
public void onResponse(GetFieldMappingsResponse response) {
7274
try {
73-
XContentBuilder builder = RestXContentBuilder.restContentBuilder(request);
74-
builder.startObject();
75-
7675
ImmutableMap<String, ImmutableMap<String, ImmutableMap<String, FieldMappingMetaData>>> mappingsByIndex = response.mappings();
76+
77+
boolean isPossibleSingleFieldRequest = indices.length == 1 && types.length == 1 && fields.length == 1;
78+
if (isPossibleSingleFieldRequest && isFieldMappingMissingField(mappingsByIndex)) {
79+
channel.sendResponse(new XContentRestResponse(request, OK, emptyBuilder(request)));
80+
return;
81+
}
82+
7783
RestStatus status = OK;
7884
if (mappingsByIndex.isEmpty() && fields.length > 0) {
7985
status = NOT_FOUND;
8086
}
87+
88+
XContentBuilder builder = RestXContentBuilder.restContentBuilder(request);
89+
builder.startObject();
8190
response.toXContent(builder, ToXContent.EMPTY_PARAMS);
8291
builder.endObject();
8392
channel.sendResponse(new XContentRestResponse(request, status, builder));
@@ -97,4 +106,25 @@ public void onFailure(Throwable e) {
97106
});
98107
}
99108

109+
/**
110+
*
111+
* Helper method to find out if the only included fieldmapping metadata is typed NULL, which means
112+
* that type and index exist, but the field did not
113+
*/
114+
private boolean isFieldMappingMissingField(ImmutableMap<String, ImmutableMap<String, ImmutableMap<String, FieldMappingMetaData>>> mappingsByIndex) throws IOException {
115+
if (mappingsByIndex.size() != 1) {
116+
return false;
117+
}
118+
119+
for (ImmutableMap<String, ImmutableMap<String, FieldMappingMetaData>> value : mappingsByIndex.values()) {
120+
for (ImmutableMap<String, FieldMappingMetaData> fieldValue : value.values()) {
121+
for (Map.Entry<String, FieldMappingMetaData> fieldMappingMetaDataEntry : fieldValue.entrySet()) {
122+
if (fieldMappingMetaDataEntry.getValue() == FieldMappingMetaData.NULL) {
123+
return true;
124+
}
125+
}
126+
}
127+
}
128+
return false;
129+
}
100130
}

0 commit comments

Comments
 (0)