Java客户端

  在Elasticsearch中,为java提供了2种客户端,一种是REST风格的客户端,另一种是Java API的客户端。

  官网:https://www.elastic.co/guide/en/elasticsearch/client/index.html

  

es java项目搭建 es java客户端_ElasticSearch

REST客户端

  Elasticsearch提供了2种REST客户端,一种是低级客户端,一种是高级客户端。

  Java Low Level REST Client: 官方提供的低级客户端。该客户端通过http来连接Elasticsearch集群。用户在使 用该客户端时需要将请求数据手动拼接成Elasticsearch所需JSON格式进行发送,收到响应时同样也需要将返回 的JSON数据手动封装成对象。虽然麻烦,不过该客户端兼容所有的Elasticsearch版本。

  Java High Level REST Client: 官方提供的高级客户端。该客户端基于低级客户端实现,它提供了很多便捷的 API来解决低级客户端需要手动转换数据格式的问题。

  示例数据

1 POST /house/_bulk
 2 
 3 {"index":{"_index":"house"}}
 4 {"id":"1001","title":"整租 · 南丹大楼 1居室 7500","price":"7500"} 
 5 {"index":{"_index":"house"}} 
 6 {"id":"1002","title":"陆家嘴板块,精装设计一室一厅,可拎包入住诚意租。","price":"8500"} 
 7 {"index":{"_index":"house"}}
 8 {"id":"1003","title":"整租 · 健安坊 1居室 4050","price":"7500"} 
 9 {"index":{"_index":"house"}}
10 {"id":"1004","title":"整租 · 中凯城市之光+视野开阔+景色秀丽+拎包入住","price":"6500"} 
11 {"index":{"_index":"house"}}
12 {"id":"1005","title":"整租 · 南京西路品质小区 21213三轨交汇 配套齐* 拎包入住","price":"6000"} 
13 {"index":{"_index":"house"}}
14 {"id":"1006","title":"祥康里 简约风格 *南户型 拎包入住 看房随时","price":"7000"}

REST低级客户端

  测试elasticsearch版本是:7.6.1

  1、创建工程test-springboot-elasticsearch,引入依赖

1 <!-- elasticsearch -->
2 <dependency>
3     <groupId>org.elasticsearch.client</groupId>
4     <artifactId>elasticsearch-rest-client</artifactId>
5     <version>7.6.1</version>
6 </dependency>

    完整依赖如下:

es java项目搭建 es java客户端_ElasticStack_02

es java项目搭建 es java客户端_ElasticStack_03

1 <?xml version="1.0" encoding="UTF-8"?>
 2 <project xmlns="http://maven.apache.org/POM/4.0.0"
 3          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 4          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
 5     <modelVersion>4.0.0</modelVersion>
 6 
 7     <groupId>com.test</groupId>
 8     <artifactId>test-springboot-es</artifactId>
 9     <version>1.0-SNAPSHOT</version>
10 
11     <parent>
12         <groupId>org.springframework.boot</groupId>
13         <artifactId>spring-boot-starter-parent</artifactId>
14         <version>2.2.5.RELEASE</version>
15     </parent>
16 
17     <properties>
18         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
19         <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
20         <java.version>1.8</java.version>
21     </properties>
22 
23     <dependencies>
24 
25         <dependency>
26             <groupId>org.springframework.boot</groupId>
27             <artifactId>spring-boot-starter-web</artifactId>
28         </dependency>
29 
30         <dependency>
31             <groupId>org.elasticsearch.client</groupId>
32             <artifactId>elasticsearch-rest-client</artifactId>
33             <version>7.6.1</version>
34         </dependency>
35 
36 
37         <dependency>
38             <groupId>org.springframework.boot</groupId>
39             <artifactId>spring-boot-starter-test</artifactId>
40             <scope>test</scope>
41         </dependency>
42 
43     </dependencies>
44 
45 
46     <!-- SpringBoot打包插件,可以将代码打包成一个可执行的jar包 -->
47     <build>
48         <plugins>
49             <plugin>
50                 <groupId>org.springframework.boot</groupId>
51                 <artifactId>spring-boot-maven-plugin</artifactId>
52             </plugin>
53         </plugins>
54     </build>
55 </project>

View Code

  2、编写测试用例

1 package com.test.springboot.es;
 2 
 3 import com.fasterxml.jackson.databind.ObjectMapper;
 4 import org.apache.http.HttpHost;
 5 import org.apache.http.util.EntityUtils;
 6 import org.elasticsearch.client.*;
 7 import org.junit.After;
 8 import org.junit.Before;
 9 import org.junit.Test;
