1. 简介
如果你曾经使用过 Elasticsearch,你一定知道通过其 RESTful 搜索 API 构建查询是一件繁琐且容易出错的事情。
本文我们将介绍 Jest,一个基于 HTTP 的 Elasticsearch Java 客户端。虽然 Elasticsearch 提供了官方的 Java 客户端,但 Jest 提供了更流畅的 API 和更简洁的接口。
2. Maven 依赖
首先,我们需要在 POM 中引入 Jest 库:
<dependency>
<groupId>io.searchbox</groupId>
<artifactId>jest</artifactId>
<version>6.3.1</version>
</dependency>
Jest 的版本号与 Elasticsearch 主版本保持同步,这有助于确保客户端与服务端的兼容性。
引入 Jest 后,Elasticsearch 相关依赖会自动作为传递依赖被引入。
3. 使用 Jest 客户端
本节将介绍如何使用 Jest 客户端执行常见的 Elasticsearch 操作。
使用 Jest 时,我们通过 JestClientFactory 创建一个 JestClient 实例。⚠️ 这些对象创建代价较高,但线程安全,建议在应用中使用单例模式共享一个实例:
public JestClient jestClient() {
JestClientFactory factory = new JestClientFactory();
factory.setHttpClientConfig(
new HttpClientConfig.Builder("http://localhost:9200")
.multiThreaded(true)
.defaultMaxTotalConnectionPerRoute(2)
.maxTotalConnection(10)
.build());
return factory.getObject();
}
这段代码创建了一个连接到本地 Elasticsearch 实例的 Jest 客户端。虽然这是最简单的连接方式,但 Jest 同样支持代理、SSL、认证甚至节点发现。
JestClient 接口非常简洁,主要方法是 execute,它接受一个 Action 接口的实现。Jest 提供了多个构建器类用于创建不同类型的 Elasticsearch 操作。
所有 Jest 调用的结果都是 JestResult 实例。可以通过 isSucceeded 方法判断是否成功,失败时可通过 getErrorMessage 获取详细信息:
JestResult jestResult = jestClient.execute(new Delete.Builder("1").index("employees").build());
if (jestResult.isSucceeded()) {
System.out.println("Success!");
}
else {
System.out.println("Error: " + jestResult.getErrorMessage());
}
3.1. 管理索引
检查索引是否存在,使用 IndicesExists 操作:
JestResult result = jestClient.execute(new IndicesExists.Builder("employees").build())
创建索引使用 CreateIndex:
jestClient.execute(new CreateIndex.Builder("employees").build());
可以自定义索引设置:
Map<String, Object> settings = new HashMap<>();
settings.put("number_of_shards", 11);
settings.put("number_of_replicas", 2);
jestClient.execute(new CreateIndex.Builder("employees").settings(settings).build());
添加或删除别名使用 ModifyAliases:
jestClient.execute(new ModifyAliases.Builder(
new AddAliasMapping.Builder("employees", "e").build()).build());
jestClient.execute(new ModifyAliases.Builder(
new RemoveAliasMapping.Builder("employees", "e").build()).build());
3.2. 创建文档
使用 Index 操作可以轻松地创建或更新文档。⚠️ Elasticsearch 中的文档本质就是 JSON 数据,Jest 支持多种方式传入 JSON 数据。
假设我们有如下 Employee 文档:
{
"name": "Michael Pratt",
"title": "Java Developer",
"skills": ["java", "spring", "elasticsearch"],
"yearsOfService": 2
}
我们可以使用字符串、Map 或 POJO 来表示该文档:
✅ 使用 Jackson 构建 JSON 字符串:
ObjectMapper mapper = new ObjectMapper();
JsonNode employeeJsonNode = mapper.createObjectNode()
.put("name", "Michael Pratt")
.put("title", "Java Developer")
.put("yearsOfService", 2)
.set("skills", mapper.createArrayNode()
.add("java")
.add("spring")
.add("elasticsearch"));
jestClient.execute(new Index.Builder(employeeJsonNode.toString()).index("employees").build());
✅ 使用 Map:
Map<String, Object> employeeHashMap = new LinkedHashMap<>();
employeeHashMap.put("name", "Michael Pratt");
employeeHashMap.put("title", "Java Developer");
employeeHashMap.put("yearsOfService", 2);
employeeHashMap.put("skills", Arrays.asList("java", "spring", "elasticsearch"));
jestClient.execute(new Index.Builder(employeeHashMap).index("employees").build());
✅ 使用 POJO:
Employee employee = new Employee();
employee.setName("Michael Pratt");
employee.setTitle("Java Developer");
employee.setYearsOfService(2);
employee.setSkills(Arrays.asList("java", "spring", "elasticsearch"));
jestClient.execute(new Index.Builder(employee).index("employees").build());
3.3. 读取文档
有两种主要方式读取文档:
- 通过文档 ID 使用 Get 操作直接读取
Employee getResult = jestClient.execute(new Get.Builder("employees", "1").build())
.getSourceAsObject(Employee.class);
- 使用 Search 操作进行搜索
⚠️ Jest 支持完整的 Elasticsearch 查询 DSL,查询同样是通过 JSON 文档表达:
String search = "{" +
" \"query\": {" +
" \"bool\": {" +
" \"must\": [" +
" { \"match\": { \"name\": \"Michael Pratt\" }}" +
" ]" +
" }" +
" }" +
"}";
jestClient.execute(new Search.Builder(search).build());
获取搜索结果时,可以使用 getSource 方法,也可以使用 Hit 类获取更多元信息:
List<SearchResult.Hit<Employee, Void>> searchResults =
jestClient.execute(new Search.Builder(search).build())
.getHits(Employee.class);
searchResults.forEach(hit -> {
System.out.println(String.format("Document %s has score %s", hit.id, hit.score));
});
3.4. 更新文档
使用 Update 操作更新文档:
employee.setYearOfService(3);
jestClient.execute(new Update.Builder(employee).index("employees").id("1").build());
支持与 Index 操作相同的 JSON 表达方式。
3.5. 删除文档
使用 Delete 操作删除文档:
jestClient.execute(new Delete.Builder("17")
.index("employees")
.build());
4. 批量操作
Jest 支持批量操作(Bulk),可以将多个操作合并为一次请求发送,节省时间和带宽:
jestClient.execute(new Bulk.Builder()
.defaultIndex("employees")
.addAction(new Index.Builder(employeeObject1).build())
.addAction(new Index.Builder(employeeObject2).build())
.addAction(new Delete.Builder("17").build())
.build());
5. 异步操作
Jest 支持异步操作,可以使用非阻塞 I/O 执行上述所有操作。
调用异步方法需使用 executeAsync 并传入一个 JestResultHandler:
jestClient.executeAsync(
new Index.Builder(employeeObject1).build(),
new JestResultHandler<JestResult>() {
@Override public void completed(JestResult result) {
// handle result
}
@Override public void failed(Exception ex) {
// handle exception
}
});
6. 总结
本文简要介绍了 Jest,一个用于 Elasticsearch 的 RESTful Java 客户端。
虽然我们只展示了其部分功能,但很明显 Jest 是一个功能强大的客户端。✅ 其流畅的构建器类和 RESTful 接口使其易于上手,同时对 Elasticsearch 接口的完整支持也使其成为原生客户端的一个有力替代方案。
所有示例代码都可以在 GitHub 上找到。