2

I'm trying to see and use the invidual _score of each hit when doing a search by a SearchQuery. This is, among other things, to know in what range of scores my searches result in. But other than setting a MinScore using searchQuery.withMinScore(float); I can't find any method for handling the scores of search.

@Override
public Page<Website> listsearch(SearchBody searchBody, int size, int page) {
    BoolQueryBuilder qb = QueryBuilders.boolQuery();

    for(SearchUnit unit:searchBody.getSearchBody()){
        if(unit.isPriority()) {
            qb.must(matchQuery("_all", unit.getWord()).operator(MatchQueryBuilder.Operator.AND)
                    .fuzziness(Fuzziness.AUTO));

        }else {
            qb.should(termQuery("_all", unit.getWord())
                    .boost(unit.getWeight()));
        }
    }

    for(SearchUnit ExUnit:searchBody.getExcludeBody()){
        qb.mustNot(matchPhraseQuery("_all",ExUnit.getWord()));
    }

    SearchQuery searchQuery = new NativeSearchQueryBuilder()
            .withIndices("websites_v1")
            .withTypes("website")
            .withQuery(qb)
            .withMinScore(0.05F)//Magical minscore
            .withPageable(new PageRequest(page, size))
            .build();


    Page<Website> search = searchRepository.search(searchQuery);
    return search;

}

The search function used is from org.springframework.data.elasticsearch.repository; defined as

Page<T> search(SearchQuery var1);

So my question is there anyway I can access the score of each returned object in the Page? Or do I need to switch my query method to something else to achive that?

Anton Schillén
  • 331
  • 1
  • 4
  • 11

1 Answers1

3

This is not possible with the Spring Data ElasticSearch repositories.

You need to autowire an EntityMapper and an ElasticSearchTemplate and extract the score yourself. Something like this should work:

Pageable pageRequest = new PageRequest(0, 10);
Page<Website> result = elasticSearchTemplate.query(searchQuery, new ResultsExtractor<Page<Website>>() {
    @Override
    public Page<Website> extract(SearchResponse response) {
        List<Website> content = new ArrayList<>();
        SearchHit[] hits = response.getHits().getHits();
        for (SearchHit hit : hits) {
            Website website = entityMapper.mapToObject(hit, Website.class);
            content.add(website);
            float documentScore = hit.getScore(); // <---- score of a hit
        }
        return new PageImpl<Website>(content, pageRequest, response.getHits().getTotalHits());
    }
});
Aerus
  • 4,332
  • 5
  • 43
  • 62
  • How to autowire entityMapper? I get bean not found exception if I try that. Any solution for that? – Patrick Feb 14 '18 at 16:27
  • @patrick `@Autowired EntityMapper entityMapper` should work, it's in package `org.springframework.data.elasticsearch.core` so if you have `spring-data-elasticsearch` in your Maven/Gradle dependencies it should find it... – Aerus Feb 16 '18 at 06:57
  • Strange it does not work for me. I raised a [question](https://stackoverflow.com/q/48830308/3493036) to see if there is anything wrong in my code or if there are changes in the spring api. – Patrick Feb 16 '18 at 15:49