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)
我正在使用 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)