变体类型
编辑变体类型
编辑Elasticsearch API 拥有许多变体类型:查询、聚合、字段映射、分析器等等。在如此庞大的集合中找到正确的类名可能具有挑战性。
Java API 客户端构建器简化了这一过程:变体类型的构建器(例如 Query
)为每个可用实现提供了方法。我们在上面已经看到了 intervals
(一种查询)和 allOf
、match
和 anyOf
(各种类型的 intervals)的实际应用。
这是因为 Java API 客户端中的变体对象是“标记联合”的实现:它们包含其所持变体的标识符(或标记)以及该变体的值。例如,Query
对象可以包含带有标记 intervals
的 IntervalsQuery
,带有标记 term
的 TermQuery
,等等。这种方法允许编写流畅的代码,您可以在其中利用 IDE 代码补全功能来指导您构建和遍历复杂的嵌套结构。
变体构建器为每个可用实现都有 setter 方法。它们使用与常规属性相同的约定,并接受构建器 lambda 表达式和变体实际类型的现成对象。以下是一个构建 term 查询的示例。
Query query = new Query.Builder() .term(t -> t .field("name") .value(v -> v.stringValue("foo")) ) .build();
变体对象为每个可用实现都有 getter 方法。这些方法检查对象是否确实包含该类型的变体,并将值向下转换为正确的类型。否则,它们会抛出 IllegalStateException
。这种方法允许编写流畅的代码来遍历变体。
assertEquals("foo", query.term().value().stringValue());
变体对象还提供有关其当前所持变体类型的信息。
- 使用每个变体类型的
is
方法:isTerm()
、isIntervals()
、isFuzzy()
等。 - 使用定义所有变体类型的嵌套
Kind
枚举。
然后,此信息可用于在检查其实际类型后向下导航到特定变体。
if (query.isTerm()) { doSomething(query.term()); } switch(query._kind()) { case Term: doSomething(query.term()); break; case Intervals: doSomething(query.intervals()); break; default: doSomething(query._kind(), query._get()); }
Elasticsearch 插件提供的自定义扩展
编辑Elasticsearch 接受可以扩展多种类型的可用变体的插件。这包括查询、聚合、文本分析器和分词器、摄取处理器等。
这些类型的 Java API 客户端类除了内置类型外,还接受 _custom
变体。这允许您通过在请求中提供任意 JSON 来使用这些插件定义的扩展,以及接收插件在响应中生成的任意 JSON。
在下面的示例中,我们使用了一个假设的插件,该插件添加了一个 sphere-distance
聚合,该聚合根据文档包含的 3D 坐标与其参考位置的距离对文档进行分组。
要创建自定义聚合,请使用 _custom()
聚合类型并提供其标识符(由插件定义)和参数。参数可以是任何可以序列化为 JSON 的对象或值。在下面的示例中,我们使用了一个简单的映射。
Map<String, Object> params = new HashMap<>(); params.put("interval", 10); params.put("scale", "log"); params.put("origin", new Double[]{145.0, 12.5, 1649.0}); SearchRequest request = SearchRequest.of(r -> r .index("stars") .aggregations("neighbors", agg -> agg ._custom("sphere-distance", params) ) );
自定义变体的结果以 JsonData
对象表示的原始 JSON 形式返回。然后,您可以遍历 JSON 树以获取数据。由于这并不总是很方便,您还可以定义表示该 JSON 数据的类,并从原始 JSON 中反序列化它们。
遍历 JSON 树
SearchResponse<Void> response = esClient.search(request, Void.class); JsonData neighbors = response .aggregations().get("neighbors") ._custom(); JsonArray buckets = neighbors.toJson() .asJsonObject() .getJsonArray("buckets"); for (JsonValue item : buckets) { JsonObject bucket = item.asJsonObject(); double key = bucket.getJsonNumber("key").doubleValue(); double docCount = bucket.getJsonNumber("doc_count").longValue(); doSomething(key, docCount); }
如果您只对聚合结果感兴趣,而不是搜索命中,请使用 |
|
获取 |
|
遍历 JSON 树以提取结果数据。 |
使用表示自定义聚合结果的类
SearchResponse<Void> response = esClient.search(request, Void.class); SphereDistanceAggregate neighbors = response .aggregations().get("neighbors") ._custom() .to(SphereDistanceAggregate.class); for (Bucket bucket : neighbors.buckets()) { doSomething(bucket.key(), bucket.docCount()); }
其中 SphereDistanceAggregate
可以定义如下:
public static class SphereDistanceAggregate { private final List<Bucket> buckets; @JsonCreator public SphereDistanceAggregate( @JsonProperty("buckets") List<Bucket> buckets ) { this.buckets = buckets; } public List<Bucket> buckets() { return buckets; }; } public static class Bucket { private final double key; private final double docCount; @JsonCreator public Bucket( @JsonProperty("key") double key, @JsonProperty("doc_count") double docCount) { this.key = key; this.docCount = docCount; } public double key() { return key; } public double docCount() { return docCount; } }
上面示例的源代码可以在 Java API 客户端测试 中找到。