DEV Community

Cover image for Get Matching Score With Spring data elastic search in Spring Boot for a Query
Balvinder Singh
Balvinder Singh

Posted on • Edited on • Originally published at tekraze.com

1

Get Matching Score With Spring data elastic search in Spring Boot for a Query

Hi everyone, I am gonna share about the scoring and percentage from es query to order results and show to the user.

Previously, I was using an elastic search rest-client template to have a search query, but that way I have to do extract score, and list of data with mapping to the required format. The configuration is a little more and complex than using spring data elasticsearch directly. But after looking for a solution to fix some other issue I have, I got the solution for getting score directly from spring data elasticsearch with a little modification.


Let me share.

I have done with pagination, but you can do normally too by using stream with a list instead. let me know if you want in the comments below, I will add

  1. We create a normal Query like match query
  2. call the bookpage method with a query and pageable parameters
  3. Create a search query with required options
  4. Call the elastic search template query method to modify and extract the response. it is the main point where you get the hit score and total hits.
  5. call additional bookDOFromMap method to get a score and append to DTO.
    /*****
    * Tekraze.com for more
    *
    *****/
    ///Imports
    import org.springframework.data.domain.Page;
    import org.springframework.data.domain.PageImpl;
    import org.springframework.data.domain.PageRequest;
    import org.springframework.data.domain.Pageable;
    import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
    import org.springframework.data.elasticsearch.core.ResultsExtractor;
    import org.springframework.data.elasticsearch.core.query.*;
    import org.elasticsearch.search.SearchHit;
    import org.elasticsearch.action.search.SearchResponse;
    import com.fasterxml.jackson.databind.ObjectMapper;
    import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
    import static org.elasticsearch.index.query.QueryBuilders.*;
    /**
    * Method to modify query and get Hit Score, and total hits to get a match score
    * Instead of BookDTO , you can replace with your class
    *
    * @param query is any query like match query, bool query
    * @param the pageable paramter containing pagination properies like page size, page number
    **/
    Page<BookDTO> bookPage(QueryBuilder query, Pageable pageable) {
    /*We create a query with rquired properties */
    SearchQuery searchQuery = new NativeSearchQueryBuilder()
    .withQuery(query) // wrap the query we created like match query
    .withPageable(pageable) // if pagination required
    .withIndices(bookIndexName) // rquired name of index to search
    .withTrackScores(true) // required to get hits and total hits
    .build();
    // THe main logic, it is to modify the results and get hits
    // extracting from response object
    Page<BookDTO> result = elasticsearchTemplate.query(searchQuery, new ResultsExtractor<Page<BookDTO>>() {
    @Override
    public Page<BookDTO> extract(SearchResponse response) {
    List<BookDTO> bookList = new LinkedList<BookDTO>();
    // Modify DTO from helper method with score
    response.getHits().forEach(hit -> bookList.add(bookDTOFromMap(hit, response)));
    // return page of recordds with score as nested property of DTO
    return new PageImpl<BookDTO>(bookList, pageable, response.getHits().getTotalHits());
    }
    });
    return result;
    }
    /****
    **Helper method to get Matchh Score from Hits and total hits
    ** and append to the DTO propeerty/
    ****/
    BookDTO bookDTOFromMap(SearchHit hit, SearchResponse searchResponse) {
    log.debug("Method to get Book DTO from Book Map");
    // Mapper to map hit object our DDTO
    ObjectMapper objectMapper = new ObjectMapper().registerModule(new JavaTimeModule());
    BookDTO bookDTO = objectMapper.convertValue(hit.getSourceAsMap(), BookDTO.class);
    // The score calculate function
    BigDecimal matchPercentage = new BigDecimal((hit.getScore() / searchResponse.getHits().getMaxScore()) * 100)
    .setScale(2, RoundingMode.UP);
    // set the score to DTO property
    bookDTO.setMatchPercentage(matchPercentage);
    return bookDTO;
    }
  6. Now you have the score calculated from hit score of each record vs all records.

You can modify the query or scoring logic by using a function score query with a scoring function for your needs.
I hope it will help, you let me know in the comments
Also, do check out other blog for more tech posts like this.
https://tekraze.com

Image of Timescale

🚀 pgai Vectorizer: SQLAlchemy and LiteLLM Make Vector Search Simple

We built pgai Vectorizer to simplify embedding management for AI applications—without needing a separate database or complex infrastructure. Since launch, developers have created over 3,000 vectorizers on Timescale Cloud, with many more self-hosted.

Read more

Top comments (0)

Billboard image

Create up to 10 Postgres Databases on Neon's free plan.

If you're starting a new project, Neon has got your databases covered. No credit cards. No trials. No getting in your way.

Try Neon for Free →