我想将一个json字符串序列化为Elasticsearch SearchResponse对象。如果json字符串不包含聚合,它可以正常工作。
如果json字符串包含聚合,XContentParser将抛出ParsingException[Could not parse aggregation keyed as [target_field]
异常。
我用来将json字符串序列化为Elasticsearch SearchResponse对象的代码:
Settings settings = Settings.builder().build();
SearchModule searchModule = new SearchModule(settings, false, new ArrayList<>());
NamedXContentRegistry xContentRegistry = new NamedXContentRegistry(searchModule.getNamedXContents());
JsonXContentParser xContentParser = new JsonXContentParser(xContentRegistry,
new JsonFactory().createParser(json));
SearchResponse response = SearchResponse.fromXContent(xContentParser);
看来我必须将聚合注册到NamedXContentRegistry,但我不知道如何注册。
5条答案
按热度按时间zlwx9yxi1#
背景:
我是根据我创建SearchResponse对象以编写Java单元测试的经验编写这个答案的。目标是从Elasticsearch查询中获取任何JSON响应对象,将其编组到SearchResponse对象中,并对创建可消费输出的业务逻辑进行单元测试。
我们使用Elasticsearch 6.7,高级REST客户端,并使用Elastic的POJO解析SearchResponse(而不是只做一个.toString()并使用GSON或Jackson操作它)。
解决方案说明:
Elasticsearch的高级REST客户端一般解析来自低级REST客户端的结果。SearchRequest的响应JSON在 search 方法第129行的RestHighLevelClient中转换为SearchResponseObject。此方法在第1401行调用 performRequestAndParseEntity,它接受
entityParser
作为CheckedFunction<XContentParser, Resp, IOException>
。最后,我们可以看到,当在第1401行调用entityParser
时,它在第1714行调用parseEntity
方法,该方法确定实体的XContentType并最终执行解析。值得注意的是,当在第1726行创建解析器时,registry
被传递到解析器中。此 registry 包含响应字段可能的所有可能的XContent值。registry 是在第288行构造RestHighLevelClient时创建的。类型的完整列表(包括聚合类型)在第1748行上列出。关于解决方案:
阅读了Elasticsearch关于这方面的讨论,似乎如果你想从Elastic注入一个JSON Response到SearchResponse对象中,需要创建一个NamedXContentRegistry和XContents测试列表,你必须重新创建解析。一个辅助方法sourced from Elastic's discussion可以做到这一点:
上述代码中的Map需要包含测试所需的***所有***聚合。有两个以上,两个在这里为简洁。
使用这个助手getNamedXContents()方法,现在可以使用以下方法获取JSON字符串并将其注入SearchResponse。Also sourced from Elastic's Discussion:
应用具有聚合结果的解决方案:
Elasticsearch需要一个提示来知道将其解析为哪种类型的聚合。当添加**?时,由弹性提供提示。typed_keys到查询。在Aggregation Type Hints上的Elasticsearch文档中显示了一个示例。
要将JSON String注入到SearchResponse**对象中,必须(1)使用上述方法,(2)注入一个带有类型提示的字符串。
主要来源:
注意:2015年前后有很多文章说这是不可能的。这显然是不正确的。
eyh26e7m2#
根据上面的答案,我是这样做的:
我写了一个这样的JSON:
然后我就这样读了
希望它能起作用:)
gg0vcinb3#
你需要在你请求的URL末尾加上
?typed_keys
,比如/cranking/_search?typed_keys
,看看这个参考。你最好像框架源代码一样在
NamedXContentRegistry
中添加更多的parse
注册表。以下是所有注册表项:eagi6jfj4#
我在使用ElasticSearch 7.15时遇到了同样的问题。上面的技术Maven给出的答案确实有助于解决这个问题,但它仍然对我不起作用,因为聚合物没有被识别。我的JSON中的聚合看起来像下面这个:
就像this article中解释的那样,这个问题是由于期望聚合在响应中返回为sterms #my-agg-name,而原始JSON只包含聚合的名称my-agg-name。使用上面的代码并将相关的聚合类型添加到注册表并不起作用。
我发现一个简单的解决方案就是在响应中返回聚合类型。因此,根据the official documentation for the aggregation feature中的示例,将***typed_key***添加到聚合请求中:
将在响应中返回相关的聚合类型,如下所示(histogram #my-agg-name):
现在解析器将识别相关的聚合类型,转换将成功。如果没有,请确保答案中返回的聚合类型包含在注册表Map中。这在ElasticSearch 7.15中很有用。
nimxete25#
让我从另一个Angular 来处理这个问题。你需要
SearchResponse
做什么?在大多数情况下,当您想要测试服务逻辑时,您需要在测试中从例如RestHighLevelClient
搜索方法返回它。如果是这样,为什么不嘲笑
SearchResponse
呢?假设您收到以下ES查询的SearchResponse
:和响应:
现在在服务中,您将其转换为具有bucket count的
Map<String, Long>
:在测试中,而不是像其他答案中建议的那样创建SearchResponse,您可以像这样模拟它: