首先有三种方式可以实现在java代码里操作ES,分别是Java API(TransportClient客户端),REST Client以及Data-ES,对于第一种,ES官方表示将在ES 8.0版本弃用,所以不是我们学习的重点。至于Data-ES,虽然它和SpringBoot集成的很好,容易上手,而且提供了很方便的api,但是据说不支持ES的权限数据,如果只是很简单的获取普通数据,Data-ES将是很好的一个方式。但如果需要获取权限数据呢?
首先pom依赖如下
org.springframework.boot
spring-boot-starter
org.springframework.boot
spring-boot-starter-test
test
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-configuration-processor
true
org.elasticsearch
elasticsearch
6.8.4
org.elasticsearch.client
elasticsearch-rest-client
6.8.4
org.elasticsearch.plugin
reindex-client
6.8.4
com.alibaba
fastjson
1.2.54
org.apache.commons
commons-lang3
org.projectlombok
lombok
true
io.springfox
springfox-swagger2
2.7.0
io.springfox
springfox-swagger-ui
2.7.0
io.springfox
springfox-staticdocs
2.4.0
io.github.robwin
assertj-swagger
0.2.0
test
然后是yml文件
server:
port: 8080
swagger:
enable: true
title: ElasticSearch-demo
description:
serviceUrl: http://localhost:8080/
version: 1.0.0
controllers: com.example.es.controller
elasticsearch:
user:
password:
host: 192.168.145.128
port: 9200
PS:swagger和lombok是好东西
配置类:
@Configuration
@Slf4j
public class ESConfig {
@Value("${elasticsearch.user}")
private String userName;
@Value("${elasticsearch.password}")
private String password;
@Value("${elasticsearch.host}")
private String host;
@Value("${elasticsearch.port}")
private Integer port;
@Bean(name = "myClient")
public RestClient getRestClient() {
//基本的连接
RestClientBuilder clientBuilder = RestClient.builder(new HttpHost(host, port));
//配置身份验证
final CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
credentialsProvider.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials(userName, password));
clientBuilder.setHttpClientConfigCallback(
httpClientBuilder -> httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider));
//设置连接超时和套接字超时
clientBuilder.setRequestConfigCallback(builder -> builder.setConnectTimeout(10000).setSocketTimeout(60000));
//设置节点选择器
clientBuilder.setNodeSelector(NodeSelector.SKIP_DEDICATED_MASTERS);
//配置HTTP异步请求ES的线程数
clientBuilder.setHttpClientConfigCallback(
httpAsyncClientBuilder -> httpAsyncClientBuilder.setDefaultIOReactorConfig(
IOReactorConfig.custom().setIoThreadCount(1).build()));
//设置监听器,每次节点失败都可以监听到,可以作额外处理
clientBuilder.setFailureListener(new RestClient.FailureListener() {
@Override
public void onFailure(Node node) {
super.onFailure(node);
log.error(node.getHost() + "--->该节点失败了");
}
});
return clientBuilder.build();
}
}
这样的话,已经算是集成到springboot了,但是如何实现增删改查?
首先引入两个bean,后续的代码有用
Person类,这个是我们接下来要操作的实体类
@Data
public class Person {
private String id;
private String name;
private String birthday;
private String addr;
}
SearchParam类,用于拼接请求内容,包括index,type和id
@Data
public class SearchParam {
@ApiModelProperty("索引")
private String index;
@ApiModelProperty("类型")
private String type;
@ApiModelProperty("id")
private String id;
}
接下来是Controller层的代码
@RestController
@RequestMapping("/es")
public class MyController {
@Autowired
private MyService service;
@PostMapping("/search")
@ApiOperation("根据id查询ES对应的数据")
public JSONObject getDataById(@RequestBody SearchParam param) {
return service.getDataById(param);
}
@PostMapping("/add")
@ApiOperation("往ES里插入数据")
public ResponseEntity add(@RequestBody SearchParam param) {
return service.add(param);
}
@PostMapping("/update")
@ApiOperation("根据id更新文档内容")
public ResponseEntity update(@RequestBody SearchParam param) {
return service.update(param);
}
@PostMapping("/delete")
@ApiOperation("根据id更新文档内容")
public ResponseEntity delete(@RequestBody SearchParam param) {
return service.delete(param);
}
}
重点来了,Service层,具体实现方法
在service类里,我们需要用到我们之前在config配置类里配置的bean,但是如果直接注入的话,spring会报如下错误
意思是spring不知道我们现在用哪个类,对于这个报错,我们做如下处理
@Service
@Slf4j
public class MyService {
@Qualifier("myClient")
@Autowired
private RestClient client;
}
用@Qualifier注解来指定具体要注入哪个bean
通过id查询:
/**
* 根据id查询文档内容
*
* @param param
* @return
*/
public JSONObject getDataById(SearchParam param) {
//拼接查询内容
String body = param.getIndex() + "/" + param.getType() + "/" + param.getId();
Request request = new Request("GET", body);
JSONObject jsonObject = new JSONObject();
try {
Response response = client.performRequest(request);
String responseBody = EntityUtils.toString(response.getEntity(), "UTF-8");
JSONObject json = JSONObject.parseObject(responseBody);
//获取我们需要的内容
Object source = json.get("_source");
jsonObject = JSONObject.parseObject(source.toString());
} catch (IOException e) {
log.error(e.getMessage());
}
return jsonObject;
}
添加文档:
/**
* 添加文档
*
* @param param
* @return
*/
public ResponseEntity add(SearchParam param) {
Person person = new Person();
person.setName("朱元璋");
person.setAddr("安徽凤阳");
person.setBirthday("1328-10-29");
person.setId("1234567890");
//以bean的id为该文档的id,以便查询
String body = param.getIndex() + "/" + param.getType() + "/" + person.getId();
String responseBody = "";
try {
Request request = new Request("POST", body);
JSONObject jsonObject = (JSONObject) JSONObject.toJSON(person);
//设置请求体并指定ContentType和编码格式
request.setEntity(new NStringEntity(jsonObject.toString(), "UTF-8"));
Response response = client.performRequest(request);
//获取响应体
responseBody = EntityUtils.toString(response.getEntity());
} catch (IOException e) {
log.error(e.getMessage());
}
return new ResponseEntity<>(responseBody, HttpStatus.OK);
}
根据id更新文档内容:
/**
* 根据id更新文档内容
*
* @param param
* @return
*/
public ResponseEntity update(SearchParam param) {
Person person = new Person();
person.setName("朱棣");
person.setAddr("南京");
person.setBirthday("1360-05-02");
//需要更新对应的id
String body = param.getIndex() + "/" + param.getType() + "/" + param.getId() + "/_update";
String responseBody = "";
try {
//构造http请求
Request request = new Request("POST", body);
JSONObject json = (JSONObject) JSONObject.toJSON(person);
JSONObject jsonObject = new JSONObject();
//将数据由"doc"包住,以便内部识别
jsonObject.put("doc", json);
request.setEntity(new NStringEntity(jsonObject.toString(), "UTF-8"));
Response response = client.performRequest(request);
//获取响应体
responseBody = EntityUtils.toString(response.getEntity());
} catch (Exception e) {
log.error(e.getMessage());
}
return new ResponseEntity<>(responseBody, HttpStatus.OK);
}
根据id删除对应文档:
/**
* 根据id删除文档
*
* @param param
* @return
*/
public ResponseEntity delete(SearchParam param) {
String body = param.getIndex() + "/" + param.getType() + "/" + param.getId();
String responseBody = "";
try {
Request request = new Request("DELETE", body);
// 执行HTTP请求
Response response = client.performRequest(request);
// 获取结果
responseBody = EntityUtils.toString(response.getEntity());
} catch (IOException e) {
log.error(e.getMessage());
}
return new ResponseEntity<>(responseBody, HttpStatus.OK);
}
好了,简单的增删改查已经可以实现了,而且对于增删改这三种操作来说,以上的方法已经基本够用了,但是对于查询的操作,远远不够,比如我不知道文档的id,我需要通过name="张三"这个条件查询出所有符合条件的文档内容来,还有我需要知道出生日期在1990-1991年之间的,如此种种,上述方法不可能实现。
关于复杂查询的,SpringBoot工程整合ElasticSearch(通过Rest-High-Level-Client)并实现较复杂的查询