private void buildExplanation(XContentBuilder builder, Explanation explanation) throws IOException { builder.startObject(); builder.field(Fields.VALUE, explanation.getValue()); builder.field(Fields.DESCRIPTION, explanation.getDescription()); Explanation[] innerExps = explanation.getDetails(); if (innerExps != null) { builder.startArray(Fields.DETAILS); for (Explanation exp : innerExps) { buildExplanation(builder, exp); } builder.endArray(); } builder.endObject(); }
@Override public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { List<SearchHitField> metaFields = Lists.newArrayList(); List<SearchHitField> otherFields = Lists.newArrayList(); if (fields != null && !fields.isEmpty()) { for (SearchHitField field : fields.values()) { if (field.values().isEmpty()) { continue; } if (field.isMetadataField()) { metaFields.add(field); } else { otherFields.add(field); } } } builder.startObject(); // For inner_hit hits shard is null and that is ok, because the parent search hit has all this // information. // Even if this was included in the inner_hit hits this would be the same, so better leave it // out. if (explanation() != null && shard != null) { builder.field("_shard", shard.shardId()); builder.field("_node", shard.nodeIdText()); } if (shard != null) { builder.field(Fields._INDEX, shard.indexText()); } builder.field(Fields._TYPE, type); builder.field(Fields._ID, id); if (nestedIdentity != null) { nestedIdentity.toXContent(builder, params); } if (version != -1) { builder.field(Fields._VERSION, version); } if (Float.isNaN(score)) { builder.nullField(Fields._SCORE); } else { builder.field(Fields._SCORE, score); } for (SearchHitField field : metaFields) { builder.field(field.name(), field.value()); } if (source != null) { XContentHelper.writeRawField("_source", source, builder, params); } if (!otherFields.isEmpty()) { builder.startObject(Fields.FIELDS); for (SearchHitField field : otherFields) { builder.startArray(field.name()); for (Object value : field.getValues()) { builder.value(value); } builder.endArray(); } builder.endObject(); } if (highlightFields != null && !highlightFields.isEmpty()) { builder.startObject(Fields.HIGHLIGHT); for (HighlightField field : highlightFields.values()) { builder.field(field.name()); if (field.fragments() == null) { builder.nullValue(); } else { builder.startArray(); for (Text fragment : field.fragments()) { builder.value(fragment); } builder.endArray(); } } builder.endObject(); } if (sortValues != null && sortValues.length > 0) { builder.startArray(Fields.SORT); for (Object sortValue : sortValues) { if (sortValue != null && sortValue.equals(MAX_TERM_AS_TEXT)) { // We don't display MAX_TERM in JSON responses in case some clients have UTF-8 parsers // that wouldn't accept a // non-character in the response, even though this is valid UTF-8 builder.nullValue(); } else { builder.value(sortValue); } } builder.endArray(); } if (matchedQueries.length > 0) { builder.startArray(Fields.MATCHED_QUERIES); for (String matchedFilter : matchedQueries) { builder.value(matchedFilter); } builder.endArray(); } if (explanation() != null) { builder.field(Fields._EXPLANATION); buildExplanation(builder, explanation()); } if (innerHits != null) { builder.startObject(Fields.INNER_HITS); for (Map.Entry<String, InternalSearchHits> entry : innerHits.entrySet()) { builder.startObject(entry.getKey()); entry.getValue().toXContent(builder, params); builder.endObject(); } builder.endObject(); } builder.endObject(); return builder; }