说明:es操作索引库、文档,除了使用它们自带的命令外(参考:http://t.csdn.cn/4zpmi),在IDEA中可以添加相关的依赖,使用对应的API来操作。
准备工作
搭建一个SpringBoot项目,DAO使用的MyBatis-Plus,对数据库中的学生表进行操作。
pom.xml文件
<?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>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.10.RELEASE</version>
<relativePath/>
</parent>
<groupId>org.hzy</groupId>
<artifactId>es_essay_demo</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
<elasticsearch.version>7.12.1</elasticsearch.version>
</properties>
<dependencies>
<!--spring web依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--mybatis-plus依赖-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.2</version>
</dependency>
<!--数据库连接驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<!--lombok依赖-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!--测试依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<!--FastJson-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.71</version>
</dependency>
<!--commons依赖-->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
</dependencies>
</project>
在此之上,导入RestHighLevelClient依赖,并指定版本,不然会使用SpringBoot自带版本,依靠此依赖实现对ES的一系列操作。
<properties>
<elasticsearch.version>7.12.1</elasticsearch.version>
</properties>
<!--RestHighLevelClient依赖-->
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-high-level-client</artifactId>
</dependency>
编写与学生类相关的索引库DSL语句,注意这里特意把学生类中的创建日期、入学日期合并成一个joinInfo字段,后面添加文档时需要考虑到这点;
PUT /student
{
"mappings": {
"properties": {
"id": {
"type": "keyword"
},
"username":{
"type": "keyword",
"copy_to": "all"
},
"password":{
"type": "keyword",
"index": false
},
"name":{
"type": "text",
"analyzer": "ik_max_word",
"copy_to": "all"
},
"gender":{
"type": "keyword"
},
"image":{
"type": "keyword"
},
"job":{
"type": "integer"
},
"joinInfo":{
"type": "keyword"
},
"updateTime":{
"type": "keyword"
},
"all":{
"type": "text",
"analyzer": "ik_max_word"
}
}
}
}
将上面索引库的DSL语句,在IDEA中用一个常量来存储,以便后面使用,注意前面“PUT /student”需要去掉,只需要最外层花括号内的信息即可;
public class Constants {
public static final String CREATE_INDEX_STRING = "{\n" +
" \"mappings\": {\n" +
" \"properties\": {\n" +
" \"id\": {\n" +
" \"type\": \"keyword\"\n" +
" },\n" +
" \n" +
" \"username\":{\n" +
" \"type\": \"keyword\",\n" +
" \"copy_to\": \"all\"\n" +
" },\n" +
" \n" +
" \"password\":{\n" +
" \"type\": \"keyword\",\n" +
" \"index\": false\n" +
" },\n" +
" \n" +
" \"name\":{\n" +
" \"type\": \"text\",\n" +
" \"analyzer\": \"ik_max_word\",\n" +
" \"copy_to\": \"all\"\n" +
" },\n" +
"\n" +
" \"gender\":{\n" +
" \"type\": \"keyword\"\n" +
" },\n" +
" \n" +
" \"image\":{\n" +
" \"type\": \"keyword\"\n" +
" },\n" +
" \n" +
" \"job\":{\n" +
" \"type\": \"integer\"\n" +
" },\n" +
"\t \n" +
"\t \"joinInfo\":{\n" +
"\t\t\"type\": \"keyword\"\n" +
"\t },\n" +
" \n" +
" \"updateTime\":{\n" +
" \"type\": \"keyword\"\n" +
" },\n" +
" \n" +
" \n" +
" \"all\":{\n" +
" \"type\": \"text\",\n" +
" \"analyzer\": \"ik_max_word\"\n" +
" }\n" +
" }\n" +
" }\n" +
"}";
}
索引库(index)操作
为了后面操作方便,把RestHighLevelClient的定义、创建、关闭放在方法外面,以下操作都是在测试类中实现;
/**
* 定义连接
*/
private RestHighLevelClient client;
/**
* 初始化客户端
*/
@BeforeEach
public void init(){
client = new RestHighLevelClient(RestClient.builder(HttpHost.create("http://192.168.126.128:9200")));
}
/**
* 关闭客户端
* @throws IOException
*/
@AfterEach
public void close() throws IOException {
client.close();
}
创建索引库
/**
* 创建索引
*/
@Test
public void addIndex() throws IOException {
// 1.创建请求
CreateIndexRequest createIndexRequest = new CreateIndexRequest("student");
// 2.编写DSL语句
createIndexRequest.source(CREATE_INDEX_STRING, XContentType.JSON);
// 3.发起请求
client.indices().create(createIndexRequest, RequestOptions.DEFAULT);
}
执行成功
到ikbana上看下,索引库已经创建完成
获取索引库
/**
* 获取索引库
* @throws IOException
*/
@Test
public void getIndex() throws IOException {
// 1.创建请求
GetIndexRequest getIndexRequest = new GetIndexRequest("student");
// 2.发起请求
boolean exists = client.indices().exists(getIndexRequest, RequestOptions.DEFAULT);
System.out.println("exists = " + exists);
}
此方法返回结果为boolean类型,仅可知该索引库是否存在;
删除索引库
/**
* 删除索引库
* @throws IOException
*/
@Test
public void deleteIndex() throws IOException {
// 1. 创建请求
DeleteIndexRequest deleteIndexRequest = new DeleteIndexRequest("student");
// 2. 发起请求
client.indices().delete(deleteIndexRequest,RequestOptions.DEFAULT);
}
删除索引库成功;
再次获取索引库,返回false;
小结
索引库没有修改操作
文档(document)操作
再提一次,文档操作等同于数据库的数据操作,即类比数据的CRUD操作;
新增文档
注意,因为数据库中查询到的记录与ES的文档的字段并不是一一对应的,需要再创建一个对象来进行拼凑;
(Student类)
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.io.Serializable;
@Data
@TableName("tb_student")
public class Student implements Serializable {
private Integer id;
private String username;
private String password;
private String name;
private Integer gender;
private String image;
private Integer job;
private String entryDate;
private String createTime;
private String updateTime;
}
(StudentDoc类,与ES文档一一对应)
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
@Data
@NoArgsConstructor
public class StudentDoc implements Serializable {
private Integer id;
private String username;
private String password;
private String name;
private Integer gender;
private String image;
private Integer job;
private String joinInfo;
private String updateTime;
public StudentDoc(Student student) {
this.id = student.getId();
this.username = student.getUsername();
this.password = student.getPassword();
this.name = student.getName();
this.gender = student.getGender();
this.image = student.getImage();
this.job = student.getJob();
this.joinInfo = "[创建日期:" + student.getCreateTime() + "], [加入日期:" + student.getEntryDate() +"]";
this.updateTime = student.getUpdateTime();
}
}
/**
* 新增文档(数据来自数据库,然后新增到ES)
*/
@Test
public void addDoc() throws IOException {
// 1.查询数据(ID为1的记录)
Student student = studentService.getById(1);
// 1.1 拼凑文档
StudentDoc studentDoc = new StudentDoc(student);
// 2.创建请求
IndexRequest request = new IndexRequest("student").id(student.getId().toString());
// 3.编写DSL语句
request.source(JSON.toJSONString(studentDoc),XContentType.JSON);
// 4.发送请求
client.index(request,RequestOptions.DEFAULT);
}
执行完成;
查看kibana平台,输入命令,可以查到对应的文档,说明新增文档成功;
查询文档
/**
* 查询文档
*/
@Test
public void getDoc() throws IOException {
// 1.创建请求,查询ID为1的文档
GetRequest request = new GetRequest("student").id("1");
// 2.发送请求
GetResponse response = client.get(request, RequestOptions.DEFAULT);
// 3.获取返回值
String json = response.getSourceAsString();
// 4.解析返回值为java对象
StudentDoc studentDoc = JSON.parseObject(json, StudentDoc.class);
System.out.println("studentDoc = " + studentDoc);
}
查询完成;
删除文档
/**
* 删除文档
*/
@Test
public void delDoc() throws IOException {
// 1.创建请求,删除ID为1的文档
DeleteRequest request = new DeleteRequest("student").id("1");
// 2.发起请求
client.delete(request, RequestOptions.DEFAULT);
}
执行完成;
再次查询,结果为null(注意,并不会报错);
更新文档
更新文档由两种方式,第一种是全局更新,其实也就是新增文档,代码是一样的,第二种是局部更新,代码如下:
/**
* 更新文档(方式二:局部更新)
*/
@Test
public void updateDoc() throws IOException {
// 1.创建请求,修改ID为1的文档
UpdateRequest request = new UpdateRequest("student","1");
// 2.指定要修改的字段
request.doc("name","徐志摩",
"username","xuzhimo");
// 3.发送请求
client.update(request,RequestOptions.DEFAULT);
}
执行完成;
再次查找ID为1的文档,可以看到文档已更新;
批量导入文档
批量将数据库中的对象数据,导入到ES上;
/**
* 批量导入文档(数据从数据库中查询获取)
*/
@Test
public void addDocs() throws IOException {
// 1.获取所有学生的数据
List<Student> students = studentService.list();
// 2.创建Bulk请求
BulkRequest bulkRequest = new BulkRequest();
// 3.添加数据到Bulk中
for (Student student : students) {
// 3.1 创建Doc对象
StudentDoc studentDoc = new StudentDoc(student);
// 3.2 创建新增文档请求并将Doc对象放入
bulkRequest.add(new IndexRequest("student").id(studentDoc.getId().toString())
.source(JSON.toJSONString(studentDoc),XContentType.JSON));
}
// 4.发送请求
client.bulk(bulkRequest,RequestOptions.DEFAULT);
}
执行完成,没有报错;
随便查找两条记录,可以看到都已经添加了进来;
总结
对于索引库的操作,请求是XxxIndexRequest(“索引库名”),创建是Create,删除是Delete,获取是Get(发起请求,方法名是exists);
对于文档的操作,请求是XxxRequest(“索引库名”,“ID”),新增是Index,删除是Delete,查询是Get,修改是Update,另外还有个批量的操作,是BulkRequest;