10 
11 import java.io.IOException;
12 import java.util.HashMap;
13 import java.util.Map;
14 
15 public class TestLowRestClient {
16 
17     private static final ObjectMapper MAPPER = new ObjectMapper();
18     private RestClient restClient;
19 
20     @Before
21     public void init() {
22         RestClientBuilder restClientBuilder = RestClient.builder(
23                 new HttpHost("127.0.0.1", 19201, "http"),
24                 new HttpHost("127.0.0.1", 19202, "http"),
25                 new HttpHost("127.0.0.1", 19203, "http"));
26         restClientBuilder.setFailureListener(new RestClient.FailureListener() {
27             @Override
28             public void onFailure(Node node) {
29                 System.out.println("出错了 -> " + node);
30             }
31         });
32         this.restClient = restClientBuilder.build();
33     }
34 
35     @After
36     public void after() throws IOException {
37         restClient.close();
38     }
39 
40     // 查询集群状态
41     @Test
42     public void testGetInfo() throws IOException {
43         Request request = new Request("GET", "/_cluster/state");
44         request.addParameter("pretty", "true");
45         Response response = this.restClient.performRequest(request);
46         System.out.println(response.getStatusLine());
47         System.out.println(EntityUtils.toString(response.getEntity()));
48     }
49 
50 
51     // 新增数据
52     @Test
53     public void testCreateData() throws IOException {
54         Request request = new Request("POST", "/house/_doc");
55         Map<String, Object> data = new HashMap<>();
56         data.put("id", "2001");
57         data.put("title", "张江高科");
58         data.put("price", "3500");
59         request.setJsonEntity(MAPPER.writeValueAsString(data));
60         Response response = this.restClient.performRequest(request);
61         System.out.println(response.getStatusLine());
62         System.out.println(EntityUtils.toString(response.getEntity()));
63     }
64 
65 
66     // 根据id查询数据
67     @Test
68     public void testQueryData() throws IOException {
69         Request request = new Request("GET", "/house/_doc/i7I4snIB-J-F9-0D3D6H");
70         Response response = this.restClient.performRequest(request);
71         System.out.println(response.getStatusLine());
72         System.out.println(EntityUtils.toString(response.getEntity()));
73     }
74 
75     // 搜索数据
76     @Test
77     public void testSearchData() throws IOException {
78         Request request = new Request("POST", "/house/_search");
79         String searchJson = "{\"query\": {\"match\": {\"title\": \"拎包入住\"}}}";
80         request.setJsonEntity(searchJson);
81         request.addParameter("pretty", "true");
82         Response response = this.restClient.performRequest(request);
83         System.out.println(response.getStatusLine());
84         System.out.println(EntityUtils.toString(response.getEntity()));
85     }
86 
87 }

   3、测试

    分别测试以上方法,均能正常返回

  从使用中,可以看出,基本和我们使用RESTful api使用几乎是一致的。

REST高级客户端

   1、在工程共新增高级客户端依赖

1 <dependency>
 2     <groupId>org.elasticsearch.client</groupId>
 3     <artifactId>elasticsearch-rest-high-level-client</artifactId>
 4     <version>7.6.1</version>
 5     <exclusions>
 6         <exclusion>
 7             <groupId>org.elasticsearch</groupId>
 8             <artifactId>elasticsearch</artifactId>
 9         </exclusion>
10     </exclusions>
11 </dependency>
12 <dependency>
13     <groupId>org.elasticsearch</groupId>
14     <artifactId>elasticsearch</artifactId>
15     <version>7.6.1</version>
16 </dependency>
17 
18 <dependency>
19     <groupId>org.elasticsearch.client</groupId>
20     <artifactId>elasticsearch-rest-client</artifactId>
21     <version>7.6.1</version>
22 </dependency>

  2、编写测试用例

