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

发布于 2025-01-16 14:26:16 字数 379 浏览 2 评论 0原文

假设我有这样的映射,并且我想通过“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"
        }
      }
    }

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

明月松间行 2025-01-23 14:26:16

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

SearchHits<Foo> searchByRequestId_Keyword(String keyword);

方法名称的分析是在 spring-data-common 模块中完成的,该模块仅使用 Java 的属性名称实体的属性(可能是嵌套的)。但是 keyword 子字段仅存在于 Elasticsearch 中,并且(如果不是自动创建)存在于 @MultiField 注释中。但是解析方法名的代码不使用特定于商店的信息,因此这样的方法将不起作用并失败,并出现 keyword 不是 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
}

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
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文