package com.github.obourgain.elasticsearch.http.response.entity; import static org.elasticsearch.common.xcontent.XContentParser.Token.END_ARRAY; import static org.elasticsearch.common.xcontent.XContentParser.Token.END_OBJECT; import static org.elasticsearch.common.xcontent.XContentParser.Token.FIELD_NAME; import static org.elasticsearch.common.xcontent.XContentParser.Token.START_ARRAY; import static org.elasticsearch.common.xcontent.XContentParser.Token.START_OBJECT; import static org.elasticsearch.common.xcontent.XContentParser.Token.VALUE_NULL; import java.io.IOException; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentFactory; import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.common.xcontent.XContentType; import com.google.common.collect.ImmutableMap; import lombok.Getter; @Getter public class Hit { private String index; private String type; private String id; private Float score; // may be null when sorting without setting track_scores to true private long version; private byte[] source; private List<String> sort = Collections.emptyList(); private Map<String, SearchHitField> fields = ImmutableMap.of(); private Map<String, Highlight> highlights = ImmutableMap.of(); private Explanation explanation; private List<String> matchedQueries = Collections.emptyList(); public Hit parse(XContentParser parser) throws IOException { assert parser.currentToken() == START_OBJECT : "expected a START_OBJECT token but was " + parser.currentToken(); XContentParser.Token token; String currentFieldName = null; while ((token = parser.nextToken()) != END_OBJECT) { if (token == FIELD_NAME) { currentFieldName = parser.currentName(); } else if (token.isValue()) { if ("_id".equals(currentFieldName)) { id = parser.text(); } else if ("_index".equals(currentFieldName)) { index = parser.text(); } else if ("_type".equals(currentFieldName)) { type = parser.text(); } else if ("_version".equals(currentFieldName)) { version = parser.intValue(); } else if ("_score".equals(currentFieldName)) { score = parser.floatValue(); } } else if (token == START_OBJECT && "_source".equals(currentFieldName)) { try (XContentBuilder docBuilder = XContentFactory.contentBuilder(XContentType.JSON)) { docBuilder.copyCurrentStructure(parser); source = docBuilder.bytes().toBytes(); } } else if (token == START_OBJECT && "fields".equals(currentFieldName)) { fields = parseSearchHitFields(parser); } else if (token == START_OBJECT && "highlight".equals(currentFieldName)) { highlights = Highlight.parseHighlights(parser); } else if (token == START_OBJECT && "_explanation".equals(currentFieldName)) { explanation = new Explanation().parse(parser); } else if (token == START_ARRAY && "sort".equals(currentFieldName)) { assert parser.currentToken() == START_ARRAY : "expected a START_ARRAY token but was " + parser.currentToken(); sort = parseSort(parser); } else if (token == START_ARRAY && "matched_queries".equals(currentFieldName)) { assert parser.currentToken() == START_ARRAY : "expected a START_ARRAY token but was " + parser.currentToken(); matchedQueries = parseMatchedQueries(parser); } else if (token == VALUE_NULL && "_score".equals(currentFieldName)) { score = null; } else { throw new IllegalStateException("unknown field " + currentFieldName); } } return this; } public static List<Hit> parseHitArray(XContentParser parser) { assert parser.currentToken() == START_ARRAY : "expected a START_ARRAY token but was " + parser.currentToken(); try { List<Hit> result = new ArrayList<>(); while (parser.nextToken() != END_ARRAY) { assert parser.currentToken() == START_OBJECT : "expected a START_OBJECT token but was " + parser.currentToken(); result.add(new Hit().parse(parser)); } return result; } catch (IOException e) { throw new RuntimeException(e); } } public static List<String> parseSort(XContentParser parser) { assert parser.currentToken() == START_ARRAY : "expected a START_ARRAY token but was " + parser.currentToken(); try { List<String> result = new ArrayList<>(); while (parser.nextToken() != END_ARRAY) { result.add(parser.text()); } return result; } catch (IOException e) { throw new RuntimeException(e); } } public static Map<String, SearchHitField> parseSearchHitFields(XContentParser parser) { assert parser.currentToken() == START_OBJECT : "expected a START_OBJECT token but was " + parser.currentToken(); try { Map<String, SearchHitField> result = new HashMap<>(); while (parser.nextToken() != XContentParser.Token.END_OBJECT) { SearchHitField field = new SearchHitField().parse(parser); result.put(field.getName(), field); } return result; } catch (IOException e) { throw new RuntimeException(e); } } private List<String> parseMatchedQueries(XContentParser parser) { try { assert parser.currentToken() == START_ARRAY : "expected a START_ARRAY token but was " + parser.currentToken(); List<String> result = new ArrayList<>(); while (parser.nextToken() != END_ARRAY) { result.add(parser.text()); } return result; } catch (IOException e) { throw new RuntimeException(e); } } }