1 package com.test.springboot.es;
  2 
  3 import com.fasterxml.jackson.databind.ObjectMapper;
  4 import org.apache.http.HttpHost;
  5 import org.apache.http.util.EntityUtils;
  6 import org.elasticsearch.action.ActionListener;
  7 import org.elasticsearch.action.delete.DeleteRequest;
  8 import org.elasticsearch.action.delete.DeleteResponse;
  9 import org.elasticsearch.action.get.GetRequest;
 10 import org.elasticsearch.action.get.GetResponse;
 11 import org.elasticsearch.action.index.IndexRequest;
 12 import org.elasticsearch.action.index.IndexResponse;
 13 import org.elasticsearch.action.search.SearchRequest;
 14 import org.elasticsearch.action.search.SearchResponse;
 15 import org.elasticsearch.action.update.UpdateRequest;
 16 import org.elasticsearch.action.update.UpdateResponse;
 17 import org.elasticsearch.client.*;
 18 import org.elasticsearch.common.Strings;
 19 import org.elasticsearch.common.unit.TimeValue;
 20 import org.elasticsearch.index.query.QueryBuilders;
 21 import org.elasticsearch.search.SearchHit;
 22 import org.elasticsearch.search.SearchHits;
 23 import org.elasticsearch.search.builder.SearchSourceBuilder;
 24 import org.elasticsearch.search.fetch.subphase.FetchSourceContext;
 25 import org.junit.After;
 26 import org.junit.Before;
 27 import org.junit.Test;
 28 
 29 import java.io.IOException;
 30 import java.util.HashMap;
 31 import java.util.Map;
 32 import java.util.concurrent.TimeUnit;
 33 
 34 public class TestHighRestClient {
 35 
 36     private static final ObjectMapper MAPPER = new ObjectMapper();
 37     private RestHighLevelClient restHighClient;
 38 
 39     @Before
 40     public void init() {
 41 
 42         RestClientBuilder restClientBuilder = RestClient.builder(
 43                 new HttpHost("127.0.0.1", 19201, "http"),
 44                 new HttpHost("127.0.0.1", 19202, "http"),
 45                 new HttpHost("127.0.0.1", 19203, "http"));
 46         restClientBuilder.setFailureListener(new RestClient.FailureListener() {
 47             @Override
 48             public void onFailure(Node node) {
 49                 System.out.println("出错了 -> " + node);
 50             }
 51         });
 52 
 53         this.restHighClient = new RestHighLevelClient(restClientBuilder);
 54     }
 55 
 56     @After
 57     public void after() throws IOException {
 58         restHighClient.close();
 59     }
 60 
 61     // 新增文档,同步操作
 62     @Test
 63     public void testCreate() throws Exception {
 64         Map<String, Object> data = new HashMap<>();
 65         data.put("id", "2002");
 66         data.put("title", "南京西路 拎包入住 一室一厅");
 67         data.put("price", "4500");
 68         IndexRequest indexRequest = new IndexRequest("house", "_doc").source(data);
 69         IndexResponse indexResponse = restHighClient.index(indexRequest, RequestOptions.DEFAULT);
 70         System.out.println("id->" + indexResponse.getId());
 71         System.out.println("index->" + indexResponse.getIndex());
 72         System.out.println("type->" + indexResponse.getType());
 73         System.out.println("version->" + indexResponse.getVersion());
 74         System.out.println("result->" + indexResponse.getResult());
 75         System.out.println("shardInfo->" + indexResponse.getShardInfo());
 76     }
 77 
 78     //  新增文档,异步操作
 79     @Test
 80     public void testCreateAsync() throws Exception {
 81         Map<String, Object> data = new HashMap<>();
 82         data.put("id", "2003");
 83         data.put("title", "南京东路 最新房源 二室一厅");
 84         data.put("price", "5500");
 85         IndexRequest indexRequest = new IndexRequest("house", "_doc").source(data);
 86         restHighClient.indexAsync(indexRequest, RequestOptions.DEFAULT, new ActionListener<IndexResponse>() {
 87             @Override
 88             public void onResponse(IndexResponse indexResponse) {
 89                 System.out.println("id->" + indexResponse.getId());
 90                 System.out.println("index->" + indexResponse.getIndex());
 91                 System.out.println("type->" + indexResponse.getType());
 92                 System.out.println("version->" + indexResponse.getVersion());
 93                 System.out.println("result->" + indexResponse.getResult());
 94                 System.out.println("shardInfo->" + indexResponse.getShardInfo());
 95             }
 96 
 97             @Override
 98             public void onFailure(Exception e) {
 99                 System.out.println(e);
100             }
101         });
102         System.out.println("ok");
103         Thread.sleep(20000);
104     }
105 
106     // 测试查询
107     @Test
108     public void testQuery() throws Exception {
109         GetRequest getRequest = new GetRequest("house", "_doc",
110                 "jLI5snIB-J-F9-0D8j7h");
111         // 指定返回的字段
112         String[] includes = new String[]{"title", "id"};
113         String[] excludes = Strings.EMPTY_ARRAY;
114         FetchSourceContext fetchSourceContext =
115                 new FetchSourceContext(true, includes, excludes);
116         getRequest.fetchSourceContext(fetchSourceContext);
117         GetResponse response = restHighClient.get(getRequest, RequestOptions.DEFAULT);
118         System.out.println("数据 -> " + response.getSource());
119     }
120 
121 
122     // 判断是否存在
123     @Test
124     public void testExists() throws Exception {
125         GetRequest getRequest = new GetRequest("house", "_doc", "jLI5snIB-J-F9-0D8j7h"); // 不返回的字段
126         // 不返回的字段
127         getRequest.fetchSourceContext(new FetchSourceContext(false));
128         boolean exists = restHighClient.exists(getRequest, RequestOptions.DEFAULT);
129         System.out.println("exists -> " + exists);
130     }
131 
132     // 删除数据
133     @Test
134     public void testDelete() throws Exception {
135 
136         DeleteRequest deleteRequest = new DeleteRequest("house", "_doc",
137                 "jLI5snIB-J-F9-0D8j7h");
138         DeleteResponse response = restHighClient.delete(deleteRequest,
139                 RequestOptions.DEFAULT);
140         System.out.println(response.status());// OK or NOT_FOUND
141     }
142 
143     // 更新数据
144     @Test
145     public void testUpdate() throws Exception {
146         UpdateRequest updateRequest = new UpdateRequest("house", "_doc",
147                 "i7I4snIB-J-F9-0D3D6H");
148         Map<String, Object> data = new HashMap<>();
149         data.put("title", "张江高科2");
150         data.put("price", "5000");
151         updateRequest.doc(data);
152         UpdateResponse response = restHighClient.update(updateRequest, RequestOptions.DEFAULT);
153         System.out.println("version -> " + response.getVersion());
154     }
155 
156 
157     // 搜索数据
158     @Test
159     public void testSearch() throws Exception {
160         SearchRequest searchRequest = new SearchRequest("house");
161         searchRequest.types("_doc");
162         SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
163         sourceBuilder.query(QueryBuilders.matchQuery("title", "拎包入住"));
164         sourceBuilder.from(0);
165         sourceBuilder.size(5);
166         sourceBuilder.timeout(new TimeValue(60, TimeUnit.SECONDS));
167         searchRequest.source(sourceBuilder);
168         SearchResponse search = restHighClient.search(searchRequest, RequestOptions.DEFAULT);
169         System.out.println("搜索到 " + search.getHits().getTotalHits().value + " 条数据.");
170         SearchHits hits = search.getHits();
171         for (SearchHit hit : hits) {
172             System.out.println(hit.getSourceAsString());
173         }
174     }
175 }

