Search code examples
javaspring-bootspring-dataspring-data-elasticsearch

How to use terms query in custom elastic search query java?


I want to search a field against an array of values in elastic search. I am writing custom terms query in java but it fails every time.

Code -

@Query("{ \"bool\" : { \"must\" : [\t{ \"term\" : {\"userId\" : ?0 } },\t{ \"terms\" : { \"language\" : ?1 } } ] } }")
List<PostElastic> findByProviderIdAndLanguagesPostOrderLessThanFromId(Long providerId, List<String> languages, Long fromTimestamp,Pageable pageable);

I get the following exception when I pass any value for language field

java.io.IOException: Unrecognized token 'en': was expecting ('true', 'false' or 'null')
at [Source: [B@20502fa2; line: 1, column: 86]
at com.fasterxml.jackson.core.JsonParser._constructError(JsonParser.java:1702) ~[jackson-core-2.9.6.jar:2.9.6]
at com.fasterxml.jackson.core.base.ParserMinimalBase._reportError(ParserMinimalBase.java:558) ~[jackson-core-2.9.6.jar:2.9.6]
at com.fasterxml.jackson.core.json.UTF8StreamJsonParser._reportInvalidToken(UTF8StreamJsonParser.java:3528) ~[jackson-core-2.9.6.jar:2.9.6]
at com.fasterxml.jackson.core.json.UTF8StreamJsonParser._handleUnexpectedValue(UTF8StreamJsonParser.java:2686) ~[jackson-core-2.9.6.jar:2.9.6]
at com.fasterxml.jackson.core.json.UTF8StreamJsonParser._nextTokenNotInObject(UTF8StreamJsonParser.java:878) ~[jackson-core-2.9.6.jar:2.9.6]
at com.fasterxml.jackson.core.json.UTF8StreamJsonParser.nextToken(UTF8StreamJsonParser.java:772) ~[jackson-core-2.9.6.jar:2.9.6]
at org.elasticsearch.common.xcontent.json.JsonXContentParser.nextToken(JsonXContentParser.java:55) ~[elasticsearch-5.6.10.jar:5.6.10]
at org.elasticsearch.index.query.TermsQueryBuilder.parseValues(TermsQueryBuilder.java:391) ~[elasticsearch-5.6.10.jar:5.6.10]
at org.elasticsearch.index.query.TermsQueryBuilder.fromXContent(TermsQueryBuilder.java:356) ~[elasticsearch-5.6.10.jar:5.6.10]
at org.elasticsearch.search.SearchModule.lambda$registerQuery$10(SearchModule.java:763) ~[elasticsearch-5.6.10.jar:5.6.10]
at org.elasticsearch.common.xcontent.NamedXContentRegistry.parseNamedObject(NamedXContentRegistry.java:143) ~[elasticsearch-5.6.10.jar:5.6.10]
at org.elasticsearch.common.xcontent.support.AbstractXContentParser.namedObject(AbstractXContentParser.java:402) ~[elasticsearch-5.6.10.jar:5.6.10]
at org.elasticsearch.index.query.QueryParseContext.parseInnerQueryBuilder(QueryParseContext.java:122) ~[elasticsearch-5.6.10.jar:5.6.10]
at org.elasticsearch.index.query.BoolQueryBuilder.fromXContent(BoolQueryBuilder.java:356) ~[elasticsearch-5.6.10.jar:5.6.10]
at org.elasticsearch.search.SearchModule.lambda$registerQuery$10(SearchModule.java:763) ~[elasticsearch-5.6.10.jar:5.6.10]
at org.elasticsearch.common.xcontent.NamedXContentRegistry.parseNamedObject(NamedXContentRegistry.java:143) ~[elasticsearch-5.6.10.jar:5.6.10]
at org.elasticsearch.common.xcontent.support.AbstractXContentParser.namedObject(AbstractXContentParser.java:402) ~[elasticsearch-5.6.10.jar:5.6.10]
at org.elasticsearch.index.query.QueryParseContext.parseInnerQueryBuilder(QueryParseContext.java:122) ~[elasticsearch-5.6.10.jar:5.6.10]
at org.elasticsearch.index.query.WrapperQueryBuilder.doRewrite(WrapperQueryBuilder.java:167) ~[elasticsearch-5.6.10.jar:5.6.10]
at org.elasticsearch.index.query.AbstractQueryBuilder.rewrite(AbstractQueryBuilder.java:263) ~[elasticsearch-5.6.10.jar:5.6.10]
at org.elasticsearch.search.builder.SearchSourceBuilder.rewrite(SearchSourceBuilder.java:879) ~[elasticsearch-5.6.10.jar:5.6.10]
at org.elasticsearch.search.internal.ShardSearchLocalRequest.rewrite(ShardSearchLocalRequest.java:244) ~[elasticsearch-5.6.10.jar:5.6.10]
at org.elasticsearch.search.internal.ShardSearchTransportRequest.rewrite(ShardSearchTransportRequest.java:171) ~[elasticsearch-5.6.10.jar:5.6.10]
at org.elasticsearch.search.SearchService.createSearchContext(SearchService.java:530) ~[elasticsearch-5.6.10.jar:5.6.10]
at org.elasticsearch.search.SearchService.createContext(SearchService.java:479) ~[elasticsearch-5.6.10.jar:5.6.10]
at org.elasticsearch.search.SearchService.createAndPutContext(SearchService.java:461) ~[elasticsearch-5.6.10.jar:5.6.10]
at org.elasticsearch.search.SearchService.executeDfsPhase(SearchService.java:226) ~[elasticsearch-5.6.10.jar:5.6.10]
at org.elasticsearch.action.search.SearchTransportService$5.messageReceived(SearchTransportService.java:332) ~[elasticsearch-5.6.10.jar:5.6.10]
at org.elasticsearch.action.search.SearchTransportService$5.messageReceived(SearchTransportService.java:329) ~[elasticsearch-5.6.10.jar:5.6.10]
at org.elasticsearch.transport.RequestHandlerRegistry.processMessageReceived(RequestHandlerRegistry.java:69) ~[elasticsearch-5.6.10.jar:5.6.10]
at org.elasticsearch.transport.TransportService$7.doRun(TransportService.java:662) ~[elasticsearch-5.6.10.jar:5.6.10]
at org.elasticsearch.common.util.concurrent.ThreadContext$ContextPreservingAbstractRunnable.doRun(ThreadContext.java:675) ~[elasticsearch-5.6.10.jar:5.6.10]
at org.elasticsearch.common.util.concurrent.AbstractRunnable.run(AbstractRunnable.java:37) ~[elasticsearch-5.6.10.jar:5.6.10]
... 3 common frames omitted

I can't use term query because array size is variable so checking for each element is not possible When I run the query directly over elastic search using postman it works.

Am I writing any wrong query, I can't find any sources online


Solution

  • According to the documentation for the @Query annotation, you have to add the double quotes yourself if you plan to use a String parameter:

    Example 54. Declare query at the method using the @Query annotation.

    public interface BookRepository extends ElasticsearchRepository<Book, String> {
        @Query("{\"bool\" : {\"must\" : {\"field\" : {\"name\" : \"?0\"}}}}")
        Page<Book> findByName(String name,Pageable pageable);
    }
    

    This also explains the error you get, because you're actually sending {"language": en} in stead of {"language": "en"}. And the only possible unquoted values are null, true or false (hence the error message).

    In your case you can solve it by using:

    @Query("{ \"bool\" : { \"must\" : [\t{ \"term\" : {\"userId\" : ?0 } },\t{ \"terms\" : { \"language\" : \"?1\" } } ] } }")
    List<PostElastic> findByProviderIdAndLanguagesPostOrderLessThanFromId(Long providerId, List<String> languages, Long fromTimestamp,Pageable pageable);