Skip to content
Advertisement

Spring Data Elasticsearch Class Cast exception on Named Query

I’m getting the following exception when trying to use a named query with Spring Data Elasticsearch.

ClassCastException: org.springframework.data.elasticsearch.core.aggregation.impl.AggregatedPageImpl cannot be cast to org.springframework.data.elasticsearch.core.SearchPage

The query I’m trying to make is:

public interface PlayerRepository extends ElasticsearchRepository<PlayerEntity, String> {
  
  @Query("{"bool":{"must":[{"terms":{"playerNumber.keyword": ?0}}]}}")
  SearchPage<PlayerEntity> fetchPlayers(JSONArray playerNumbers, Pageable pageable);
}

If I do not use the @Query annotation and instead let Spring derive the query from the method name like so:

SearchPage<PlayerEntity> findPlayerEntityByPlayerNumberIn(List<String> playerNumbers, Pageable pageable);

It works as expected. However, the PlayerNumber field is a @MultiField that supports the the field types of Text and Keyword like so:

@Document(indexName = "#{@playersIndexName}")
public class PlayerEntity {

  @MultiField(
      mainField = @Field(type = Text, name = "playerNumber"),
      otherFields = {@InnerField(suffix = "keyword", type = Keyword)})
  private String playerNumber;

  ...
}

And I need to use the keyword mapping here for the query and not the text mapping. As far as I can tell, Spring Data Elasticsearch cannot derive queries from method names on InnerField, which is why I went with the named query approach. But it seems like the using the declared query approach, detailed here, only supports a subset of return types as detailed here

In addition, I need to use the SearchPage return type as well, because there is metadata there that I need to make decisions on.

So I guess there are a couple of questions that come out of this:

  • Is it possible to use InnerFields in derived query methods? i.e. something like SearchPage<PlayerEntity> findPlayerEntityByPlayerNumber_KeywordIn(List<String> playerNumbers, Pageable pageable);
  • Is it possible for a named query to return a SearchPage? I think this might be possible with a custom Repository implementation, but if I could get either approach above to work that would be ideal.

Thanks for any help!!

spring-data-elasticsearch version: 4.0.3.RELEASE

spring-boot-starter-parent version: 2.3.3.RELEASE

elasticsearch version: 7.11.1

Advertisement

Answer

To answer your second question (Is it possible for a named query to return a SearchPage?): This is a bug that it does not work with @Query annotated methods. I fixed that yesterday for the main, 4.2.x, 4.1.x and 4.0.x branches so it will work when the next service releases are out.

To answer the first one, I will need to do some research and tests before I can say anything about that – it would be great if it would work. I think I’ can give more information later this weekend.

Edit/Addition:

The query derivation from the method name is based on the properties of the Java class and is done in the Spring Data base which knows nothing about these inner fields that only exist in Elasticsearch.

But you can use the following custom repository fragment:

    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);
        }
    }
User contributions licensed under: CC BY-SA
3 People found this is helpful
Advertisement