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,它支持 TextKeyword 的字段类型,如下所示:

@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 类型,因为那里有我需要做决定的元数据。

所以我想由此产生了几个问题:

感谢您的帮助!!

spring-data-elasticsearch版本:4.0.3.RELEASE

spring-boot-starter-parent 版本:2.3.3.RELEASE

弹性搜索版本:7.11.1

回答你的第二个问题(命名查询是否可以 return 搜索页面?):这是一个错误,它不适用于 @Query 注释方法。我昨天为 main4.2.x4.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);
        }
    }