变体类型
编辑变体类型编辑
Elasticsearch API 拥有许多变体类型:查询、聚合、字段映射、分析器等等。在如此庞大的集合中找到正确的类名可能很困难。
Java API 客户端构建器简化了这一过程:变体类型的构建器,例如 Query
,为每个可用实现提供方法。我们在上面的 intervals
(一种查询)和 allOf
、match
和 anyOf
(各种类型的间隔)中看到了这一点。
这是因为 Java API 客户端中的变体对象是“标记联合”的实现:它们包含它们所持有的变体的标识符(或标记)以及该变体的值。例如,一个 Query
对象可以包含一个带有标记 intervals
的 IntervalsQuery
,一个带有标记 term
的 TermQuery
,等等。这种方法允许编写流畅的代码,您可以在其中让 IDE 代码补全功能指导您构建和导航复杂的嵌套结构。
变体构建器为每个可用实现提供 setter 方法。它们使用与常规属性相同的约定,并接受构建器 lambda 表达式和变体实际类型的现成对象。以下是一个构建术语查询的示例。
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 客户端测试 中找到。