Filter empty fields in SearchHit#toXContent (#58418)

This commit restores the filtering of empty fields during the
xcontent serialization of SearchHit. The filtering was removed
unintentionally in #41656.
This commit is contained in:
Jim Ferenczi 2020-06-25 15:06:50 +02:00 committed by jimczi
parent 03e6d1b535
commit 6451187e84
2 changed files with 69 additions and 2 deletions

View File

@ -647,7 +647,12 @@ public final class SearchHit implements Writeable, ToXContentObject, Iterable<Do
} else {
builder.field(Fields._SCORE, score);
}
for (DocumentField field : metaFields.values()) {
// ignore empty metadata fields
if (field.getValues().size() == 0) {
continue;
}
// _ignored is the only multi-valued meta field
// TODO: can we avoid having an exception here?
if (field.getName().equals(IgnoredFieldMapper.NAME)) {
@ -659,10 +664,15 @@ public final class SearchHit implements Writeable, ToXContentObject, Iterable<Do
if (source != null) {
XContentHelper.writeRawField(SourceFieldMapper.NAME, source, builder, params);
}
if (!documentFields.isEmpty()) {
if (documentFields.isEmpty() == false &&
// ignore fields all together if they are all empty
documentFields.values().stream()
.anyMatch(df -> df.getValues().size() > 0)) {
builder.startObject(Fields.FIELDS);
for (DocumentField field : documentFields.values()) {
field.toXContent(builder, params);
if (field.getValues().size() > 0) {
field.toXContent(builder, params);
}
}
builder.endObject();
}

View File

@ -55,8 +55,10 @@ import java.util.function.Predicate;
import static org.elasticsearch.common.xcontent.XContentHelper.toXContent;
import static org.elasticsearch.test.XContentTestUtils.insertRandomFields;
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertToXContentEquivalent;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.instanceOf;
import static org.hamcrest.Matchers.not;
import static org.hamcrest.Matchers.notNullValue;
import static org.hamcrest.Matchers.nullValue;
@ -359,6 +361,61 @@ public class SearchHitTests extends AbstractWireSerializingTestCase<SearchHit> {
}
}
public void testToXContentEmptyFields() throws IOException {
Map<String, DocumentField> fields = new HashMap<>();
fields.put("foo", new DocumentField("foo", Collections.emptyList()));
fields.put("bar", new DocumentField("bar", Collections.emptyList()));
SearchHit hit = new SearchHit(0, "_id", null, fields, Collections.emptyMap());
{
BytesReference originalBytes = toShuffledXContent(hit, XContentType.JSON, ToXContent.EMPTY_PARAMS, randomBoolean());
// checks that the fields section is completely omitted in the rendering.
assertThat(originalBytes.utf8ToString(), not(containsString("fields")));
final SearchHit parsed;
try (XContentParser parser = createParser(XContentType.JSON.xContent(), originalBytes)) {
parser.nextToken(); // jump to first START_OBJECT
parsed = SearchHit.fromXContent(parser);
assertEquals(XContentParser.Token.END_OBJECT, parser.currentToken());
assertNull(parser.nextToken());
}
assertThat(parsed.getFields().size(), equalTo(0));
}
fields = new HashMap<>();
fields.put("foo", new DocumentField("foo", Collections.emptyList()));
fields.put("bar", new DocumentField("bar", Collections.singletonList("value")));
hit = new SearchHit(0, "_id", null, fields, Collections.emptyMap());
{
BytesReference originalBytes = toShuffledXContent(hit, XContentType.JSON, ToXContent.EMPTY_PARAMS, randomBoolean());
final SearchHit parsed;
try (XContentParser parser = createParser(XContentType.JSON.xContent(), originalBytes)) {
parser.nextToken(); // jump to first START_OBJECT
parsed = SearchHit.fromXContent(parser);
assertEquals(XContentParser.Token.END_OBJECT, parser.currentToken());
assertNull(parser.nextToken());
}
assertThat(parsed.getFields().size(), equalTo(1));
assertThat(parsed.getFields().get("bar").getValues(), equalTo( Collections.singletonList("value")));
}
Map<String, DocumentField> metadata = new HashMap<>();
metadata.put("_routing", new DocumentField("_routing", Collections.emptyList()));
hit = new SearchHit(0, "_id", null, fields, Collections.emptyMap());
{
BytesReference originalBytes = toShuffledXContent(hit, XContentType.JSON, ToXContent.EMPTY_PARAMS, randomBoolean());
final SearchHit parsed;
try (XContentParser parser = createParser(XContentType.JSON.xContent(), originalBytes)) {
parser.nextToken(); // jump to first START_OBJECT
parsed = SearchHit.fromXContent(parser);
assertEquals(XContentParser.Token.END_OBJECT, parser.currentToken());
assertNull(parser.nextToken());
}
assertThat(parsed.getFields().size(), equalTo(1));
assertThat(parsed.getFields().get("bar").getValues(), equalTo( Collections.singletonList("value")));
assertNull(parsed.getFields().get("_routing"));
}
}
static Explanation createExplanation(int depth) {
String description = randomAlphaOfLengthBetween(5, 20);
float value = randomFloat();