REST客户端与SpringBoot集成

  测试elasticsearch版本是:7.6.1

  集成原理:

    在SpringBoot自动装配类(RestClientAutoConfiguration.class)中,导入Rest客户端配置类(RestClientConfigurations)中的静态类

1 @Configuration(proxyBeanMethods = false)
2 @ConditionalOnClass(RestClient.class)
3 @EnableConfigurationProperties(RestClientProperties.class)
4 @Import({ RestClientConfigurations.RestClientBuilderConfiguration.class,
5         RestClientConfigurations.RestHighLevelClientConfiguration.class,
6         RestClientConfigurations.RestClientFallbackConfiguration.class })
7 public class RestClientAutoConfiguration {
8 
9 }

    查看Rest客户端配置类(RestClientConfigurations)

1 class RestClientConfigurations {
 2 
 3     ...
 4 
 5     @Configuration(proxyBeanMethods = false)
 6     @ConditionalOnClass(RestHighLevelClient.class)
 7     static class RestHighLevelClientConfiguration {
 8 
 9         // 高级客户端
10         @Bean
11         @ConditionalOnMissingBean
12         RestHighLevelClient elasticsearchRestHighLevelClient(RestClientBuilder restClientBuilder) {
13             return new RestHighLevelClient(restClientBuilder);
14         }
15 
16         // 低级客户端
17         @Bean
18         @ConditionalOnMissingBean
19         RestClient elasticsearchRestClient(RestClientBuilder builder,
20                 ObjectProvider<RestHighLevelClient> restHighLevelClient) {
21             RestHighLevelClient client = restHighLevelClient.getIfUnique();
22             if (client != null) {
23                 return client.getLowLevelClient();
24             }
25             return builder.build();
26         }
27 
28     }
29 
30     ...
31 
32 }

    可以看到配置类中,自动配置类 ES低级客户端、ES高级客户端

  集成

  1、新建项目引入依赖,spring-boot-starter-data-elasticsearch

1 <!-- SpringBoot默认使用SpringData ElasticSearch模块进行操作 -->
2 <dependency>
3     <groupId>org.springframework.boot</groupId>
4     <artifactId>spring-boot-starter-data-elasticsearch</artifactId> 
5 </dependency>

    完整依赖如下:

es java项目搭建 es java客户端_ElasticStack_02

es java项目搭建 es java客户端_ElasticStack_03

