gpt4 book ai didi

java - 如何将带有聚合的 Elasticsearch JSON 字符串响应转换为 Elasticsearch SearchResponse 对象

转载 作者:塔克拉玛干 更新时间:2023-11-02 08:33:06 27 4
gpt4 key购买 nike

我想将一个 json 字符串序列化为一个 Elasticsearch SearchResponse 对象。如果 json 字符串不包含聚合,它工作正常。

如果 json 字符串包含聚合,则 XContentParser 抛出一个ParsingException[无法解析键控为 [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 注册聚合,但我不知道如何注册。

最佳答案

背景:
我根据我为编写 Java 单元测试 而创建 SearchResponse 对象的经验写下这个答案。目标是从 Elasticsearch 查询中获取任何 JSON 响应对象,将其编码到 SearchResponse 对象中,并对创建可消费输出的业务逻辑进行单元测试。

我们使用 Elasticsearch 6.7,高级 rest 客户端,并使用 Elastic 的 POJO 解析 SearchResponse(与仅执行 .toString() 并使用 GSON 或 Jackson 对其进行操作相比)。

解法说明:
Elasticsearch 的高级休息客户端一般解析来自低级休息客户端的结果。 SearchRequest 的响应 JSON 在 RestHighLevelClient 中转换为 SearchResponse 对象在 search 方法的第 129 行。此方法调用 performRequestAndParseEntity在第 1401 行,它接受 entityParser作为 CheckedFunction<XContentParser, Resp, IOException> .最后,我们可以看到在调用 entityParser 时在第 1401 行,它调用 parseEntity 第 1714 行的方法确定实体的 XContentType 并最终执行解析。值得注意的是,当在第 1726 行创建解析器时 registry 被传递到解析器。此注册表 包含响应字段可能的所有可能的 XContent 值。当 RestHighLevelClientline 288 上构建时,将创建 registry .类型的完整列表,包括聚合类型,列在 line 1748 上.

解决方案:
在阅读了关于此的 Elasticsearch 讨论后,似乎如果您想将来自 Elastic 的 JSON 响应注入(inject)到 SearchResponse 对象中,则有必要创建一个 NamedXContentRegistry 并列出XContents 测试你必须重新创建解析。一个帮助方法来做到这一点,sourced from Elastic's discussion :

public static List<NamedXContentRegistry.Entry> getDefaultNamedXContents() {
Map<String, ContextParser<Object, ? extends Aggregation>> map = new HashMap<>();
map.put(TopHitsAggregationBuilder.NAME, (p, c) -> ParsedTopHits.fromXContent(p, (String) c));
map.put(StringTerms.NAME, (p, c) -> ParsedStringTerms.fromXContent(p, (String) c));
List<NamedXContentRegistry.Entry> entries = map.entrySet().stream()
.map(entry -> new NamedXContentRegistry.Entry(Aggregation.class, new ParseField(entry.getKey()), entry.getValue()))
.collect(Collectors.toList());
return entries;
}

上述代码中的 map 需要具有测试所需的ALL 聚合。不止两个,这里简单说两个。

使用此助手 getNamedXContents() 方法,您现在可以使用以下方法获取 JSON 字符串并将其注入(inject) SearchResponse。 Also sourced from Elastic's Discussion :

public static SearchResponse getSearchResponseFromJson(String jsonResponse){
try {
NamedXContentRegistry registry = new NamedXContentRegistry(getDefaultNamedXContents());
XContentParser parser = JsonXContent.jsonXContent.createParser(registry, jsonResponse);
return SearchResponse.fromXContent(parser);
} catch (IOException e) {
System.out.println("exception " + e);
}catch (Exception e){
System.out.println("exception " + e);
}
return new SearchResponse();
}

应用具有聚合结果的解决方案:
Elasticsearch 需要一个提示来知道将其解析为哪种类型的聚合。将 ?typed_keys 添加到查询时,弹性会提供提示。 Aggregation Type Hints 上的 Elasticsearch 文档中显示了一个示例.

要将 JSON 字符串注入(inject)到 SearchResponse 对象中,必须 (1) 使用上述方法和 (2) 注入(inject)一个带有类型提示的字符串。

主要来源:

  1. https://discuss.elastic.co/t/elasticsearch-json-response-to-searchresponse-object/124394/6
  2. https://github.com/elastic/elasticsearch/blob/master/client/rest-high-level/src/main/java/org/elasticsearch/client/RestHighLevelClient.java
  3. https://github.com/elastic/elasticsearch/blob/master/test/framework/src/main/java/org/elasticsearch/test/InternalAggregationTestCase.java
  4. https://www.elastic.co/guide/en/elasticsearch/reference/current/returning-aggregation-type.html

注意:大约 2015 年有很多文章说这是不可能的。这显然是不正确的。

关于java - 如何将带有聚合的 Elasticsearch JSON 字符串响应转换为 Elasticsearch SearchResponse 对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49798654/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com