【问题标题】:Spring Data Elasticsearch Class Cast exception on Named Query命名查询上的 Spring Data Elasticsearch Class Cast 异常
【发布时间】:2021-08-03 07:03:25
【问题描述】:

尝试将命名查询与 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,只支持详细的返回类型的子集here

此外,我还需要使用 SearchPage 返回类型,因为那里有我需要做出决定的元数据。

所以我想有几个问题:

  • 是否可以在派生查询方法中使用InnerFields?即类似SearchPage&lt;PlayerEntity&gt; findPlayerEntityByPlayerNumber_KeywordIn(List&lt;String&gt; playerNumbers, Pageable pageable);
  • 命名查询是否可以返回SearchPage?我认为这可能通过自定义存储库实现来实现,但如果我可以让上述任何一种方法发挥作用,那将是理想的。

感谢您的帮助!!

spring-data-elasticsearch 版本:4.0.3.RELEASE

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

elasticsearch 版本:7.11.1

【问题讨论】:

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


    【解决方案1】:

    回答您的第二个问题(命名查询是否可以返回 SearchPage?):这是一个错误,它不适用于 @Query 带注释的方法。我昨天为 main4.2.x4.1.x4.0.x 分支修复了这个问题,所以它将在下一个服务版本发布时工作。

    要回答第一个问题,我需要先进行一些研究和测试,然后才能对此发表任何看法 - 如果它有效,那就太好了。我想我可以在本周末晚些时候提供更多信息。

    编辑/添加:

    方法名称的查询派生基于 Java 类的属性,并在 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);
            }
        }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-05-06
      • 2014-10-23
      • 1970-01-01
      • 2016-03-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多