Java Spring elasticsearch "Failed to derive xcontent" 与@Query

Java Spring elasticsearch "Failed to derive xcontent" with @Query

我的一个 elasticsearch 存储库中有一个自定义 @Query,因为自动生成方法没有使用匹配(而是使用 query_string 和 analyze_wildcard),因此不适用于例如空格.这个查询对我来说看起来很简单,所以我认为自己编写它不会有问题。

@Query("\"bool\": { " +
        "   \"filter\": [ " +
        "    {  " +
        "       \"term\": { " +
        "          \"userId.keyword\": \"?0\" " +
        "        } " +
        "    }, " +
        "    {" +
        "       \"match\": { " +
        "          \"content\": \"?1\" " +
        "       }" +
        "     } " +
        "   ] " +
        "  }")
Page<SearchablePageHistory> findAllByUserIdAndContentLike(String userId, String content, Pageable pageable);

但是当我尝试执行该函数时出现以下错误:

org.elasticsearch.ElasticsearchStatusException: Elasticsearch exception [type=x_content_parse_exception, reason=Failed to derive xcontent]
    at org.elasticsearch.rest.BytesRestResponse.errorFromXContent(BytesRestResponse.java:177) ~[elasticsearch-7.6.2.jar:7.6.2]
    at org.elasticsearch.client.RestHighLevelClient.parseEntity(RestHighLevelClient.java:1793) ~[elasticsearch-rest-high-level-client-7.6.2.jar:7.6.2]
    at org.elasticsearch.client.RestHighLevelClient.parseResponseException(RestHighLevelClient.java:1770) ~[elasticsearch-rest-high-level-client-7.6.2.jar:7.6.2]
    at org.elasticsearch.client.RestHighLevelClient.internalPerformRequest(RestHighLevelClient.java:1527) ~[elasticsearch-rest-high-level-client-7.6.2.jar:7.6.2]
    at org.elasticsearch.client.RestHighLevelClient.performRequest(RestHighLevelClient.java:1484) ~[elasticsearch-rest-high-level-client-7.6.2.jar:7.6.2]
    at org.elasticsearch.client.RestHighLevelClient.performRequestAndParseEntity(RestHighLevelClient.java:1454) ~[elasticsearch-rest-high-level-client-7.6.2.jar:7.6.2]
    at org.elasticsearch.client.RestHighLevelClient.search(RestHighLevelClient.java:970) ~[elasticsearch-rest-high-level-client-7.6.2.jar:7.6.2]
    at org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate.lambda$search(ElasticsearchRestTemplate.java:265) ~[spring-data-elasticsearch-4.0.0.RELEASE.jar:4.0.0.RELEASE]
    at org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate.execute(ElasticsearchRestTemplate.java:351) ~[spring-data-elasticsearch-4.0.0.RELEASE.jar:4.0.0.RELEASE]
    at org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate.search(ElasticsearchRestTemplate.java:265) ~[spring-data-elasticsearch-4.0.0.RELEASE.jar:4.0.0.RELEASE]
    at org.springframework.data.elasticsearch.repository.query.ElasticsearchStringQuery.execute(ElasticsearchStringQuery.java:89) ~[spring-data-elasticsearch-4.0.0.RELEASE.jar:4.0.0.RELEASE]
    at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor$QueryMethodInvoker.invoke(QueryExecutorMethodInterceptor.java:195) ~[spring-data-commons-2.3.0.RELEASE.jar:2.3.0.RELEASE]
    at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.doInvoke(QueryExecutorMethodInterceptor.java:152) ~[spring-data-commons-2.3.0.RELEASE.jar:2.3.0.RELEASE]
    at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.invoke(QueryExecutorMethodInterceptor.java:130) ~[spring-data-commons-2.3.0.RELEASE.jar:2.3.0.RELEASE]
    Suppressed: org.elasticsearch.client.ResponseException: method [POST], host [http://localhost:9200], URI [/history/_search?pre_filter_shard_size=128&typed_keys=true&max_concurrent_shard_requests=5&ignore_unavailable=false&expand_wildcards=open&allow_no_indices=true&ignore_throttled=true&search_type=dfs_query_then_fetch&batched_reduce_size=512&ccs_minimize_roundtrips=true], status line [HTTP/1.1 400 Bad Request]
{"error":{"root_cause":[{"type":"x_content_parse_exception","reason":"Failed to derive xcontent"}],"type":"x_content_parse_exception","reason":"Failed to derive xcontent"},"status":400}
        at org.elasticsearch.client.RestClient.convertResponse(RestClient.java:283) ~[elasticsearch-rest-client-7.6.2.jar:7.6.2]
        at org.elasticsearch.client.RestClient.performRequest(RestClient.java:261) ~[elasticsearch-rest-client-7.6.2.jar:7.6.2]
        at org.elasticsearch.client.RestClient.performRequest(RestClient.java:235) ~[elasticsearch-rest-client-7.6.2.jar:7.6.2]
        at org.elasticsearch.client.RestHighLevelClient.internalPerformRequest(RestHighLevelClient.java:1514) ~[elasticsearch-rest-high-level-client-7.6.2.jar:7.6.2]
        ... 124 common frames omitted

使用 debuggin,我在 org.elasticsearch.client.RestClient.java:244 中追踪了发送到 elasticsearch 的原始 Rest-Request,发现这是发送到服务器的负载:

{"from":0,"size":10,"query":{"wrapper":{"query":"ImJvb2wiOiB7ICAgICJmaWx0ZXIiOiBbICAgICB7ICAgICAgICJ0ZXJtIjogeyAgICAgICAidXNlcklkLmtleXdvcmQiOiAiMzFjMjA5NTktNjg5Zi00YjI4LWExNzctNmQ3ZTQ2YTBhYzMwIiAgICAgIH0gICAgIH0sICAgeyJtYXRjaCI6IHsgICAgImNvbnRlbnQiOiAidGVzdHNzIiAgIH19ICAgIF0gICB9"}},"version":true,"sort":[{"id":{"order":"desc"}}]}

有了这个有效负载,错误并不令人惊讶,但我不知道为什么会有这种奇怪的含糊不清的字符。我怀疑那应该是我未正确使用的自定义查询。我通过调试这一行得到了这个有效负载:

httpResponse = client.execute(context.requestProducer, context.asyncResponseConsumer, context.context, null).get();

然后执行:

StandardCharsets.UTF_8.decode(((NByteArrayEntity) ((HttpPost) ((HttpAsyncMethods.RequestProducerImpl) context.requestProducer).request).entity).buf).toString()

这些是我在存储库中使用的导入和类名-Class:

import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.elasticsearch.annotations.Query;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;

import java.util.stream.Stream;

public interface SearchablePageHistoryRepository extends ElasticsearchRepository<SearchablePageHistory, Integer> {
    Page<SearchablePageHistory> findAllByUserId(String userId, Pageable pageable);

    @Query("\"bool\": { " +
        "   \"filter\": [ " +
        "    {  " +
        "       \"term\": { " +
        "          \"userId.keyword\": \"?0\" " +
        "        } " +
        "    }, " +
        "    {" +
        "       \"match\": { " +
        "          \"content\": \"?1\" " +
        "       }" +
        "     } " +
        "   ] " +
        "  }")
    Page<SearchablePageHistory> findAllByUserIdAndContentLike(String userId, String content, Pageable pageable);
}

我不使用@Query 的所有其他查询都可以正常工作,没有问题。我不知道我做错了什么,因为我的示例与文档中给出的示例非常相似:https://docs.spring.io/spring-data/elasticsearch/docs/current/reference/html/#elasticsearch.query-methods.at-query

难看,我发现了我的错误 -> 仍然会留下这个 post 以防其他人偶然发现同样的问题,因为在我看来错误消息不是很有帮助。

我只是忘记了查询外部的括号:

改变这个:

@Query("\"bool\": { " +
        "   \"filter\": [ " +
        "    {  " +
        "       \"term\": { " +
        "          \"userId.keyword\": \"?0\" " +
        "        } " +
        "    }, " +
        "    {" +
        "       \"match\": { " +
        "          \"content\": \"?1\" " +
        "       }" +
        "     } " +
        "   ] " +
        "  }")
    Page<SearchablePageHistory> findAllByUserIdAndContentLike(String userId, String content, Pageable pageable);

对此:

    @Query("{\"bool\": { " +
        "   \"filter\": [ " +
        "    {  " +
        "       \"term\": { " +
        "          \"userId.keyword\": \"?0\" " +
        "        } " +
        "    }, " +
        "    {" +
        "       \"match\": { " +
        "          \"content\": \"?1\" " +
        "       }" +
        "     } " +
        "   ] " +
        "  }}")
Page<SearchablePageHistory> findAllByUserIdAndContentLike(String userId, String content, Pageable pageable);

解决了问题。

加法:

"ImJvb2wiOiB7ICAgICJmaWx0ZXIiOiBbICAgICB7ICAgICAgICJ0ZXJtIjogeyAgICAgICAidXNlcklkLmtleXdvcmQiOiAiMzFjMjA5NTktNjg5Zi00YjI4LWExNzctNmQ3ZTQ2YTBhYzMwIiAgICAgIH0gICAgIH0sICAgeyJtYXRjaCI6IHsgICAgImNvbnRlbnQiOiAidGVzdHNzIiAgIH19ICAgIF0gICB9" 

是一个包装查询,这是一个base64编码的字符串,包含

""bool": {    "filter": [     {       "term": {       "userId.keyword": "31c20959-689f-4b28-a177-6d7e46a0ac30"      }     },   {"match": {    "content": "testss"   }}    ]   }"

有类似的问题,实际上是缺少括号