在Elasticsearch7.15版本之后,Elasticsearch官方将它的高级客户端RestHighLevelClient标记为弃用状态。同时推出了全新的Java API客户端Elasticsearch Java API Client,该客户端也将在Elasticsearch8.0及以后版本中成为官方推荐使用的客户端。

Elasticsearch Java API Client 支持除 Vector tile search API 和 Find structure API 之外的所有 Elasticsearch API。且支持所有API数据类型,并且不再有原始JsonValue属性。它是针对Elasticsearch8.0及之后版本的客户端,目前Elasticsearch已经更新至8.0.1,所以我们需要学习新的Elasticsearch Java API Client的使用方法。

环境要求

首先,你的项目需要支持Java8或以上,并且你的项目需要有一个Json对象映射库,比如Jackson等,本文章中使用Jackson作为示例。

安装依赖

在Gradle项目中安装

1
2
3
4
dependencies {
implementation 'co.elastic.clients:elasticsearch-java:8.0.1'
implementation 'com.fasterxml.jackson.core:jackson-databind:2.12.3'
}

在Maven项目中安装

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<project>

<dependencies>
<dependency>
<groupId>co.elastic.clients</groupId>
<artifactId>elasticsearch-java</artifactId>
<version>8.0.1</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.12.3</version>
</dependency>
</dependencies>
</project>

连接

1
2
3
4
5
6
7
8
// 创建低级客户端
RestClient restClient = RestClient.builder(new HttpHost("localhost", 9200)).build();

// 使用Jackson映射器创建传输层
ElasticsearchTransport transport = new RestClientTransport(restClient, new JacksonJsonpMapper());

// 创建API客户端
ElasticsearchClient client = new ElasticsearchClient(transport);

测试查询请求

注意,需要ES内有相应的数据才可以查到。如没有数据可供测试可以直接跳过本项。

1
2
3
4
5
6
7
8
9
10
11
12
SearchResponse<Product> search = client.search(s -> s
.index("products")
.query(q -> q
.term(t -> t
.field("name")
.value(v -> v.stringValue("testname"))
)),
Product.class);

for (Hit<Product> hit: search.hits().hits()) {
processProduct(hit.source());
}

索引Index的基本操作

创建索引

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 创建连接
RestClient restClient = RestClient.builder(
new HttpHost("localhost", 9200)).build();
ElasticsearchTransport transport = new RestClientTransport(
restClient, new JacksonJsonpMapper());
ElasticsearchClient client = new ElasticsearchClient(transport);

// 创建索引
CreateIndexResponse createIndexResponse = client.indices().create(c -> c.index("newapi"));
// 打印结果
System.out.println(createIndexResponse.acknowledged());

// 关闭连接
transport.close();
restClient.close();

查询索引

1
2
3
4
5
6
7
8
9
10
11
12
// Create the low-level client
RestClient restClient = RestClient.builder(
new HttpHost("localhost", 9200)).build();
// Create the transport with a Jackson mapper
ElasticsearchTransport transport = new RestClientTransport(
restClient, new JacksonJsonpMapper());
// And create the API client
ElasticsearchClient client = new ElasticsearchClient(transport);
GetIndexResponse createIndexResponse = client.indices().get(e->e.index("newapi"));
System.out.println(String.join(",", createIndexResponse.result().keySet()));
transport.close();
restClient.close();

删除索引

1
2
3
4
5
6
7
8
9
10
11
12
// Create the low-level client
RestClient restClient = RestClient.builder(
new HttpHost("localhost", 9200)).build();
// Create the transport with a Jackson mapper
ElasticsearchTransport transport = new RestClientTransport(
restClient, new JacksonJsonpMapper());
// And create the API client
ElasticsearchClient client = new ElasticsearchClient(transport);
DeleteIndexResponse deleteIndexResponse = client.indices().delete(e->e.index("newapi"));
System.out.println(deleteIndexResponse.acknowledged());
transport.close();
restClient.close();

文档Doc的基本操作

创建文档Doc

1
2
3
4
5
6
7
8
9
10
11
// 创建一个需要保存至ES的对象
Test test = new Test();
test.setName("添加测试");
test.setSex("男");
test.setAge(24);

// 构建一个创建Doc的请求
CreateResponse createResponse = client.create(e->e.index("newapi").id("1003").document(test));

// 打印请求结果
System.out.println(createResponse.result());

其中,index为文档Doc所属索引的名字,id为该文档的id,document参数现在可以直接传入Java对象了。

修改文档Doc

1
2
3
4
5
6
7
8
9
// 构建需要修改的内容,这里使用了Map
Map<String, Object> map = new HashMap<>();
map.put("age", 35);

// 构建修改文档的请求
UpdateResponse<Test> response = client.update(e -> e.index("newapi").id("1003").doc(map), Test.class);

// 打印请求结果
System.out.println(response.result());

查询文档Doc

1
2
3
4
5
// 构建查询请求
GetResponse<Test> response = client.get(e -> e.index("newapi").id("1003"), Test.class);

// 打印查询结果
System.out.println(response.source().toString());

删除文档Doc

1
2
3
4
5
// 构建删除文档请求
DeleteResponse response = client.delete(e -> e.index("newapi").id("1001"));

// 打印请求结果
System.out.println(response.result());

如何迁移

如何从高级客户端High Level Rest Client迁移至新版客户端Elasticsearch Java API Client?

根据官方给出的答案是无法平滑的迁移,不过新版客户端和旧版高级客户端是可以共存的,并且没有操作开销。所以在你的项目中可以逐步的从旧版客户端迁移至新版客户端。

并且,官方还提供了使High Level Rest Client和Elasticsearch Java API Client使用相同的传输通道的方案,他可以使两个客户端共享相同的Low Level Rest Client,管理所有连接,循环策略的网络层以及节点嗅探等工作。

以下代码展示了如何使用相同的HTTP客户端同时初始化新客户端和旧客户端:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 创建低级客户端(新版客户端内容)
RestClientBuilder httpClientBuilder = RestClient.builder(
new HttpHost("localhost", 9200)
);

// 创建旧版高级客户端RestHighLevelClient
RestHighLevelClient hlrc = new RestHighLevelClient(httpClientBuilder);

// 使用相同的低级客户端创建新的Java客户端
ElasticsearchTransport transport = new RestClientTransport(
hlrc.getLowLevelClient(),
new JacksonJsonpMapper()
);

ElasticsearchClient esClient = new ElasticsearchClient(transport);

// 新旧客户端共享相同的http客户端