package org.molgenis.data.elasticsearch.response; import org.elasticsearch.action.search.SearchResponse; import org.elasticsearch.action.search.ShardSearchFailure; import org.elasticsearch.common.base.Joiner; import org.elasticsearch.search.SearchHit; import org.elasticsearch.search.SearchHitField; import org.elasticsearch.search.aggregations.Aggregations; import org.elasticsearch.search.suggest.term.TermSuggestion.Score; import org.molgenis.data.DataService; import org.molgenis.data.aggregation.AggregateResult; import org.molgenis.data.elasticsearch.util.Hit; import org.molgenis.data.elasticsearch.util.SearchRequest; import org.molgenis.data.elasticsearch.util.SearchResult; import org.molgenis.data.meta.model.Attribute; import org.molgenis.data.meta.model.EntityType; import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import static org.molgenis.data.meta.AttributeType.MREF; /** * Generates a SearchResult from the ElasticSearch SearchResponse object * * @author erwin */ public class ResponseParser { private final AggregateResponseParser aggregateResponseParser; public ResponseParser() { this.aggregateResponseParser = new AggregateResponseParser(); } public SearchResult parseSearchResponse(SearchRequest request, SearchResponse response, EntityType entityType, DataService dataService) { ShardSearchFailure[] failures = response.getShardFailures(); if ((failures != null) && (failures.length > 0)) { StringBuilder sb = new StringBuilder("Exception while searching:\n"); for (ShardSearchFailure failure : failures) { sb.append(failure.shard()).append(":").append(failure.reason()); } return new SearchResult(sb.toString()); } List<Hit> searchHits = new ArrayList<Hit>(); long totalCount = response.getHits().totalHits(); for (SearchHit hit : response.getHits().hits()) { Map<String, Object> columnValueMap = new LinkedHashMap<String, Object>(); // If fieldsToReturn is used the "fields" field of the SearchHit is // filled if not the "source" field is filled if ((hit.fields() != null) && !hit.fields().isEmpty()) { for (SearchHitField searchHitField : hit.fields().values()) { columnValueMap.put(searchHitField.name(), searchHitField.value()); } } if ((hit.sourceAsMap() != null) && !hit.sourceAsMap().isEmpty()) { for (Map.Entry<String, Object> entry : hit.sourceAsMap().entrySet()) { // Check if the field is MREF, if so, only extract the // information for labelAttribute from refeEntity and put it // in the Hit result map String fieldName = entry.getKey(); if (entityType == null || entityType.getAttribute(fieldName) == null || entityType.getAttribute(fieldName).getDataType() != MREF) { columnValueMap.put(entry.getKey(), entry.getValue()); } else { Attribute attribute = entityType.getAttribute(fieldName).getRefEntity().getLabelAttribute(); List<Object> values = new ArrayList<Object>(); if (entry.getValue() instanceof List<?>) { for (Object eachElement : (List<?>) entry.getValue()) { if (eachElement instanceof Map<?, ?>) { for (Map.Entry<?, ?> entrySet : ((Map<?, ?>) eachElement).entrySet()) { if (entrySet.getKey().toString().equalsIgnoreCase(attribute.getName())) { Object value = entrySet.getValue(); if (value != null) { if (value instanceof List<?>) { values.addAll((List<?>) value); } else { values.add(value); } break; } } } } } } columnValueMap.put(entry.getKey(), Joiner.on(',').join(values)); } } columnValueMap.put(Score.class.getSimpleName().toLowerCase(), String.valueOf(hit.getScore()).equals("NaN") ? 0 : hit.getScore()); } searchHits.add(new Hit(hit.id(), hit.type(), columnValueMap)); } AggregateResult aggregate = null; Aggregations aggregations = response.getAggregations(); if (aggregations != null) { aggregate = aggregateResponseParser .parseAggregateResponse(request.getAggregateField1(), request.getAggregateField2(), request.getAggregateFieldDistinct(), aggregations, dataService); } return new SearchResult(totalCount, searchHits, aggregate); } }