Home > Mobile >  Spring data elasticsearch how to create repository method for keyword field
Spring data elasticsearch how to create repository method for keyword field

Time:03-25

Let's say I have mapping like this, and I want to search by the "requestId.keyword" field to fetch the exact match requests. How can I implement it with the Spring Data Elasticsearch repository without using @Query annotation?

 "requestId": {
      "type": "text",
      "analyzer": "1_to_15_analyzer_without_space",
      "search_analyzer": "all_symbols_and_fold_analyzer",
      "fields": {
        "keyword": {
          "type": "keyword"
        }
      }
    }

CodePudding user response:

This is not possible with the mechanism to build queries by introspecting the method name. The first idea is to have something like (I am using a Foo entity here):

SearchHits<Foo> searchByRequestId_Keyword(String keyword);

The analysis of the method name is done in the spring-data-common module which only uses the property names of the Java properties of an entity (might be nested). But the keyword subfield only exists in Elasticsearch and - if not autocreated - in the @MultiField annotation. But the code to parse the methodname does not use store-specific information and so an approach like this will not work and fail with the error that keyword is not a property of text - which is right for the Java object.

What you can do is to first add a custom repository fragment interface:

public interface FooKeywordRepository {
    SearchHits<Foo> searchByRequestIdKeyword(String keyword);
}

and provide an implementation that must be named like the interface with Impl as suffix:

import org.elasticsearch.index.query.QueryBuilders;
import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.data.elasticsearch.core.query.Criteria;
import org.springframework.data.elasticsearch.core.query.CriteriaQuery;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.data.elasticsearch.core.query.Query;

public class FooKeywordRepositoryImpl implements FooKeywordRepository {

    private final ElasticsearchOperations operations;

    public FooKeywordRepositoryImpl(ElasticsearchOperations operations) {
        this.operations = operations;
    }

    @Override
    public SearchHits<Foo> searchByRequestIdKeyword(String keyword) {

        Query query1 = new NativeSearchQueryBuilder()
            .withQuery(QueryBuilders.termQuery("requestId.keyword", keyword))
            .build();

        Query query2 = new CriteriaQuery(Criteria.where("requestId.keyword").is(keyword));

        return operations.search(query1, Foo.class); // could be query2 as well
    }
}

You have an ElasticsearchOperations injected and use that to execute a query that you build. I have put in two ways to build the query, both work.

Your repository definition to use would then be:

public interface FooRepository extends ElasticsearchRepository<Foo, String>, FooKeywordRepository {
    // other custom methods if needed
}
  • Related