任何使用过Elasticsearch的人都知道,使用基于rest的搜索API构建查询多是单调乏味且容易出错的。java
在本教程中,咱们将研究Jest,一个用于Elasticsearch的HTTP Java客户端。Elasticsearch提供了本身原生的Java客户端,然而 Jest提供了更流畅的API和更容易使用的接口。git
咱们须要作的第一件事是导入Jest库到咱们的POM文件中:github
<dependency> <groupId>io.searchbox</groupId> <artifactId>jest</artifactId> <version>6.3.1</version> </dependency>
Jest的版本是遵循Elasticsearch的主版本号的。
这将确保客户端和服务端之间的兼容性。spring
经过包含Jest依赖项,相应的[Elasticsearch库](https://search.maven.org/search?q=g:org.elasticsearch a:elasticsearch)将被包含为传递依赖项。json
在本节中,咱们将研究如何使用Jest client执行Elasticsearch中的常见任务。安全
要使用Jest client,咱们只需使用 JestClientFactory 建立一个 JestClient 对象。这些对象的建立开销很高,并且是线程安全的,所以咱们将建立一个能够在整个应用程序中共享的单例实例:app
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(); }
这里将建立一个Jest client,该客户端链接到本地运行的Elasticsearch。虽然这个链接示例很简单,可是Jest还彻底支持代理、SSL、身份验证,甚至节点发现。异步
JestClient 类是通用类,只有少数公共方法。咱们将使用的一个主要方法是execute,它接受Action接口的一个实例。Jest客户端提供了几个构建器类来帮助建立与Elasticsearch交互的不一样操做。elasticsearch
全部Jest调用的结果都是JestResult的一个实例。 咱们能够经过调用 issucceeded
方法来检查是否成功。对于失败的操做,咱们能够调用GetErrorMessage
方法来获取更多详细信息:maven
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()); }
检查索引是否存在,咱们使用IndicatesExists
操做:
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());
Jest client使用索引操做类索引或建立新文档变得容易。Elasticsearch中的文档只是JSON数据,有多种方法能够将JSON数据传递给Jest client 进行索引。
对于这个例子,让咱们使用一个虚构的雇员文档:
{ "name": "Michael Pratt", "title": "Java Developer", "skills": ["java", "spring", "elasticsearch"], "yearsOfService": 2 }
表示JSON文档的第一种方法是使用Java字符串。虽然咱们能够手动建立JSON字符串,但咱们必须注意正确的格式、大括号和转义引号字符。所以,更容易的方式是使用一个JSON库(如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());
咱们还可使用Java Map 来表示JSON数据,并将其传递给索引操做:
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());
最后,Jest client 能够接受表示要索引的文档的任何POJO。假设咱们有一个Employee类:
public class Employee { String name; String title; List<String> skills; int yearsOfService; }
咱们能够把这个类的一个实例直接传递给Index builder:
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());
使用Jest client从Elasticsearch访问文档有两种主要方法。首先,若是咱们知道文档ID,咱们可使用get操做直接访问它:
jestClient.execute(new Get.Builder("employees", "17").build());
要访问返回的文档,咱们必须调用其中一个getSource
方法。咱们能够将结果做为原始JSON获取,或者将其反序列化为DTO:
Employee getResult = jestClient.execute(new Get.Builder("employees", "1").build()) .getSourceAsObject(Employee.class);
访问文档的其余方法是使用搜索查询,这种方式在Jest中是经过搜索操做实现的。
Jest client 支持所有的 Elasticsearch query DSL。 与索引操做同样,查询被表示为JSON文档,而且有多种执行搜索的方法。
首先,咱们能够传递一个表示搜索查询的JSON字符串。提醒一下,咱们必须确保字符串是正确转义的,而且是有效的JSON:
String search = "{" + " \"query\": {" + " \"bool\": {" + " \"must\": [" + " { \"match\": { \"name\": \"Michael Pratt\" }}" + " ]" + " }" + " }" + "}"; jestClient.execute(new Search.Builder(search).build());
与上面的索引操做同样,咱们可使用Jackson之类的库来构建JSON查询字符串。此外,咱们还可使用原生的Elasticsearch查询操做API。这样作的一个缺点是,咱们的应用程序必须依赖于完整的Elasticsearch库。
咱们可使用 getSource 方法来访问搜索操做中匹配的文档。然而,Jest还提供了Hit类,它包装了匹配的文档并提供有关结果的元数据。 使用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)); });
Jest为更新文档提供了一个简单的Update操做:
employee.setYearOfService(3); jestClient.execute(new Update.Builder(employee).index("employees").id("1").build());
它接受与咱们前面看到的索引操做相同的JSON表示,这使得在两个操做之间共享代码变得很容易。
从索引中删除文档是使用Delete操做完成的。它只须要索引名和文档ID:
jestClient.execute(new Delete.Builder("17") .index("employees") .build());
Jest client 一样支持批量操做。 这意味着咱们能够经过同时发送多个操做来节省时间和带宽。
使用批量操做,咱们能够将任意数量的请求组合成单个调用。咱们甚至能够将不一样类型的请求组合在一块儿:
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());
Jest client 一样支持异步操做。 这意味着咱们可使用非阻塞I/O执行上述任何操做。
要异步调用操做,只需使用客户端的executeAsync
方法:
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 } });
注意,除了(本例中是索引)操做以外,异步流还须要一个JestResultHandler
。当操做完成时,Jest client 将调用该对象。该接口有两个方法—完成和失败—分别容许处理操做的成功或失败。
在本教程中,咱们简要介绍了Jest client,一个用于Elasticsearch的RESTful Java客户端。虽然咱们只介绍了它的一小部分功能,但很明显Jest是一个健壮的Elasticsearch客户端。它的流畅的构建器类和RESTful接口使其易于学习,而且它对Elasticsearch接口的彻底支持使其成为原生客户端的一个有力的替代方案。
和往常同样,本教程中的全部代码示例都在咱们的Github页面上。
译者:huowolf/