Spring data elasticsearch如何为关键字字段创建存储库方法

Spring data elasticsearch how to create repository method for keyword field

假设我有这样的映射,我想通过“requestId.keyword”字段进行搜索以获取精确匹配请求。如何在不使用 @Query 注释的情况下使用 Spring Data Elasticsearch 存储库实现它?

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

这对于通过内省方法名称构建查询的机制是不可能的。第一个想法是有类似的东西(我在这里使用 Foo 实体):

SearchHits<Foo> searchByRequestId_Keyword(String keyword);

方法名称的分析在 spring-data-common 模块中完成,该模块仅使用实体的 Java 属性的 属性 名称(可能是嵌套的)。但是 keyword 子字段仅存在于 Elasticsearch 中,并且 - 如果不是自动创建的 - 在 @MultiField 注释中。但是解析方法名的代码不使用 store-specific 信息,所以像这样的方法将不起作用并且会失败,错误是 keyword is not a 属性 of text - 这适用于 Java 对象。

您可以做的是首先添加自定义存储库片段接口:

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

并提供一个必须像接口一样命名的实现,后缀为Impl

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
    }
}

您有一个 ElasticsearchOperations 注入并使用它来执行您构建的查询。我使用了两种方法来构建查询,都有效。

您要使用的存储库定义将是:

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