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
InnerField
s in derived query methods? i.e. something likeSearchPage<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); } }