Spring Data Elasticsearch Class 对命名查询投射异常
Spring Data Elasticsearch Class Cast exception on Named Query
尝试将命名查询与 Spring Data Elasticsearch 结合使用时出现以下异常。
ClassCastException: org.springframework.data.elasticsearch.core.aggregation.impl.AggregatedPageImpl cannot be cast to org.springframework.data.elasticsearch.core.SearchPage
我要查询的是:
public interface PlayerRepository extends ElasticsearchRepository<PlayerEntity, String> {
@Query("{\"bool\":{\"must\":[{\"terms\":{\"playerNumber.keyword\": ?0}}]}}")
SearchPage<PlayerEntity> fetchPlayers(JSONArray playerNumbers, Pageable pageable);
}
如果我不使用 @Query
注释而是让 Spring 从方法名称派生查询,如下所示:
SearchPage<PlayerEntity> findPlayerEntityByPlayerNumberIn(List<String> playerNumbers, Pageable pageable);
它按预期工作。但是,PlayerNumber
字段是一个 @MultiField
,它支持 Text
和 Keyword
的字段类型,如下所示:
@Document(indexName = "#{@playersIndexName}")
public class PlayerEntity {
@MultiField(
mainField = @Field(type = Text, name = "playerNumber"),
otherFields = {@InnerField(suffix = "keyword", type = Keyword)})
private String playerNumber;
...
}
而且我需要在此处使用关键字映射进行查询,而不是文本映射。据我所知,Spring Data Elasticsearch 无法从 InnerField
上的方法名称派生查询,这就是我采用命名查询方法的原因。不过好像是用声明查询的方式,详见here, only supports a subset of return types as detailed here
此外,我还需要使用 SearchPage
return 类型,因为那里有我需要做决定的元数据。
所以我想由此产生了几个问题:
- 是否可以在派生查询方法中使用
InnerField
s?即类似 SearchPage<PlayerEntity> findPlayerEntityByPlayerNumber_KeywordIn(List<String> playerNumbers, Pageable pageable);
- 命名查询是否可以 return 和
SearchPage
?我认为这可以通过自定义存储库实现实现,但如果我可以采用上述任何一种方法来工作,那将是理想的。
感谢您的帮助!!
spring-data-elasticsearch版本:4.0.3.RELEASE
spring-boot-starter-parent 版本:2.3.3.RELEASE
弹性搜索版本:7.11.1
回答你的第二个问题(命名查询是否可以 return 搜索页面?):这是一个错误,它不适用于 @Query
注释方法。我昨天为 main、4.2.x、4.1.x[= 修复了这个问题29=] 和 4.0.x 分支,因此它将在下一个服务版本发布时工作。
要回答第一个问题,我需要先做一些研究和测试,然后才能对此发表任何看法 - 如果可行,那就太好了。我想我可以在本周末晚些时候提供更多信息。
Edit/Addition:
方法名称的查询派生基于 Java class 的属性,并在 Spring 数据库中完成,该数据库对这些内部字段一无所知存在于 Elasticsearch 中。
但您可以使用以下自定义存储库片段:
public interface CustomPlayerRepository {
SearchPage<PlayerEntity> findPlayerEntityByPlayerNumberKeywordIn(List<String> playerNumbers, Pageable pageable);
}
public class CustomPlayerRepositoryImpl implements CustomPlayerRepository {
private final ElasticsearchOperations operations;
public CustomPlayerRepositoryImpl(ElasticsearchOperations operations) {
this.operations = operations;
}
@Override
public SearchPage<PlayerEntity> findPlayerEntityByPlayerNumberKeywordIn(
List<String> playerNumbers, Pageable pageable) {
var criteriaQuery = new CriteriaQuery(new Criteria("playerNumber.keyword").in(playerNumbers), pageable);
var searchHits = operations.search(criteriaQuery, PlayerEntity.class);
return SearchHitSupport.searchPageFor(searchHits, pageable);
}
}
尝试将命名查询与 Spring Data Elasticsearch 结合使用时出现以下异常。
ClassCastException: org.springframework.data.elasticsearch.core.aggregation.impl.AggregatedPageImpl cannot be cast to org.springframework.data.elasticsearch.core.SearchPage
我要查询的是:
public interface PlayerRepository extends ElasticsearchRepository<PlayerEntity, String> {
@Query("{\"bool\":{\"must\":[{\"terms\":{\"playerNumber.keyword\": ?0}}]}}")
SearchPage<PlayerEntity> fetchPlayers(JSONArray playerNumbers, Pageable pageable);
}
如果我不使用 @Query
注释而是让 Spring 从方法名称派生查询,如下所示:
SearchPage<PlayerEntity> findPlayerEntityByPlayerNumberIn(List<String> playerNumbers, Pageable pageable);
它按预期工作。但是,PlayerNumber
字段是一个 @MultiField
,它支持 Text
和 Keyword
的字段类型,如下所示:
@Document(indexName = "#{@playersIndexName}")
public class PlayerEntity {
@MultiField(
mainField = @Field(type = Text, name = "playerNumber"),
otherFields = {@InnerField(suffix = "keyword", type = Keyword)})
private String playerNumber;
...
}
而且我需要在此处使用关键字映射进行查询,而不是文本映射。据我所知,Spring Data Elasticsearch 无法从 InnerField
上的方法名称派生查询,这就是我采用命名查询方法的原因。不过好像是用声明查询的方式,详见here, only supports a subset of return types as detailed here
此外,我还需要使用 SearchPage
return 类型,因为那里有我需要做决定的元数据。
所以我想由此产生了几个问题:
- 是否可以在派生查询方法中使用
InnerField
s?即类似SearchPage<PlayerEntity> findPlayerEntityByPlayerNumber_KeywordIn(List<String> playerNumbers, Pageable pageable);
- 命名查询是否可以 return 和
SearchPage
?我认为这可以通过自定义存储库实现实现,但如果我可以采用上述任何一种方法来工作,那将是理想的。
感谢您的帮助!!
spring-data-elasticsearch版本:4.0.3.RELEASE
spring-boot-starter-parent 版本:2.3.3.RELEASE
弹性搜索版本:7.11.1
回答你的第二个问题(命名查询是否可以 return 搜索页面?):这是一个错误,它不适用于 @Query
注释方法。我昨天为 main、4.2.x、4.1.x[= 修复了这个问题29=] 和 4.0.x 分支,因此它将在下一个服务版本发布时工作。
要回答第一个问题,我需要先做一些研究和测试,然后才能对此发表任何看法 - 如果可行,那就太好了。我想我可以在本周末晚些时候提供更多信息。
Edit/Addition:
方法名称的查询派生基于 Java class 的属性,并在 Spring 数据库中完成,该数据库对这些内部字段一无所知存在于 Elasticsearch 中。
但您可以使用以下自定义存储库片段:
public interface CustomPlayerRepository {
SearchPage<PlayerEntity> findPlayerEntityByPlayerNumberKeywordIn(List<String> playerNumbers, Pageable pageable);
}
public class CustomPlayerRepositoryImpl implements CustomPlayerRepository {
private final ElasticsearchOperations operations;
public CustomPlayerRepositoryImpl(ElasticsearchOperations operations) {
this.operations = operations;
}
@Override
public SearchPage<PlayerEntity> findPlayerEntityByPlayerNumberKeywordIn(
List<String> playerNumbers, Pageable pageable) {
var criteriaQuery = new CriteriaQuery(new Criteria("playerNumber.keyword").in(playerNumbers), pageable);
var searchHits = operations.search(criteriaQuery, PlayerEntity.class);
return SearchHitSupport.searchPageFor(searchHits, pageable);
}
}