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

feat: allow aggregating and searching with aggregation criteria at the same time

parent 27c9975f
......@@ -13,6 +13,7 @@ import java.util.stream.Stream;
import fr.inra.urgi.rare.domain.GeneticResource;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.MultiMatchQueryBuilder;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import fr.inra.urgi.rare.domain.IndexedGeneticResource;
import org.elasticsearch.action.search.SearchRequestBuilder;
......@@ -26,6 +27,7 @@ import org.springframework.data.elasticsearch.core.aggregation.AggregatedPage;
import org.springframework.data.elasticsearch.core.query.FetchSourceFilterBuilder;
import org.springframework.data.elasticsearch.core.query.IndexQuery;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.data.elasticsearch.core.query.SourceFilter;
/**
* Implementation of {@link GeneticResourceDaoCustom}
......@@ -75,16 +77,26 @@ public class GeneticResourceDaoImpl implements GeneticResourceDaoCustom {
boolean aggregate,
SearchRefinements refinements,
Pageable page) {
BoolQueryBuilder boolQueryBuilder = boolQuery()
.must(multiMatchQuery(query, SEARCHABLE_FIELDS.toArray(new String[0])));
// this full text query is executed, and its results are used to compute aggregations
MultiMatchQueryBuilder fullTextQuery = multiMatchQuery(query, SEARCHABLE_FIELDS.toArray(new String[0]));
// this post filter query is applied, after the aggregation have been computed, to apply the
// refinements (i.e. the aggregation/facet criteria).
// See https://www.elastic.co/guide/en/elasticsearch/reference/current/search-request-post-filter.html
BoolQueryBuilder refinementQuery = boolQuery();
for (RareAggregation term : refinements.getTerms()) {
boolQueryBuilder.must(termsQuery(term.getField(), refinements.getRefinementsForTerm(term)));
refinementQuery.must(termsQuery(term.getField(), refinements.getRefinementsForTerm(term)));
}
// this allows avoiding to get back the suggestions field in the found documents, since we don't care
// about them, and they're large
SourceFilter sourceFilter = new FetchSourceFilterBuilder().withExcludes(SUGGESTIONS_FIELD).build();
NativeSearchQueryBuilder builder = new NativeSearchQueryBuilder()
.withQuery(boolQueryBuilder)
.withSourceFilter(new FetchSourceFilterBuilder().withExcludes(SUGGESTIONS_FIELD).build())
.withQuery(fullTextQuery)
.withSourceFilter(sourceFilter)
.withFilter(refinementQuery)
.withPageable(page);
if (aggregate) {
......
......@@ -425,6 +425,35 @@ class GeneticResourceDaoTest {
geneticResourceDao.search("hello", false, refinements, firstPage);
assertThat(result.getContent()).isEmpty();
}
@Test
public void shouldApplyRefinementsAfterAggregating() {
SearchRefinements refinements =
SearchRefinements.builder()
.withTerm(RareAggregation.DOMAIN, Arrays.asList("Plantae"))
.build();
AggregatedPage<GeneticResource> result =
geneticResourceDao.search("hello", true, refinements, firstPage);
assertThat(result.getContent()).extracting(GeneticResource::getId).containsOnly("r1");
// aggregations are computed based on the result of the full-text-query, not based on the result
// of the refinements
Terms domain = result.getAggregations().get(RareAggregation.DOMAIN.getName());
assertThat(domain.getBuckets()).hasSize(2);
assertThat(domain.getBuckets()).extracting(Bucket::getKeyAsString).containsOnly("Plantae", "Fungi");
assertThat(domain.getBuckets()).extracting(Bucket::getDocCount).containsOnly(1L);
result = geneticResourceDao.search("Human", true, refinements, firstPage);
assertThat(result.getContent()).extracting(GeneticResource::getId).containsOnly("r1");
domain = result.getAggregations().get(RareAggregation.DOMAIN.getName());
assertThat(domain.getBuckets()).hasSize(1);
assertThat(domain.getBuckets()).extracting(Bucket::getKeyAsString).containsOnly("Plantae");
assertThat(domain.getBuckets()).extracting(Bucket::getDocCount).containsOnly(1L);
}
}
private void shouldSuggest(BiConsumer<GeneticResourceBuilder, String> config) {
......
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