Commit 30491396 authored by Gradl, Tobias's avatar Gradl, Tobias
Browse files

437: Show result highlight in item view (OPENED)

Task-Url: #437
parent 20c1baf8
package eu.dariah.de.search.controller.search;
import java.io.IOException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import eu.dariah.de.search.exceptions.QueryExecutionException;
import eu.dariah.de.search.query.ExtendedQueryImpl;
import eu.dariah.de.search.query.Query;
import eu.dariah.de.search.query.SimpleQueryImpl;
import eu.dariah.de.search.query.execution.QueryExecutionServiceImpl;
import eu.dariah.de.search.query.meta.SruQueryExecutionServiceImpl;
public abstract class BaseQueryExecutionController {
protected final Logger logger = LoggerFactory.getLogger(this.getClass());
@Autowired protected ObjectMapper objMapper;
@Autowired protected SruQueryExecutionServiceImpl sruQueryExecutionService;
protected Query deserializeQuery(String jsonQuery) throws QueryExecutionException {
Query query = null;
try {
JsonNode node = objMapper.readValue(jsonQuery, JsonNode.class);
// For wrapped queries
if (node.has("query")) {
node = node.get("query");
}
if (node.has("queryString")) {
query = objMapper.treeToValue(node, SimpleQueryImpl.class);
} else {
query = objMapper.treeToValue(node, ExtendedQueryImpl.class);
}
return query;
} catch (IOException e) {
throw new QueryExecutionException("Failed to deserialize provided query", e);
}
}
@Autowired protected QueryExecutionServiceImpl queryExecutionService;
}
......@@ -5,6 +5,7 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.stream.Collectors;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
......@@ -15,6 +16,9 @@ import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestAttribute;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
......@@ -34,9 +38,14 @@ import de.unibamberg.minf.processing.output.xml.XmlOutputService;
import eu.dariah.de.search.Constants.ResultElementRelationTypes;
import eu.dariah.de.search.Constants.RootElementKeys;
import eu.dariah.de.search.controller.BaseController;
import eu.dariah.de.search.exceptions.QueryExecutionException;
import eu.dariah.de.search.model.Collection;
import eu.dariah.de.search.model.ExtendedDatamodelContainer;
import eu.dariah.de.search.query.Query;
import eu.dariah.de.search.query.execution.ItemService;
import eu.dariah.de.search.query.execution.QueryExecutionServiceImpl;
import eu.dariah.de.search.query.results.FieldHighlight;
import eu.dariah.de.search.query.results.QueryResult;
import eu.dariah.de.search.query.results.ResultElement;
import eu.dariah.de.search.service.CollectionService;
import eu.dariah.de.search.service.DatamodelService;
......@@ -49,6 +58,7 @@ public class ItemController extends BaseController {
@Autowired private CollectionService collectionService;
@Autowired private DatamodelService datamodelService;
@Autowired private ItemService itemService;
@Autowired protected QueryExecutionServiceImpl queryExecutionService;
@Value("${datamodels.integration}")
protected String integrationModelEntityId;
......@@ -62,6 +72,11 @@ public class ItemController extends BaseController {
@GetMapping(value = "/")
public String getItem(@PathVariable String type, @PathVariable String itemId, Model model, Locale locale, HttpServletResponse response) throws IOException {
return this.postItem(type, itemId, null, model, locale, response);
}
@PostMapping(value = "/")
public String postItem(@PathVariable String type, @PathVariable String itemId, @RequestParam(required= false, name="query") String jsonQuery, Model model, Locale locale, HttpServletResponse response) throws IOException {
model.addAttribute("itemId", itemId);
if (itemId==null || type==null) {
return ITEM_404_VIEW;
......@@ -71,11 +86,30 @@ public class ItemController extends BaseController {
return ITEM_404_VIEW;
}
JsonNode itemSource = itemService.getItem(datamodel.getIndexName(), itemId, locale, false, false);
Query query = null;
if (jsonQuery!=null && !jsonQuery.isBlank()) {
try {
query = queryExecutionService.deserializeQuery(jsonQuery);
} catch (QueryExecutionException e) {
logger.error("Failed to deserialize query", e);
}
}
JsonNode itemSource = null;
ResultElement item = null;
if (itemSource!=null) {
if (query!=null) {
query.setItemId(itemId);
QueryResult qr = queryExecutionService.executeQuery(query, locale);
item = qr.getResultElements().get(0);
itemSource = item.getSource();
}
if (item==null) {
itemSource = itemService.getItem(datamodel.getIndexName(), itemId, locale, false, false);
item = itemService.renderResultElement(itemSource, datamodel.getIndexName(), itemId, locale);
}
}
if (item==null) {
return ITEM_404_VIEW;
}
......@@ -114,6 +148,14 @@ public class ItemController extends BaseController {
model.addAttribute("endpointId", item.getEndpointId());
model.addAttribute("datamodel", datamodel);
model.addAttribute("item", item);
if (item.getFieldHighlights()!=null) {
model.addAttribute("highlights", item.getFieldHighlights().stream()
.flatMap(f -> f.getHighlightTexts().stream())
.distinct()
.collect(Collectors.toList()));
}
return "item/view";
}
......@@ -129,7 +171,7 @@ public class ItemController extends BaseController {
@GetMapping(value = "/data")
public @ResponseBody String getItem(@PathVariable String type, @PathVariable String itemId, @RequestParam(name="type") String dataType, Model model, Locale locale, HttpServletResponse response) throws IOException {
public @ResponseBody String getData(@PathVariable String type, @PathVariable String itemId, @RequestParam(name="type") String dataType, Model model, Locale locale, HttpServletResponse response) throws IOException {
ExtendedDatamodelContainer datamodel = datamodelService.findById(type);
JsonNode itemSource = itemService.getItem(datamodel.getIndexName(), itemId, locale, dataType.equals(RootElementKeys.INTEGRATIONS.toString()), dataType.equals(RootElementKeys.CONTENT.toString()));
ResultElement item = itemService.renderResultElement(itemSource, datamodel.getIndexName(), itemId, locale);
......
......@@ -36,7 +36,7 @@ public class MetaqueryExecutionController extends BaseQueryExecutionController {
@PostMapping
public @ResponseBody List<QueryResult> queryAsPost(@RequestBody String q, HttpServletResponse response, Locale locale) throws QueryExecutionException {
Query query = this.deserializeQuery(q);
Query query = queryExecutionService.deserializeQuery(q);
List<QueryResult> results = new ArrayList<>();
//results.addAll(sruQueryExecutionService.executeQuery(query, locale));
......
......@@ -16,6 +16,7 @@ import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
......@@ -32,13 +33,11 @@ import eu.dariah.de.search.service.DatamodelService;
@Controller
@RequestMapping("/query")
public class QueryExecutionController extends BaseQueryExecutionController {
@Autowired private QueryExecutionServiceImpl queryExecutionService;
public class QueryExecutionController extends BaseQueryExecutionController {
@Autowired private AggregationService aggregationService;
@Autowired private CustomSearchService customSearchService;
@Autowired protected DatamodelService datamodelService;
@Autowired protected ObjectMapper objMapper;
@GetMapping
public @ResponseBody List<QueryResult> queryAsGet(@RequestParam String q, HttpServletResponse response, Locale locale) {
......@@ -56,7 +55,7 @@ public class QueryExecutionController extends BaseQueryExecutionController {
@PostMapping
public @ResponseBody List<QueryResult> queryAsPost(@RequestBody String q, HttpServletResponse response, Locale locale) throws QueryExecutionException {
Query query = this.deserializeQuery(q);
Query query = queryExecutionService.deserializeQuery(q);
List<QueryResult> results = new ArrayList<>();
if ((query.getSourceIds()==null || query.getSourceIds().isEmpty()) && query.getCustomSearch()!=null && !query.getCustomSearch().isEmpty()) {
List<CustomSearch> cs = customSearchService.findByPrefix(query.getCustomSearch());
......@@ -80,7 +79,7 @@ public class QueryExecutionController extends BaseQueryExecutionController {
@PostMapping(value="/tags/")
public @ResponseBody JsonNode getTags(@RequestBody String q, HttpServletResponse response) throws QueryExecutionException {
Query query = this.deserializeQuery(q);
Query query = queryExecutionService.deserializeQuery(q);
ObjectNode result = objMapper.createObjectNode();
ArrayNode sourceIds = objMapper.createArrayNode();
for (String sourceId : query.getSourceIds()) {
......
......@@ -21,6 +21,7 @@ public abstract class BaseQuery implements Query {
private List<String> tagAggregators;
private List<Filter> filters;
private List<SearchTypes> resultTypes;
private String itemId;
@JsonDeserialize(contentUsing=ResourceDeserializer.class)
private List<SerializableResource> entities;
......@@ -58,4 +59,7 @@ public abstract class BaseQuery implements Query {
public List<SearchTypes> getResultTypes() { return resultTypes; }
public void setResultTypes(List<SearchTypes> resultTypes) { this.resultTypes = resultTypes; }
public String getItemId() { return itemId; }
public void setItemId(String itemId) { this.itemId = itemId; }
}
......@@ -42,4 +42,7 @@ public interface Query {
public List<SearchTypes> getResultTypes();
public void setResultTypes(List<SearchTypes> resultTypes);
public String getItemId();
public void setItemId(String itemId);
}
package eu.dariah.de.search.query.execution;
import java.util.List;
import java.util.Locale;
import eu.dariah.de.search.pojo.TagPojo;
import eu.dariah.de.search.exceptions.QueryExecutionException;
import eu.dariah.de.search.query.Query;
import eu.dariah.de.search.query.results.QueryResult;
public interface QueryExecutionService {
public QueryResult executeQuery(Query q, Locale locale);
//public List<TagPojo> getTags(Query query, String datasourceId);
public Query deserializeQuery(String jsonQuery) throws QueryExecutionException;
}
package eu.dariah.de.search.query.execution;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
......@@ -20,6 +21,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import de.unibamberg.minf.core.util.json.JsonNodeHelper;
import de.unibamberg.minf.dme.model.base.Element;
......@@ -27,11 +29,14 @@ import de.unibamberg.minf.processing.model.base.Resource;
import eu.dariah.de.search.Constants;
import eu.dariah.de.search.es.service.params.FetchParams;
import eu.dariah.de.search.es.service.params.SearchParams;
import eu.dariah.de.search.exceptions.QueryExecutionException;
import eu.dariah.de.search.model.Collection;
import eu.dariah.de.search.model.ExtendedDatamodelContainer;
import eu.dariah.de.search.model.Filter;
import eu.dariah.de.search.pojo.conversion.FilterConverter;
import eu.dariah.de.search.query.ExtendedQueryImpl;
import eu.dariah.de.search.query.Query;
import eu.dariah.de.search.query.SimpleQueryImpl;
import eu.dariah.de.search.query.execution.base.BaseQueryService;
import eu.dariah.de.search.query.results.QueryResult;
import eu.dariah.de.search.query.results.QueryResultDatasource;
......@@ -47,6 +52,7 @@ public class QueryExecutionServiceImpl extends BaseQueryService implements Query
@Autowired private JsonNodeHelper jsonNodeHelper;
@Autowired private FilterConverter filterConverter;
@Autowired protected ObjectMapper objMapper;
@Value("${querying.min_score:0.02F}")
private float minScoreThreshold;
......@@ -63,7 +69,25 @@ public class QueryExecutionServiceImpl extends BaseQueryService implements Query
return qr;
}
@Override
public Query deserializeQuery(String jsonQuery) throws QueryExecutionException {
Query query = null;
try {
JsonNode node = objMapper.readValue(jsonQuery, JsonNode.class);
// For wrapped queries
if (node.has("query")) {
node = node.get("query");
}
if (node.has("queryString")) {
query = objMapper.treeToValue(node, SimpleQueryImpl.class);
} else {
query = objMapper.treeToValue(node, ExtendedQueryImpl.class);
}
return query;
} catch (IOException e) {
throw new QueryExecutionException("Failed to deserialize provided query", e);
}
}
public List<SearchResponse> executeQueries(Map<QueryBuilder, String[]> queryIndicesMap, Query q, String[] aggregationKeys) {
List<SearchResponse> responses = new ArrayList<>();
......
......@@ -213,14 +213,21 @@ public abstract class BaseQueryService extends BaseResultService {
/** Filtered query requires bool.must
* -> wrap original query within bool.must component
*/
if (q.getSourceIds()!=null && q.getSourceIds().size()>0) {
if ((q.getSourceIds()!=null && !q.getSourceIds().isEmpty()) || (q.getItemId()!=null && !q.getItemId().isBlank())) {
if (boolQb==null) {
boolQb = QueryBuilders.boolQuery();
if (bldr!=null) {
boolQb.must(bldr);
}
}
boolQb.filter(QueryBuilders.termsQuery(Constants.ELEMENT_KEY_COLLECTION_ID, q.getSourceIds()));
if (q.getItemId()!=null && !q.getItemId().isBlank()) {
boolQb.filter(QueryBuilders.termsQuery(Constants.ELEMENT_KEY_META_ID, q.getItemId()));
}
if (q.getSourceIds()!=null && !q.getSourceIds().isEmpty()) {
boolQb.filter(QueryBuilders.termsQuery(Constants.ELEMENT_KEY_COLLECTION_ID, q.getSourceIds()));
}
}
if (q.getFilters()!=null && !q.getFilters().isEmpty()) {
......
package eu.dariah.de.search.query.execution.base;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
......@@ -83,7 +84,7 @@ public abstract class BaseResultService implements InitializingBean {
String modelId = index.substring(config.getIndexing().getIndexNamePrefix().length());
boolean messageCodes = this.isResolveMessageCodes(modelId);
ResultElement qre = new ResultElement();
ResultElement qre = new ResultElement(source);
/* Basic metadata */
qre.setId(id);
......@@ -163,12 +164,10 @@ public abstract class BaseResultService implements InitializingBean {
log.warn("Failed to read error node: {}", e.getMessage());
}
if (fieldHighlights!=null) {
qre.setFieldHighlights(new ArrayList<FieldHighlight>());
qre.setFieldHighlights(new ArrayList<>());
for (String field : fieldHighlights.keySet()) {
qre.getFieldHighlights().add(new FieldHighlight(field, null, fieldHighlights.get(field)));
qre.getFieldHighlights().add(new FieldHighlight(field, null, Arrays.asList(fieldHighlights.get(field))));
}
}
......
package eu.dariah.de.search.query.results;
import java.util.List;
public class FieldHighlight {
private String field;
private String fieldLabel;
private String[] highlightTexts;
private List<String> highlightTexts;
public String getField() { return field; }
public void setField(String field) { this.field = field; }
......@@ -11,12 +13,12 @@ public class FieldHighlight {
public String getFieldLabel() { return fieldLabel; }
public void setFieldLabel(String fieldLabel) { this.fieldLabel = fieldLabel; }
public String[] getHighlightTexts() { return highlightTexts; }
public void setHighlightTexts(String[] highlightTexts) { this.highlightTexts = highlightTexts; }
public List<String> getHighlightTexts() { return highlightTexts; }
public void setHighlightTexts(List<String> highlightTexts) { this.highlightTexts = highlightTexts; }
public FieldHighlight() {}
public FieldHighlight(String field, String fieldLabel, String[] highlightTexts) {
public FieldHighlight(String field, String fieldLabel, List<String> highlightTexts) {
this.field = field;
this.fieldLabel = fieldLabel;
this.highlightTexts = highlightTexts;
......
......@@ -7,7 +7,9 @@ import java.util.Map;
import org.apache.lucene.search.Explanation;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.MissingNode;
import eu.dariah.de.search.Constants.ResultElementRelationTypes;
......@@ -39,6 +41,16 @@ public class ResultElement implements Comparable<ResultElement> {
private List<String> errors;
@JsonIgnore
private final JsonNode source;
public ResultElement(JsonNode source) {
this.source = source;
}
public ResultElement() {
this.source = MissingNode.getInstance();
}
public String getId() { return id; }
public void setId(String id) { this.id = id; }
......@@ -100,7 +112,9 @@ public class ResultElement implements Comparable<ResultElement> {
public List<String> getErrors() { return errors; }
public void setErrors(List<String> errors) { this.errors = errors; }
public JsonNode getSource() { return source; }
@Override
public int compareTo(ResultElement arg0) {
if (arg0.getScore()==this.getScore()) {
......
Subproject commit 11e3a70be8ceffdcf95b0e6429f3cee814349daa
Subproject commit 255e23de4b3262402bd623ef7ca3a09f3016f03d
Subproject commit 4b14145e8fb1606bfaed7e3f13a62b8182f7c6c2
Subproject commit efab5dbc0833c446605b6befe494196f3747de88
Subproject commit 02681ec7b32cb0844a4f23b67302733699703945
Subproject commit be962398b220fc7fc2bfc7fd62c610ff33153391
Subproject commit f0020c03a8d959c71381c495340953ab29f36e47
Subproject commit 576d22130e5ec4612227d3fef2cc21794cd4bf5f
Subproject commit 26a1346f2f740e884decf4938f3408c61e6273c6
Subproject commit b0a4a681cbfab4cee147432ead86a9dd4c271076
Subproject commit df587fba963bd6004c8eec3afea93d41ff7d831e
Subproject commit 81e735c155cd5f5cb10a1197c8884439ee7b8baf
Subproject commit 6d04da1c6f4f898211d49b221ab33ba74a9f549c
Subproject commit 43b0b3e9e428a3a19ac50333e33cfd077389c27b
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment