Commit 01578e24 authored by Jean-Baptiste Nizet's avatar Jean-Baptiste Nizet
Browse files

feat: implement highlighting of description on backend

parent 12482a00
......@@ -26,6 +26,7 @@ public interface GeneticResourceDaoCustom {
*/
AggregatedPage<GeneticResource> search(String query,
boolean aggregate,
boolean highlight,
SearchRefinements refinements,
Pageable page);
......
......@@ -22,11 +22,13 @@ import org.elasticsearch.index.query.MultiMatchQueryBuilder;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.suggest.SuggestBuilder;
import org.elasticsearch.search.suggest.SuggestBuilders;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.data.elasticsearch.core.EntityMapper;
import org.springframework.data.elasticsearch.core.aggregation.AggregatedPage;
import org.springframework.data.elasticsearch.core.query.FetchSourceFilterBuilder;
import org.springframework.data.elasticsearch.core.query.IndexQuery;
......@@ -76,14 +78,18 @@ public class GeneticResourceDaoImpl implements GeneticResourceDaoCustom {
private int MAX_RETURNED_SUGGESTION_COUNT = 10;
private final ElasticsearchTemplate elasticsearchTemplate;
private final GeneticResourceHighlightMapper geneticResourceHighlightMapper;
public GeneticResourceDaoImpl(ElasticsearchTemplate elasticsearchTemplate) {
public GeneticResourceDaoImpl(ElasticsearchTemplate elasticsearchTemplate,
EntityMapper entityMapper) {
this.elasticsearchTemplate = elasticsearchTemplate;
this.geneticResourceHighlightMapper = new GeneticResourceHighlightMapper(entityMapper);
}
@Override
public AggregatedPage<GeneticResource> search(String query,
boolean aggregate,
boolean highlight,
SearchRefinements refinements,
Pageable page) {
......@@ -115,7 +121,11 @@ public class GeneticResourceDaoImpl implements GeneticResourceDaoCustom {
.size(rareAggregation.getType().getMaxBuckets())));
}
return elasticsearchTemplate.queryForPage(builder.build(), GeneticResource.class);
if (highlight) {
builder.withHighlightFields(new HighlightBuilder.Field("description").numOfFragments(0));
}
return elasticsearchTemplate.queryForPage(builder.build(), GeneticResource.class, geneticResourceHighlightMapper);
}
@Override
......
package fr.inra.urgi.rare.dao;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import fr.inra.urgi.rare.domain.GeneticResource;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.springframework.data.domain.Pageable;
import org.springframework.data.elasticsearch.core.DefaultResultMapper;
import org.springframework.data.elasticsearch.core.EntityMapper;
import org.springframework.data.elasticsearch.core.SearchResultMapper;
import org.springframework.data.elasticsearch.core.aggregation.AggregatedPage;
import org.springframework.data.elasticsearch.core.aggregation.impl.AggregatedPageImpl;
/**
* A special {@link SearchResultMapper}, only usable for {@link GeneticResource}, which delegates to the
* default mapper, but then replaces the description in the mapped genetic resources by the highlighted description
* if it's found in the search response.
* @author JB Nizet
*/
public class GeneticResourceHighlightMapper implements SearchResultMapper {
private DefaultResultMapper defaultResultMapper;
public GeneticResourceHighlightMapper(EntityMapper entityMapper) {
this.defaultResultMapper = new DefaultResultMapper(entityMapper);
}
@SuppressWarnings("unchecked")
@Override
public <T> AggregatedPage<T> mapResults(SearchResponse response, Class<T> clazz, Pageable pageable) {
if (clazz != GeneticResource.class) {
throw new IllegalArgumentException("The only supported class is " + GeneticResource.class);
}
AggregatedPage<GeneticResource> page = defaultResultMapper.mapResults(response, GeneticResource.class, pageable);
List<GeneticResource> newContent = new ArrayList<>(page.getContent());
for (int i = 0; i < page.getContent().size(); i++) {
GeneticResource geneticResource = page.getContent().get(i);
SearchHit hit = response.getHits().getAt(i);
Map<String, HighlightField> highlightFields = hit.getHighlightFields();
String newDescription = geneticResource.getDescription();
boolean hightlightFound = false;
if (highlightFields != null) {
HighlightField descriptionHighlight = highlightFields.get("description");
if (descriptionHighlight != null && descriptionHighlight.getFragments().length == 1) {
newDescription = descriptionHighlight.getFragments()[0].string();
hightlightFound = true;
}
}
if (hightlightFound) {
GeneticResource newGeneticResource = GeneticResource.builder(geneticResource)
.withDescription(newDescription)
.build();
newContent.set(i, newGeneticResource);
}
}
return (AggregatedPage<T>) new AggregatedPageImpl<>(newContent,
page.getPageable(),
page.getTotalElements(),
page.getAggregations(),
page.getScrollId());
}
}
......@@ -53,6 +53,7 @@ public class SearchController {
@GetMapping
public AggregatedPageDTO<GeneticResource> search(@RequestParam("query") String query,
@RequestParam("agg") Optional<Boolean> agg,
@RequestParam("highlight") Optional<Boolean> highlight,
@RequestParam("page") Optional<Integer> page,
@RequestParam MultiValueMap<String, String> parameters) {
boolean aggregate = agg.orElse(false);
......@@ -60,6 +61,7 @@ public class SearchController {
validatePage(requestedPage);
return AggregatedPageDTO.fromPage(geneticResourceDao.search(query,
aggregate,
highlight.orElse(false),
createRefinementsFromParameters(parameters),
PageRequest.of(page.orElse(0), PAGE_SIZE)));
......
......@@ -49,7 +49,7 @@ class SearchControllerTest {
PageRequest pageRequest = PageRequest.of(0, SearchController.PAGE_SIZE);
String query = "pauca";
when(mockGeneticResourceDao.search(query, false, SearchRefinements.EMPTY, pageRequest))
when(mockGeneticResourceDao.search(query, false, false, SearchRefinements.EMPTY, pageRequest))
.thenReturn(new AggregatedPageImpl<>(Arrays.asList(resource), pageRequest, 1));
mockMvc.perform(get("/api/genetic-resources").param("query", query))
......@@ -73,7 +73,7 @@ class SearchControllerTest {
PageRequest pageRequest = PageRequest.of(0, SearchController.PAGE_SIZE);
String query = "pauca";
when(mockGeneticResourceDao.search(query, true, SearchRefinements.EMPTY, pageRequest))
when(mockGeneticResourceDao.search(query, true, false, SearchRefinements.EMPTY, pageRequest))
.thenReturn(new AggregatedPageImpl<>(
Arrays.asList(resource),
pageRequest,
......@@ -117,7 +117,7 @@ class SearchControllerTest {
.withTerm(RareAggregation.MATERIAL, Arrays.asList("m1"))
.build();
when(mockGeneticResourceDao.search(query, false, expectedRefinements, pageRequest))
when(mockGeneticResourceDao.search(query, false, false, expectedRefinements, pageRequest))
.thenReturn(new AggregatedPageImpl<>(Collections.emptyList(), pageRequest, 1));
mockMvc.perform(get("/api/genetic-resources")
......
Markdown is supported
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