1 <?xml version="1.0" encoding="UTF-8"?>
 2 <project xmlns="http://maven.apache.org/POM/4.0.0"
 3          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 4          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
 5     <modelVersion>4.0.0</modelVersion>
 6 
 7     <groupId>com.test</groupId>
 8     <artifactId>test-springboot-es</artifactId>
 9     <version>1.0-SNAPSHOT</version>
10 
11     <parent>
12         <groupId>org.springframework.boot</groupId>
13         <artifactId>spring-boot-starter-parent</artifactId>
14         <version>2.2.5.RELEASE</version>
15     </parent>
16 
17     <properties>
18 
19         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
20         <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
21         <java.version>1.8</java.version>
22     </properties>
23 
24     <dependencies>
25 
26         <dependency>
27             <groupId>org.springframework.boot</groupId>
28             <artifactId>spring-boot-starter-web</artifactId>
29         </dependency>
30 
31 
32         <!-- SpringBoot默认使用SpringData ElasticSearch模块进行操作 -->
33         <dependency>
34             <groupId>org.springframework.boot</groupId>
35             <artifactId>spring-boot-starter-data-elasticsearch</artifactId> 
36         </dependency>
37         
38         <dependency>
39             <groupId>org.springframework.boot</groupId>
40             <artifactId>spring-boot-starter-test</artifactId>
41             <scope>test</scope>
42         </dependency>
43 
44     </dependencies>
45 
46 
47     <!-- SpringBoot打包插件,可以将代码打包成一个可执行的jar包 -->
48     <build>
49         <plugins>
50             <plugin>
51                 <groupId>org.springframework.boot</groupId>
52                 <artifactId>spring-boot-maven-plugin</artifactId>
53             </plugin>
54         </plugins>
55     </build>
56 </project>

View Code

   2、编写测试用例

1 package com.test.springboot.es;
 2 
 3 
 4 import org.apache.http.util.EntityUtils;
 5 import org.elasticsearch.action.search.SearchRequest;
 6 import org.elasticsearch.action.search.SearchResponse;
 7 import org.elasticsearch.client.*;
 8 import org.elasticsearch.common.unit.TimeValue;
 9 import org.elasticsearch.index.query.QueryBuilders;
10 import org.elasticsearch.search.SearchHit;
11 import org.elasticsearch.search.SearchHits;
12 import org.elasticsearch.search.builder.SearchSourceBuilder;
13 import org.junit.Test;
14 import org.junit.runner.RunWith;
15 import org.springframework.beans.factory.annotation.Autowired;
16 import org.springframework.boot.test.context.SpringBootTest;
17 import org.springframework.test.context.junit4.SpringRunner;
18 
19 import java.io.IOException;
20 import java.util.concurrent.TimeUnit;
21 
22 @RunWith(SpringRunner.class)
23 @SpringBootTest
24 public class TestSpringBootES {
25 
26     // 低级客户端
27     @Autowired
28     RestClient restClient;
29 
30     // 高级客户端
31     @Autowired
32     RestHighLevelClient restHighLevelClient;
33 
34     // 低级客户端搜索数据
35     @Test
36     public void testRestClientSearch() throws IOException {
37         Request request = new Request("POST", "/house/_search");
38         String searchJson = "{\"query\": {\"match\": {\"title\": \"拎包入住\"}}}";
39         request.setJsonEntity(searchJson);
40         request.addParameter("pretty", "true");
41         Response response = restClient.performRequest(request);
42         System.out.println(response.getStatusLine());
43         System.out.println(EntityUtils.toString(response.getEntity()));
44     }
45 
46     // 高级客户端搜索数据
47     @Test
48     public void testRestHighLevelClientSearch() throws Exception {
49         SearchRequest searchRequest = new SearchRequest("house");
50         SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
51         sourceBuilder.query(QueryBuilders.matchQuery("title", "拎包入住"));
52         sourceBuilder.from(0);
53         sourceBuilder.size(5);
54         sourceBuilder.timeout(new TimeValue(60, TimeUnit.SECONDS));
55         searchRequest.source(sourceBuilder);
56         SearchResponse search = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
57         System.out.println("搜索到 " + search.getHits().getTotalHits() + " 条数据.");
58         SearchHits hits = search.getHits();
59         for (SearchHit hit : hits) {
60             System.out.println(hit.getSourceAsString());
61         }
62     }
63 }

  3、编辑application.yml文件

1 spring:
2   elasticsearch:
3     rest:
4       uris: http://127.0.0.1:9200

 

  4、测试验证, 测试方法皆运行成功,证明ES低级客户端、ES高级客户端皆有效