Spring数据Elasticsearch按字段和最新日期查询找到

时间:2019-07-08 10:07:20

标签: java spring spring-boot elasticsearch spring-data-elasticsearch

我正在使用Spring Boot 2.1.6和Elasticsearch 6.2.2

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

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

Account findTop1ByAccountIdOrderByCreatedDesc(final String accountId);

我想这意味着它将从按accountId筛选的索引中进行选择,然后按创建的降序对结果进行排序,最后将仅返回第一个(最新)结果。

但是索引中只有两个条目,相同的条目减去创建的日期,并且该查询返回两个结果。我认为这意味着它不会转换为我的想法,而是会选择具有该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存储库魔术?

/ EDIT

原始问题:

我有一个这样声明的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的最新条目(创建的=最大值)。

我知道我可以使用查询生成器,但是我想知道是否有某种魔术可以通过使用春季命名查询来为我做这件事,目前我正在尝试(找不到其他有效的措辞组合) :

Account findTop1ByAccountIdOrderByCreatedDesc(final String accountId);

但是它返回null。我看到数据在索引中(修剪后的版本):

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魔术将不起作用。假设我不进行重命名,问题仍然是相同的。目前,我通过使用以下方法实现自己的逻辑来解决此问题:

@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);
    }

}

1 个答案:

答案 0 :(得分:1)

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

问题的确是使用@JsonProperty批注在索引中重命名此属性。据我所记得,在使用Template类而不是Repository类编写数据时,该批注还用于编写到索引的映射。因此,存储库查询在索引中搜索字段 accountId ,而数据存储在字段 ilmAccountIdentifier 中。

Spring Data Elasticsearch的3.2.0版本(当前RC1,RC2将于本月晚些时候发布,GA应该在9月初发布)具有一个新的Mapper实施,可以在不使用{{1 }},只需使用@JsonProperty批注:

@Field

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

作为解决方法,您可以将@Field(name="ilmAccountIdentifier", type = FieldType.Text) private String accountId; 属性重命名为accountId吗?

相关问题