springBoot集成es有三种方法:java api、rest client、data-es,主流的是第三种方法,下面分别介绍下:
一、java api:这种方式,官方已经明确表示在ES 7.0版本中将弃用TransportClient
客户端,且在8.0版本中完全移除它。下面以SpringBoot 2.0.5,ES 5.5.0搭配看下集成方法:
1、依赖:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.glodon</groupId>
<artifactId>elasticsearch_data</artifactId>
<version>1.0-SNAPSHOT</version>
<!--SpringBoot的基本父级依赖-->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.6.RELEASE</version>
</parent>
<properties>
<java.version>1.8</java.version>
<elasticsearch.version>5.5.0</elasticsearch.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
<!--springboot对web项目的支持-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--引入spring-data-es的依赖-->
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>transport</artifactId>
<version>${elasticsearch.version}</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.7</version>
</dependency>
<!--<dependency>-->
<!--<groupId>org.elasticsearch</groupId>-->
<!--<artifactId>elasticsearch</artifactId>-->
<!--<version>5.5.0</version>-->
<!--</dependency>-->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.8</version>
</dependency>
<!--引入ES推荐的操作客户端:rest-high-level-client-->
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
2、配置文件:
@Configuration
public class MyConfig {
@Bean
public TransportClient client() throws UnknownHostException {
// 指定集群名,默认为elasticsearch,如果改了集群名,这里一定要加
Settings settings = Settings.builder()
.put("cluster.name", "elasticsearch")
.build();
TransportClient client = new PreBuiltTransportClient(settings);
/*
这里只配置了一个节点的地址然添加进去,也可以配置多个从节点添加进去再返回
*/
InetSocketTransportAddress node = new InetSocketTransportAddress(
InetAddress.getByName("localhost"),
9300
);
client.addTransportAddress(node);
return client;
}
}
3、controller:
@RestController
@RequestMapping("/es")
public class BookController {
@Autowired
private TransportClient client;
@RequestMapping(value = "/go")
public String go() {
return "go1";
}
/**
* 根据id查询
*
* @param id book id
*/
@RequestMapping(value = "/book", method = RequestMethod.GET)
public ResponseEntity<java.util.Map<String, Object>> get(@RequestParam("id") String id) {
GetResponse result = client.prepareGet("book", "novel", id).get();
return new ResponseEntity<>(result.getSource(), HttpStatus.OK);
}
/**
* 添加文档
*
* @param id book id
* @param name book name
*/
@RequestMapping(value = "/book", method = RequestMethod.POST)
public ResponseEntity<String> add(@RequestParam("id") String id, @RequestParam("name") String name) {
try {
// 构造ES的文档,这里注意startObject()开始构造,结束构造一定要加上endObject()
XContentBuilder content = XContentFactory.jsonBuilder().startObject().
field("id", id)
.field("name", name)
.endObject();
IndexResponse result = client.prepareIndex("book", "novel")
.setSource(content).get();
return new ResponseEntity<>(result.getId(), HttpStatus.OK);
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
/**
* 根据id删除book
*
* @param id book id
*/
@RequestMapping(value = "/book/{id}", method = RequestMethod.DELETE)
public ResponseEntity<String> delete(@PathVariable(value = "id") String id) {
DeleteResponse result = client.prepareDelete("book", "novel", id).get();
return new ResponseEntity<>(result.getResult().toString(), HttpStatus.OK);
}
/**
* 更新文档,这里的Book可以不管他,这样做是为了解决PUT请求的问题,随便搞
*/
@RequestMapping(value = "/book", method = RequestMethod.PUT)
public ResponseEntity<String> update(@RequestBody Book book) {
System.out.println(book);
// 根据id查询
UpdateRequest updateRequest = new UpdateRequest("book", "novel", book.getId().toString());
try {
XContentBuilder contentBuilder = XContentFactory.jsonBuilder().startObject();
if (StringUtils.isNotBlank(book.getName())) {
contentBuilder.field("name", book.getName());
}
contentBuilder.endObject();
updateRequest.doc(contentBuilder);
} catch (IOException e) {
e.printStackTrace();
}
// 进行更新
UpdateResponse updateResponse = new UpdateResponse();
try {
updateResponse = client.update(updateRequest).get();
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
return new ResponseEntity<>(updateResponse.getResult().toString(), HttpStatus.OK);
}
}
二、rest client:
官方给出来的REST Client有Java Low Level REST Client和Java Hight Level REST Client两个,前者兼容所有版本的ES,后者是基于前者开发出来的,只暴露了部分API,待完善。这种方法是基于HTTP端口去通信的,便于操作,而且跟ES版本几乎没有关系。这个案例中使用Java Low Level REST Client,有如下的一些特点:
最小化依赖;持久连接;跟踪请求和响应的日志记录;可选的集群节点自动发现功能;提供跨所有可用节点的负载平衡;提供节点故障和特定响应代码时的故障转移;提供失败重连的惩罚机制(是否对一个连接失败的节点尝试重连,取决于它连续失败的次数,尝试重连且失败的次数越多,客户端在再次尝试重连这个节点时等的时间就越长。说那么多,太复杂了,其实给一个场景就是:我找你玩儿,你不答应,我伤自尊了,下次去找你我隔了一个星期再去找你,你又不答应,我又伤自尊了,下次再找你的话,那我就隔两个星期,依次类推);下面以es6.4.0为例看下集成方法:
1、依赖:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>elasticsearch_data</artifactId>
<groupId>com.glodon</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>es_java_rest</artifactId>
<dependencies>
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-client</artifactId>
<version>6.4.0</version>
</dependency>
<!--引入json进行HTTP序列化-->
<dependency>
<groupId>org.json</groupId>
<artifactId>json</artifactId>
<version>20160810</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.1.0</version>
<executions>
<execution>
<phase>package</phase>
<goals><goal>shade</goal></goals>
<configuration>
<relocations>
<relocation>
<pattern>org.apache.http</pattern>
<shadedPattern>hidden.org.apache.http</shadedPattern>
</relocation>
<relocation>
<pattern>org.apache.logging</pattern>
<shadedPattern>hidden.org.apache.logging</shadedPattern>
</relocation>
<relocation>
<pattern>org.apache.commons.codec</pattern>
<shadedPattern>hidden.org.apache.commons.codec</shadedPattern>
</relocation>
<relocation>
<pattern>org.apache.commons.logging</pattern>
<shadedPattern>hidden.org.apache.commons.logging</shadedPattern>
</relocation>
</relocations>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
2、配置文件:
@Configuration
public class RestConfig {
@Bean
public RestClient getClient() throws KeyStoreException, NoSuchAlgorithmException, KeyManagementException {
// 如果有多个从节点可以持续在内部new多个HttpHost,参数1是ip,参数2是HTTP端口,参数3是通信协议
RestClientBuilder clientBuilder = RestClient.builder(new HttpHost("localhost", 9200, "http"));
// 添加其他配置,返回来的还是RestClientBuilder对象,这些配置都是可选的
// clientBuilder.setXX()...
// 最后配置好的clientBuilder再build一下即可得到真正的Client
return clientBuilder.build();
}
}
3、controller:
@RestController
@RequestMapping("/rest/book")
public class BookController {
@Autowired
private RestClient client;
// // RequestOptions类保存应在同一应用程序中的多个请求之间共享的部分请求
// private static final RequestOptions COMMON_OPTIONS;
//
// static {
// RequestOptions.Builder builder = RequestOptions.DEFAULT.toBuilder();
// // 添加所有请求所需的任何标头。
// builder.addHeader("Authorization", "Bearer " + TOKEN);
// // 自定义响应使用者
// builder.setHttpAsyncResponseConsumerFactory(
// new HttpAsyncResponseConsumerFactory.HeapBufferedResponseConsumerFactory(30 * 1024 * 1024 * 1024));
// COMMON_OPTIONS = builder.build();
// }
@RequestMapping(value = "/go", method = RequestMethod.GET)
public ResponseEntity<String> go() {
return new ResponseEntity<>("go", HttpStatus.OK);
}
/**
* 同步执行HTTP请求
* @return
* @throws IOException
*/
@RequestMapping(value = "/es", method = RequestMethod.GET)
public ResponseEntity<String> getEsInfo() throws IOException {
// 构造HTTP请求,第一个参数是请求方法,第二个参数是服务器的端点,host默认是http://localhost:9200
Request request = new Request("GET", "/");
// // 设置其他一些参数比如美化json
// request.addParameter("pretty", "true");
// // 设置请求体
// request.setEntity(new NStringEntity("{\"json\":\"text\"}", ContentType.APPLICATION_JSON));
// // 还可以将其设置为String,默认为ContentType为application/json
// request.setJsonEntity("{\"json\":\"text\"}");
/*
performRequest是同步的,将阻塞调用线程并在请求成功时返回Response,如果失败则抛出异常
内部属性可以取出来通过下面的方法
*/
Response response = client.performRequest(request);
// // 获取请求行
// RequestLine requestLine = response.getRequestLine();
// // 获取host
// HttpHost host = response.getHost();
// // 获取状态码
// int statusCode = response.getStatusLine().getStatusCode();
// // 获取响应头
// Header[] headers = response.getHeaders();
// 获取响应体
String responseBody = EntityUtils.toString(response.getEntity());
return new ResponseEntity<>(responseBody, HttpStatus.OK);
}
/**
* 异步执行HTTP请求
* @return
*/
@RequestMapping(value = "/es/asyn", method = RequestMethod.GET)
public ResponseEntity<String> asynchronous() {
Request request = new Request(
"GET",
"/");
client.performRequestAsync(request, new ResponseListener() {
@Override
public void onSuccess(Response response) {
System.out.println("异步执行HTTP请求并成功");
}
@Override
public void onFailure(Exception exception) {
System.out.println("异步执行HTTP请求并失败");
}
});
return null;
}
/**
* 并行异步执行HTTP请求
*/
@RequestMapping(value = "/ps", method = RequestMethod.POST)
public void parallAsyn(@RequestBody Book[] documents) {
// final CountDownLatch latch = new CountDownLatch(documents.length);
// for (int i = 0; i < documents.length; i++) {
// Request request = new Request("PUT", "/posts/doc/" + i);
// //let's assume that the documents are stored in an HttpEntity array
// request.setEntity(documents[i]);
// client.performRequestAsync(
// request,
// new ResponseListener() {
// @Override
// public void onSuccess(Response response) {
//
// latch.countDown();
// }
//
// @Override
// public void onFailure(Exception exception) {
//
// latch.countDown();
// }
// }
// );
// }
// latch.await();
}
/**
* 添加ES对象, Book的ID就是ES中存储的document的ID,所以最好不要为空,自定义生成的ID太浮夸
*
* @return ResponseEntity
* @throws IOException
*/
@RequestMapping(value = "/", method = RequestMethod.POST)
public ResponseEntity<String> add(@RequestBody Book book) throws IOException {
// 构造HTTP请求,第一个参数是请求方法,第二个参数是服务器的端点,host默认是http://localhost:9200,
// endpoint直接指定为index/type的形式
Request request = new Request("POST", new StringBuilder("/book/book/").
append(book.getId()).toString());
// 设置其他一些参数比如美化json
request.addParameter("pretty", "true");
JSONObject jsonObject = new JSONObject(book);
System.out.println(jsonObject.toString());
// 设置请求体并指定ContentType,如果不指定默认为APPLICATION_JSON
request.setEntity(new NStringEntity(jsonObject.toString()));
// 发送HTTP请求
Response response = client.performRequest(request);
// 获取响应体, id: AWXvzZYWXWr3RnGSLyhH
String responseBody = EntityUtils.toString(response.getEntity());
return new ResponseEntity<>(responseBody, HttpStatus.OK);
}
/**
* 根据id获取ES对象
*
* @param id
* @return
* @throws IOException
*/
@RequestMapping(value = "/{id}", method = RequestMethod.GET)
public ResponseEntity<String> getBookById(@PathVariable("id") String id) {
Request request = new Request("GET", new StringBuilder("/book/book/").
append(id).toString());
// 添加json返回优化
request.addParameter("pretty", "true");
Response response = null;
String responseBody = null;
try {
// 执行HHTP请求
response = client.performRequest(request);
responseBody = EntityUtils.toString(response.getEntity());
} catch (IOException e) {
return new ResponseEntity<>("can not found the book by your id", HttpStatus.NOT_FOUND);
}
return new ResponseEntity<>(responseBody, HttpStatus.OK);
}
/**
* 根据id更新Book
*
* @param id
* @param book
* @return
*/
@RequestMapping(value = "/{id}", method = RequestMethod.PUT)
public ResponseEntity<String> updateBook(@PathVariable("id") String id, @RequestBody Book book) throws IOException {
// 构造HTTP请求
Request request = new Request("POST", new StringBuilder("/book/book/").
append(id).append("/_update").toString());
request.addParameter("pretty", "true");
// 将数据丢进去,这里一定要外包一层“doc”,否则内部不能识别
JSONObject jsonObject = new JSONObject();
jsonObject.put("doc", new JSONObject(book));
request.setEntity(new NStringEntity(jsonObject.toString()));
// 执行HTTP请求
Response response = client.performRequest(request);
// 获取返回的内容
String responseBody = EntityUtils.toString(response.getEntity());
return new ResponseEntity<>(responseBody, HttpStatus.OK);
}
/**
* 使用脚本更新Book
* @param id
* @param
* @return
* @throws IOException
*/
@RequestMapping(value = "/update2/{id}", method = RequestMethod.PUT)
public ResponseEntity<String> updateBook2(@PathVariable("id") String id, @RequestParam("name") String name) throws IOException {
// 构造HTTP请求
Request request = new Request("POST", new StringBuilder("/book/book/").
append(id).append("/_update").toString());
request.addParameter("pretty", "true");
JSONObject jsonObject = new JSONObject();
// 创建脚本语言,如果是字符变量,必须加单引号
StringBuilder op1 = new StringBuilder("ctx._source.name=").append("'" + name + "'");
jsonObject.put("script", op1);
request.setEntity(new NStringEntity(jsonObject.toString(), ContentType.APPLICATION_JSON));
// 执行HTTP请求
Response response = client.performRequest(request);
// 获取返回的内容
String responseBody = EntityUtils.toString(response.getEntity());
return new ResponseEntity<>(responseBody, HttpStatus.OK);
}
@RequestMapping(value = "/{id}", method = RequestMethod.DELETE)
public ResponseEntity<String> deleteById(@PathVariable("id") String id) throws IOException {
Request request = new Request("DELETE", new StringBuilder("/book/book/").append(id).toString());
request.addParameter("pretty", "true");
// 执行HTTP请求
Response response = client.performRequest(request);
// 获取结果
String responseBody = EntityUtils.toString(response.getEntity());
return new ResponseEntity<>(responseBody, HttpStatus.OK);
}
}
三、spring-data-es:Spring提供了本身基于SpringData实现的一套方案spring-data-elasticsearch
,还有后来衍生的spring-boot-data-elasticsearch
,都是一样的,版本之间的搭配建议为:
spring data elasticsearch | elasticsearch |
---|---|
3.1.x | 6.2.2 |
3.0.x | 5.5.0 |
2.1.x | 2.4.0 |
2.0.x | 2.2.0 |
1.3.x | 1.5.2 |
集成方法见下一篇博客:https://blog.csdn.net/w_t_y_y/article/details/109472658