Spring data Elasticsearch 按字段查找和最新日期查询

Spring data Elasticsearch find by field and latest date query

我正在使用 Spring Boot 2.1.6 和 Elasticsearch 6.2.2

编辑以更好地阐明我的问题

当我让 Spring 在我的存储库中使用以下方法为我生成查询时:

Account findTop1ByAccountIdOrderByCreatedDesc(final String accountId);

我想这意味着它将 select 从索引中按 accountId 过滤,然后按创建的降序对结果进行排序,最后它将 return 只有第一个(最新)结果。

但我在索引中只有两个条目,相同的条目减去创建日期,并且该查询 returns 两个结果。我认为这意味着它不会转化为我的想法,而是会选择所有具有该 ID 的帐户(因为这是一个键,所有都是 "top"),按降序排列。

这会更符合我的查询,但它不是合法的命名:

Account findTop1OrderByCreatedDescByAccountId(final String accountId);

org.springframework.data.mapping.PropertyReferenceException: No property descByAccountId found for type LocalDateTime! Traversed path: Account.created.

还有这个:

Account findTop1OrderByCreatedDescAndAccountIdEquals(final String accountId);

org.springframework.data.mapping.PropertyReferenceException: No property desc found for type LocalDateTime! Traversed path: Account.created.

那么,如果可能的话,我该如何翻译我对 Spring 存储库魔法的查询?

/编辑

原问题:

我有一个这样声明的 POJO(精简版):

@Document(indexName = "config.account", type = "account")
public class Account{

    @Id
    private String id;

    @Field(type = FieldType.Text)
    @JsonProperty("ilmAccountIdentifier")
    private String accountId;

    @Field(type = FieldType.Text)
    private String endOfBusinessDay;

    @Field(type = FieldType.Date)
    private LocalDateTime created;

}

我想查询索引以检索给定 accountId 的最新条目 (created = max)。

我知道我可以使用查询构建器,但我想知道是否有一些魔法可以通过使用 spring 命名查询为我做到这一点,目前我正在尝试(找不到其他有效的措辞组合):

Account findTop1ByAccountIdOrderByCreatedDesc(final String accountId);

但它 return 是空的。我看到数据在索引中(修剪版本):

Account(id=W83u0GsBEjwDhWt1-Whn,
accountId=testfindByAccountIdReturnsLatestVersion,
endOfBusinessDay=17:00:00,
created=2019-07-08T09:34)

但是生成的查询 Spring 很奇怪,不是我所期望的:

SearchRequest{
searchType=QUERY_THEN_FETCH,
indices=[config.account],
indicesOptions=IndicesOptions[ignore_unavailable=false, allow_no_indices=true, expand_wildcards_open=true, expand_wildcards_closed=false, allow_aliases_to_multiple_indices=true, forbid_closed_indices=true, ignore_aliases=false],
types=[account],
routing='null',
preference='null',
requestCache=null,
scroll=null,
maxConcurrentShardRequests=0,
batchedReduceSize=512,
preFilterShardSize=128,
allowPartialSearchResults=null,
source={
  "from":0,
  "query":{
    "bool":{
      "must":[{
        "query_string": 
          {"query":
             "testfindByAccountIdReturnsLatestVersion",
             "fields": ["accountId^1.0"],
             "type":"best_fields",
             "default_operator":"and",
             "max_determinized_states":10000,
             "enable_position_increments":true,
             "fuzziness":"AUTO",
             "fuzzy_prefix_length":0,
             "fuzzy_max_expansions":50,
             "phrase_slop":0,
             "escape":false,
             "auto_generate_synonyms_phrase_query":true,
             "fuzzy_transpositions":true,
             "boost":1.0}
          }],
        "adjust_pure_negative":true,"boost":1.0}
      }
,"version":true}}

我想要的是这个 SQL 查询的等价物:

select *
from(
  select *
  from account
  where accountId = ?
  order by created desc
)
where rownum = 1

是否可以使用 Spring 魔术,或者我必须使用 QueryBuilder 或我自己的逻辑吗?

感谢和欢呼

编辑

无关,但我意识到如果在使用@JsonProperty 映射期间重命名字段,spring 存储库魔法将不起作用。假设我不做那个重命名,问题仍然是一样的。目前我通过以下方式实现自己的逻辑来解决这个问题:

@Repository
public interface AccountRepository  extends ElasticsearchRepository<Account, String>, AccountRepositoryCustom {

    List<Account> findByIlmAccountIdentifierOrderByCreatedDesc(final String accountId);

}

public interface AccountRepositoryCustom {

    Account findLatestByAccountId(final String accountId);

}

@Repository
public class AccountRepositoryImpl implements AccountRepositoryCustom {

    @Autowired
    @Lazy
    private AccountRepository accountRepository;

    public Account findLatestByAccountId(final String accountId){
        return accountRepository.findByIlmAccountIdentifierOrderByCreatedDesc(accountId).get(0);
    }

}

对于从方法名称构建的查询,您必须使用文档 class 中的 属性 名称,因此此处 findByAccountId 是正确的。

问题确实是在索引中用 @JsonProperty 注释重命名了这个 属性。此注释用于将映射写入索引,据我所知,在使用模板 classes 而不是存储库 classes 写入数据时也是如此。因此存储库查询在索引中搜索字段 accountId,而数据存储在字段 ilmAccountIdentifier.

Spring Data Elasticsearch 的 3.2.0 版本(目前是 RC1,RC2 将在本月晚些时候发布,GA 应该在九月初发布)有一个新的 Mapper 实现可用,这是在没有 @JsonProperty 的情况下工作,只需使用 @Field 注释:

@Field(name="ilmAccountIdentifier", type = FieldType.Text)
private String accountId;

但是 3.2.x 不适用于 Elasticsearch 6.2,您需要更新到 6.7。

作为解决方法,您可以将 accountId 属性 重命名为 ilmAccountIdentifier 吗?

编辑 23.07.2019:

我刚刚发现用 topN 限制结果不起作用是 Spring Data Elasticsearch 中的 old bug,似乎它从未在这个sub-module。所以请为这个问题投票。

注意:spring-data-elasticsearch是一个社区驱动的模块,所以我们靠贡献生活!

编辑 2019 年 11 月 28 日:

我在 2019 年 8 月实现了 topN,它将出现在 Spring Data Elasticsearch Neumann 版本(版本 4)