Java客户端
在Elasticsearch中,为java提供了2种客户端,一种是REST风格的客户端,另一种是Java API的客户端。
官网:https://www.elastic.co/guide/en/elasticsearch/client/index.html
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>
完整依赖如下:

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>
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>
完整依赖如下:

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>
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高级客户端皆有效