这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos
在REST API文档中,数量众多API是按照特性(feature)来分组的,如下图
在ES的Java库Java API Client中,上图中的各种feature被称为namespace
在ES的Java库Java API Client中,与REST API对应的的类和接口都在统一的包名co.elastic.clients.elasticsearch之下,然后再通过下一级package进行分类,这个分类与上图的feature相对应,例如索引相关的,在REST API中的feature是Index APIs,那么在Java API Client中,完整的package就是co.elastic.clients.elasticsearch.indices,这里面有索引操作所需的请求、响应、服务等各种类,如下图
每一个namespace(也就是REST API中的feature),都有自己的client,例如索引相关的操作都有索引专用的client类负责,实例代码如下,client.indices()返回的是ElasticsearchIndicesClient对象,这是索引操作专用的实例
ElasticsearchClient client = …
client.indices().create(c -> c.index("products"));
展开上述代码的indices()方法,看看其内部实现,如下所示,每次调用indices方法,都会创建一个ElasticsearchIndicesClient对象,对于其他namespace,例如ingest、license亦是如此,都会创建新的实例
看到这里,经验丰富的您应该发现了问题:在大量并发频繁执行各种namespace操作时,会创建大量client对象,这样会影响系统性能吗?
es预判了咱们的预判,如下图,官方说这是轻量级对象(very lightweight),所以,理论上可以放心创建,不必担心其对系统造成的压力
尽管每个namespace都有自己的client,但也有例外,就是search和document,它们的代码不在search或者document这样的package下面,而是在core下面,而且可以通过ElasticsearchClient来操作,如下图
对于单值属性,我们在使用的时候判断是否为空是个常规操作,这样是为了避免直接使用时可能出现的空指针异常
而对于集合,Java API Client 已经确保了API返回的集合非空,我们只需要检查集合中是否有内容,而不必担心集合自身是否等于null的问题,官方给出的演示代码如下
NodeStatistics stats = NodeStatistics.of(b -> b
.total(1)
.failed(0)
.successful(1)
);
// The failures
list was not provided.
// - it's not null
assertNotNull(stats.failures());
出于好奇,去看看NodeStatistics源码,构造方法如下,failures来自ApiTypeHelper.unmodifiable
private NodeStatistics(Builder builder) {this.failures = ApiTypeHelper.unmodifiable(builder.failures);
this.total = ApiTypeHelper.requireNonNull(builder.total, this, "total");
this.successful = ApiTypeHelper.requireNonNull(builder.successful, this, "successful");
this.failed = ApiTypeHelper.requireNonNull(builder.failed, this, "failed");
}
再去看ApiTypeHelper.unmodifiable,如下,已确保了failures不为空
public static <T> List<T> unmodifiable(@Nullable List<T> list) {
if (list == null) {
return undefinedList();
}
if (list == UNDEFINED_LIST) {
return list;
}
return Collections.unmodifiableList(list);
}
因此,再使用API返回的集合时,集合对象自身始终非空
variant type是Java API Client中常见的对象类型,这个该如何翻译呢,个人觉得是不确定类型的意思,不专业,期待您的指正
举个例子,查询是最常见的操作了,下面列举三种查询,第一个是普通的不分词查询
{
"query":{"term":{ "interests":"youyong"}}
}
分词查询
{
"query":{"match":{"interests": "changge"}}
}
以及复杂的全文本查询
{
"query": {
"intervals" : {
"my_text" : {
"all_of" : {
"ordered" : false,
"intervals" : [
{
"match" : {
"query" : "my favorite books",
"max_gaps" : 0,
"ordered" : true
}
},
{
"any_of" : {
"intervals" : [
{ "match" : { "query" : "java tutorials" } },
{ "match" : { "query" : "cold porridge" } }
]
}
}
]
}
}
}
}
}
对查询来说,在Java API Client中,有个Query对象代表了查询行为,这就是个典型的variant type,至于对应的真实query是哪种,可以在builder时指定,例如下面指定了类型是term
Query query = new Query.Builder()
.term(t -> t
.field("name")
.value(v -> v.stringValue("foo"))
)
.build();
上述query有对应的方法返回其值,例如上面的value可以这样获取
query.term().value().stringValue()
如果在设置的时候,并非用stringValue方法,而是其他类型,那么上面的代码在获取String类型的值时会抛出IllegalStateException异常
variant type配有对应的isXXX方法返回其是否属于某个类型,例如Query就有query.isTerm()表示自己是不是term查询
还可以用_kind()返回当前类型,下面是示例
switch(query._kind()) {
case Term:
doSomething(query.term());
break;
case Intervals:
doSomething(query.intervals());
break;
default:
doSomething(query._kind(), query._get());
}
可见有了variant type,在 queries, aggregations, field mappings, analyzers等多种场景下,我们不需要使用各种具体的类,只要用最抽象的variant type,再配置builder pattern即可,这对服务提供者和服务消费者都是有效的简化
下面是kibana页面上,用JSON创建索引的操作截图
如果要在代码中实现上述效果,该如何做呢?一层一层的创建mapping、proterties、field对象?那可真是麻烦…
在Java API Client中,可以通过json字符串反序列化为API对象,首先,将上述JSON放入名为some-index.json的文件中,然后执行以下代码,即可用json文件创建req对象
InputStream input = this.getClass()
.getResourceAsStream("some-index.json");
CreateIndexRequest req = CreateIndexRequest.of(b -> b
.index("some-index")
.withJson(input)
);
boolean created = client.indices().create(req).acknowledged();
再来段更复杂的,一个API对象,既通过JSON反序列化生成,同时又能调用对象的方法设置一些属性
Reader queryJson = new StringReader(
"{" +
" \"query\": {" +
" \"range\": {" +
" \"@timestamp\": {" +
" \"gt\": \"now-1w\"" +
" }" +
" }" +
" }," +
" \"size\": 100" +
"}");
Reader aggregationJson = new StringReader(
"{" +
" \"size\": 0, " +
" \"aggregations\": {" +
" \"hours\": {" +
" \"date_histogram\": {" +
" \"field\": \"@timestamp\"," +
" \"interval\": \"hour\"" +
" }," +
" \"aggregations\": {" +
" \"max-cpu\": {" +
" \"max\": {" +
" \"field\": \"host.cpu.usage\"" +
" }" +
" }" +
" }" +
" }" +
" }" +
"}");
SearchRequest aggRequest = SearchRequest.of(b -> b
.withJson(queryJson)
.withJson(aggregationJson)
.ignoreUnavailable(true)
);
Map
.search(aggRequest, Void.class)
.aggregations();
手机扫一扫
移动阅读更方便
你可能感兴趣的文章