一 初识elasticsearch

1.什么是elasticsearch?

elasticsearch是一款非常强大的开源搜索引擎,可以帮助我们从海量数据中快速找到需要的内容。

elasticsearch结合kibanaLogstashBeats,也就是elastic stack(ELK)。被广泛应用在日志数据分析、实时监控等领域。

elasticsearchelastic stack(ELK)的核心,负责存储、搜索分析数据。

elasticsearch结构

2.elasticsearch的发展

Lucene是一个Java语言的搜索引擎类库,是Apache公司的顶级项目,由DougCutting于1999年研发。
官网地址https://lucene.apache.org/

Lucene的优势:

  • 易拓展
  • 高性能(基于倒排索引)

Lucene的缺点:

  • 只限于Java语言开发
  • 学习曲线陡峭
  • 不支持水平拓展

2004年Shay Banon基于Lucene开发了Compass

2010年Shay Banon重写了Compass,取名为Elasticsearch官网地址: https://www.elastic.co/cn/

相比与lucene,elasticsearch具备下列优势:

  • 支持分布式,可水平扩展
  • 提供Restful接口,可被任何语言调用

3.为什么学习elasticsearch?

搜索引擎技术排名:

  • 1.Elasticsearch:开源的分布式搜索引擎
  • 2.Splunk:商业项目
  • 3.SolrApache的开源搜索引擎

4.正向索引和倒排索引

传统数据库(如MySQL)采用正向索引,例如给下表(tb_goods)中的id创建索引:

正向索引

倒排索引:

  • 文档(document):每条数据就是一个文档
  • 词条(term):文档按照语义分成的词语

倒排索引1

倒排索引2

5.与MySQL的对比

文档

elasticsearch是面向文档存储的,可以是数据库中的一条商品数据,一个订单信息。文档数据会被序列化为json格式后存储在elasticsearch中。

文档

索引

  • 索引(index):相同类型的文档的集合
  • 映射(mapping):索引中文档的字段约束信息,类似表的结构约束

索引

概念对比

MySQL Elasticsearch 说明
Table Index 索引(index),就是文档的集合,类似数据库的表(table)
Row Document 文档(Document),就是一条条的数据,类似数据库中的行(Row),文档都是JSON格式
Column Field 字段(Field),就是JSON文档中的字段,类似数据库中的列(Column)
Schema Mapping DSL是elasticsearch提供的JSON风格的请求语句,用来操作的表结构( Schema)
SQL DSL DSL是elasticsearch提供的JSON风格的请求语句,用来操作elasticsearch,实现CRUD

架构

MySql:擅长事务类型操作,确保数据的安全和一致性

Elasticsearch:擅长海量数据的搜索、分析、计算

架构

二 安装elasticsearch

1.单点部署es

(1)创建网络

1
docker network create es-net

(2)加载镜像

1
2
3
docker pull elasticsearch
# 图形化插件
docker pull kibana

(3)运行

1
2
3
4
5
6
7
8
9
10
11
docker run -d \
--name es\
-e "ES_JAVA_OPTS=-Xms512m -Xmx512m" \
-e "discovery.type=single-node" \
-v es-data:/usr/share/elasticsearch/data \
-v es-plugins:/usr/share/elasticsearch/plugins \
--privileged \
--network es-net\
-p 9200:9200 \
-p 9300:9300 \
elasticsearch:7.12.1

2.单点部署kibana

运行docker命令,部署kibana

1
2
3
4
5
6
docker run -d \
--name kibana \
-e ELASTICSEARCH_HOSTS=http://es:9200 \
--network=es-net \
-p 5601:5601 \
kibana:7.12.1

三 分词器

1.为什么要分词器?

es在创建倒排索引时,需要对文档分词;在搜索时,需要对用户输入内容分词。但默认的分词规则对中文处理并不友好。

kibanaDevTools中测试:

1
2
3
4
5
6
POST /_analyze
{
"analyzer": "standard",
"text": "你的java真是太棒了!"
}

语法说明:

  • POST:请求方式
  • /_analyze:请求路径,这里省略了http://192.168.127.131:9200,有kibana帮我们补充
  • 请求参数,json风格:
    语法说明:
    • analyzer:分词器类型,这里是默认的standard分词器
    • text:要分词的内容

2.中文分词IK分词器安装

处理中文分词,一般会使用IK分词器。https://github.com/medcl/elasticsearch-analysis-ik

安装ik插件(在线较慢)

1
2
3
4
5
6
7
8
9
# 进入让其内部
docker exec -it elasticsearch /bin/bash

# 在线下载并安装
./bin/elasticsearch-plugin install https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v7.12.1/elasticsearch-analysis-ik-7.12.1.zip
# 退出
exit
# 重启容器
docker restart elasticsearch

离线安装

  1. 查看数据卷目录

安装插件需要知道elasticsearchplugins目录位置,而我们用了数据卷挂载,因此需要查看elasticsearch的数据卷目录,通过下面命令查看:

1
docker volume inspect es-plugins
  1. 上传ik分词器文件夹并命名为ik
  2. 重启容器
1
2
3
4
# 重启容器
docker restart es
# 查看es日志
docker logs -f es

4)测试

IK分词器包含两者模式:

  • ik_smart: 最少切分
  • ik_max_word:最细切分

3.拓展词库

要扩展ik分词器的词库,只需要修改一个ik分词器目录中的config目录的IKAnalyzer.cfg.xml文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
<properties>
<comment>IK Analyzer 扩展配置</comment>
<!--用户可以在这里配置自己的扩展字典 -->
<entry key="ext_dict">ext.dic</entry>
<!--用户可以在这里配置自己的扩展停止词字典-->
<entry key="ext_stopwords"></entry>
<!--用户可以在这里配置远程扩展字典 -->
<!-- <entry key="remote_ext_dict">words_location</entry> -->
<!--用户可以在这里配置远程扩展停止词字典-->
<!-- <entry key="remote_ext_stopwords">words_location</entry> -->
</properties>

3.停用词库

要禁用某些敏感词条,只需要修改修改一个ik分词器目录中的config目录的IKAnalyzer.cfg.xml文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
<properties>
<comment>IK Analyzer 扩展配置</comment>
<!--用户可以在这里配置自己的扩展字典 -->
<entry key="ext_dict"></entry>
<!--用户可以在这里配置自己的扩展停止词字典-->
<entry key="ext_stopwords">stopword.dic</entry>
<!--用户可以在这里配置远程扩展字典 -->
<!-- <entry key="remote_ext_dict">words_location</entry> -->
<!--用户可以在这里配置远程扩展停止词字典-->
<!-- <entry key="remote_ext_stopwords">words_location</entry> -->
</properties>

四 索引库操作

1.mapping映射

mapping属性

mapping是对索引库中文档的约束,常见的mapping属性包括:

  • type:字段数据类型,常见的简单类型有:
    • 字符串: text(可分词的文本)keyword(精确值,例如:品牌、国家、IP地址)
    • 数值:longintegershortbytedoublefloat
    • 布尔:boolean
    • 日期:date
    • 对象:object
  • index:是否创建索引,默认为true
  • analyzer:使用哪种分词器
  • properties:该字段的子字段

2.创建索引库

ES中通过Restful请求操作索引库、文档。请求内容用DSL语句来表示。创建索引库和mapping的DSL语法如下:
中通过RESTful请求操作索引库、文档.请求内容用DSL语句来表示.创建索引库和映射的DSL语法如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
PUT /索引库名称
{
"mapprings":{
"properties": {
"字段名": {
"type": "text",
"analyzer": "ik_smart"
},
"字段名2": {
"type": "keyword",
"index": false
},
"字段名3": {
"properties": {
"子字段": {
"type": "keyword"
}
}
}
}
}
}

# 创建索引库
PUT /test
{
"mappings": {
"properties": {
"info": {
"type": "text",
"analyzer": "ik_smart"
},
"email": {
"type": "keyword",
"index": false
},
"name": {
"type": "object",
"properties": {
"firstName": {
"type": "keyword"
},
"lastName": {
"type": "keyword"
}
}
}
}
}

3.查询、删除索引库

查看索引库语法:

1
2
3
GET /索引库名
# 示例
GET /test

删除索引库语法:

1
2
3
DELETE /索引库名
# 示例
DELETE /test

4.修改索引库

索引库和mapping一旦创建无法修改,但是可以添加新的字段,语法如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
PUT /索引库名/_mapping
{
"properties": {
"新字段名": {
"type": "integer"
}
}
}
# 示例
# 修改索引库
PUT /test/_mapping
{
"properties": {
"age": {
"type": "integer"
}
}

五 文档操作

1.新增文档

新增文档的DSL语法如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
POST /索引库名/_doc/文档id
{
"字段1": "值1",
"字段2": "值2",
"字段3": {
"子属性1": "值3",
"子属性2": "值4",
}
}
# 示例
POST /test/_doc/1
{
"info": "Java讲师",
"email": "hh@163.com",
"name": {
"firstName": "云",
"lastName": "赵"
}
}

2.查询删除文档

查看文档语法:

1
2
3
GET /索引库名/_doc/文档id
# 示例
GET /test/_doc/1

删除文档语法:

1
2
3
DELETE /索引库名/_doc/文档id
# 示例
DELETE /test/_doc/1

3.修改文档

方式一: 全量修改,会删除旧文档,添加新文档

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
PUT /索引库名/_doc/文档id
{
"字段1": "值1",
"字段2": "值2",
"字段3": {
"子属性1": "值3",
"子属性2": "值4",
}
}
# 示例
PUT /test/_doc/1
{
"info": "Java讲师",
"email": "hh@163.com",
"name": {
"firstName": "云",
"lastName": "赵"
}
}

方式二: 增量修改,修改指定字段

1
2
3
4
5
6
7
8
9
10
11
12
13
POST /test/_doc/1
{
"doc": {
"字段名": "新的值"
}
}
# 示例
POST /heima/_doc/1
{
"doc": {
"email": "ZY@163.com"
}
}

六 RestClient操作索引

1.什么是RestClient?

ES官方提供了各种不同语言的客户端,用来操作ES。
这些客户端的本质就是组装DSL语句,通过http请求发送给ES。
官方文档地址: https://www.elastic.co/guide/en/elasticsearch/client/index.html

2.RestClient操作案例

案例: 利用JavaRestClient实现创建、删除索引库,判断索引库是否存在

根据课前资料提供的酒店数据创建索引库,索引库名为hotelmapping属性根据数据库结构定义。

基本步骤如下:

  • 1.导入课前资料Demo

  • 2.分析数据结构,定义mapping属性

    • mapping要考虑的问题:字段名、数据类型、是否参与搜索、是否分词、如果分词,分词器是什么?

    tip:ES中支持两种地理坐标数据类型:

    geo_point:由纬度( latitude)和经度(lorhgitude)确定的一个点。例如:“32.8752345,120.2981576”

    geo_shape:有多个geo_point组成的复杂几何图形。例如一条直线,“LINESTRING(-77.03653 38.897676,-77.009051 38.889939)”

    tip: 字段拷贝可以使用copy_to属性将当前字段拷贝到指定字段示例:
    copy_to字段

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
# 酒店的mapping
PUT /hotel
{
"mappings": {
"properties": {
"id": {
"type": "keyword"
},
"name": {
"type": "text",
"analyzer": "ik_max_word",
"copy_to": "all"
},
"address": {
"type": "keyword",
"index": false
},
"price": {
"type": "integer"
},
"score": {
"type": "integer"
},
"brand": {
"type": "keyword",
"copy_to": "all"
},
"city": {
"type": "keyword"
},
"starName": {
"type": "keyword"
},
"business": {
"type": "keyword",
"copy_to": "all"
},
"location": {
"type": "geo_point"
},
"pic": {
"type": "keyword",
"index": false
},
"all": {
"type": "text",
"analyzer": "ik_max_word"
}
}
}
}
  • 3.初始化JavaRestClient

    (1)引入es的es的RestHighLevelClient依赖:与服务端版本保持一致

1
2
3
4
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-high-level-client</artifactId>
</dependency>

(2)因为SpringBoot默认的ES版本是7.6.2所以我们要覆盖默认的ES版本

1
2
3
4
<properties>
<java.version>1.8</java.version>
<elasticsearch.version>7.12.1</elasticsearch.version>
</properties>

(3)初始化RestHighLevelClient

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
package cn.itcast.hotel;

import org.apache.http.HttpHost;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestHighLevelClient;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import java.io.IOException;

public class HotelIndexTest {
private RestHighLevelClient client;

@Test
void testInit() {
System.out.println(client);
}

@BeforeEach
void setUp() {
this.client = new RestHighLevelClient(RestClient.builder(
HttpHost.create("http://192.168.127.131:9200")
// 集群可写多个
// HttpHost.create("http://192.168.127.131:9200"),
// HttpHost.create("http://192.168.127.131:9200")
));
}

@AfterEach
void tearDown() throws IOException {
this.client.close();
}
}

  • 4.利用JavaRestClient创建索引库

创建索引库代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
package cn.itcast.hotel;

import cn.itcast.hotel.constants.HotelConstants;
import org.apache.http.HttpHost;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.indices.CreateIndexRequest;
import org.elasticsearch.common.xcontent.XContentType;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import java.io.IOException;

import static cn.itcast.hotel.constants.HotelConstants.MAPPING_TEMPLATE;

public class HotelIndexTest {
private RestHighLevelClient client;

@Test
void testInit() {
System.out.println(client);
}

@Test
void createHotelIndex() throws IOException {
// 1.创建Request对象
CreateIndexRequest request = new CreateIndexRequest("hotel");
// 2.准备请求的参数:DSL语句
request.source(MAPPING_TEMPLATE, XContentType.JSON)
// 3.发送请求
client.indices().create(request, RequestOptions.DEFAULT)
}

@BeforeEach
void setUp() {
this.client = new RestHighLevelClient(RestClient.builder(
HttpHost.create("http://192.168.127.131:9200")
// 集群可写多个
// HttpHost.create("http://192.168.127.131:9200"),
// HttpHost.create("http://192.168.127.131:9200")
));
}

@AfterEach
void tearDown() throws IOException {
this.client.close();
}
}

  • 5.利用JavaRestClient删除索引库
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
package cn.itcast.hotel;

import org.apache.http.HttpHost;
import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.indices.CreateIndexRequest;
import org.elasticsearch.common.xcontent.XContentType;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import java.io.IOException;

import static cn.itcast.hotel.constants.HotelConstants.MAPPING_TEMPLATE;

public class HotelIndexTest {
private RestHighLevelClient client;

@Test
void testInit() {
System.out.println(client);
}

@Test
void testDeleteHotelIndex() throws IOException {
// 1.创建Request对象
DeleteIndexRequest request = new DeleteIndexRequest("hotel");
// 3.发送请求
client.indices().delete(request, RequestOptions.DEFAULT);
}

@BeforeEach
void setUp() {
this.client = new RestHighLevelClient(RestClient.builder(
HttpHost.create("http://192.168.127.131:9200")
// 集群可写多个
// HttpHost.create("http://192.168.127.131:9200"),
// HttpHost.create("http://192.168.127.131:9200")
));
}

@AfterEach
void tearDown() throws IOException {
this.client.close();
}
}

  • 6.利用JavaRestClient判断索引库是否存在
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
package cn.itcast.hotel;

import org.apache.http.HttpHost;
import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.indices.CreateIndexRequest;
import org.elasticsearch.common.xcontent.XContentType;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import java.io.IOException;

import static cn.itcast.hotel.constants.HotelConstants.MAPPING_TEMPLATE;

public class HotelIndexTest {
private RestHighLevelClient client;

@Test
void testInit() {
System.out.println(client);
}

@Test
void testGetHotelIndex() throws IOException {
// 1.创建Request对象
GetIndexRequest request = new GetIndexRequest("hotel");
// 2.发送请求
boolean exists = client.indices().exists(request, RequestOptions.DEFAULT);
System.out.println(exists ? "索引库已经存在" : "索引库不存在");
}

@BeforeEach
void setUp() {
this.client = new RestHighLevelClient(RestClient.builder(
HttpHost.create("http://192.168.127.131:9200")
// 集群可写多个
// HttpHost.create("http://192.168.127.131:9200"),
// HttpHost.create("http://192.168.127.131:9200")
));
}

@AfterEach
void tearDown() throws IOException {
this.client.close();
}
}

七 RestClient操作文档

1.RestClient操作文档案例

案例: 利用JavaRestClient实现文档的CRUD

去数据库查询酒店数据,导入到hotel索引库,实现酒店数据的CRUD。

基本步骤如下:

  • 1.初始化JavaRestClient

新建一个测试类,实现文档相关操作,并且完成JavaRestClient的初始化(与索引操作相同)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
package cn.itcast.hotel;

import org.apache.http.HttpHost;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestHighLevelClient;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;

import java.io.IOException;

public class HotelDocumentTest {
private RestHighLevelClient client;


@BeforeEach
void setUp() {
this.client = new RestHighLevelClient(RestClient.builder(
HttpHost.create("http://192.168.127.132:9200")
// 集群可写多个
// HttpHost.create("http://192.168.127.131:9200"),
// HttpHost.create("http://192.168.127.131:9200")
));
}

@AfterEach
void tearDown() throws IOException {
this.client.close();
}
}

  • 2.利用JavaRestClient新增酒店数据

先查询酒店数据,然后给这条数据创建倒排索引,即可完成添加

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
package cn.itcast.hotel;

import cn.itcast.hotel.pojo.Hotel;
import cn.itcast.hotel.pojo.HotelDoc;
import cn.itcast.hotel.service.IHotelService;
import com.alibaba.fastjson.JSON;
import org.apache.http.HttpHost;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.xcontent.XContentType;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.io.IOException;

@SpringBootTest
public class HotelDocumentTest {
private RestHighLevelClient client;

@Autowired
private IHotelService hotelService;

@Test
void testAddDocument() throws IOException {

// 根据id查询酒店数据
Hotel hotel = hotelService.getById(61083L);
HotelDoc hotelDoc = new HotelDoc(hotel);
// 1. 准备Request对象
IndexRequest request = new IndexRequest("hotel").id(hotelDoc.getId().toString());
// 2. 准备json文档
request.source(JSON.toJSONString(hotelDoc), XContentType.JSON);
// 3. 发送请求
client.index(request, RequestOptions.DEFAULT);
}

@BeforeEach
void setUp() {
this.client = new RestHighLevelClient(RestClient.builder(
HttpHost.create("http://192.168.127.132:9200")
// 集群可写多个
// HttpHost.create("http://192.168.127.131:9200"),
// HttpHost.create("http://192.168.127.131:9200")
));
}

@AfterEach
void tearDown() throws IOException {
this.client.close();
}
}

  • 3.利用JavaRestClient根据id查询酒店数据

根据id查询到的文档数据是json,需要反序列化为java对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
package cn.itcast.hotel;

import cn.itcast.hotel.pojo.Hotel;
import cn.itcast.hotel.pojo.HotelDoc;
import cn.itcast.hotel.service.IHotelService;
import com.alibaba.fastjson.JSON;
import org.apache.http.HttpHost;
import org.elasticsearch.action.get.GetRequest;
import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.xcontent.XContentType;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.io.IOException;

@SpringBootTest
public class HotelDocumentTest {
private RestHighLevelClient client;

@Autowired
private IHotelService hotelService;

@Test
void testGetDocumentById() throws IOException {
// 1. 准备Request
GetRequest request = new GetRequest("hotel", "61083");
// 2. 发送请求,得到响应
GetResponse response = client.get(request, RequestOptions.DEFAULT);
// 3. 解析响应结构
String json = response.getSourceAsString();
HotelDoc hotelDoc = JSON.parseObject(json, HotelDoc.class);
System.out.println(hotelDoc);

}

@BeforeEach
void setUp() {
this.client = new RestHighLevelClient(RestClient.builder(
HttpHost.create("http://192.168.127.132:9200")
// 集群可写多个
// HttpHost.create("http://192.168.127.131:9200"),
// HttpHost.create("http://192.168.127.131:9200")
));
}

@AfterEach
void tearDown() throws IOException {
this.client.close();
}
}

  • 4.利用JavaRestClient修改酒店数据

方式一: 全量修改,会删除旧文档,添加新文档
方式二: 增量修改,修改指定字段

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
// 方式2,方式一与新增同
package cn.itcast.hotel;

import cn.itcast.hotel.pojo.Hotel;
import cn.itcast.hotel.pojo.HotelDoc;
import cn.itcast.hotel.service.IHotelService;
import com.alibaba.fastjson.JSON;
import org.apache.http.HttpHost;
import org.elasticsearch.action.get.GetRequest;
import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.xcontent.XContentType;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.io.IOException;

@SpringBootTest
public class HotelDocumentTest {
private RestHighLevelClient client;

@Autowired
private IHotelService hotelService;


@Test
void testUpdateDocumentById() throws IOException {
// 1. 准备request对象
UpdateRequest request = new UpdateRequest("hotel", "61083");
// 2. 准备请求参数
request.doc(
"price", "952",
"startName", "四钻"
);
// 3. 发送请求
client.update(request, RequestOptions.DEFAULT);
}

@BeforeEach
void setUp() {
this.client = new RestHighLevelClient(RestClient.builder(
HttpHost.create("http://192.168.127.132:9200")
// 集群可写多个
// HttpHost.create("http://192.168.127.131:9200"),
// HttpHost.create("http://192.168.127.131:9200")
));
}

@AfterEach
void tearDown() throws IOException {
this.client.close();
}
}

  • 5.利用JavaRestClient删除酒店数据
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
package cn.itcast.hotel;

import cn.itcast.hotel.pojo.Hotel;
import cn.itcast.hotel.pojo.HotelDoc;
import cn.itcast.hotel.service.IHotelService;
import com.alibaba.fastjson.JSON;
import org.apache.http.HttpHost;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.xcontent.XContentType;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.io.IOException;

@SpringBootTest
public class HotelDocumentTest {
private RestHighLevelClient client;
@Test
void testDeleteDocument() throws IOException {
// 1. 准备request对象
DeleteRequest request = new DeleteRequest("hotel", "61083");
// 2. 发送请求
client.delete(request, RequestOptions.DEFAULT);
}

@BeforeEach
void setUp() {
this.client = new RestHighLevelClient(RestClient.builder(
HttpHost.create("http://192.168.127.132:9200")
// 集群可写多个
// HttpHost.create("http://192.168.127.131:9200"),
// HttpHost.create("http://192.168.127.131:9200")
));
}

@AfterEach
void tearDown() throws IOException {
this.client.close();
}
}

八 JavaRestClient批量导入数据

利用JavaRestClient批量导入酒店数据到ES

案例 利用JavaRestClient批量导入酒店数据到ES

需求: 批量查询酒店数据,然后批量导入索引库中

思路:

  • 1.利用mybatis-plus查询酒店数据
  • 2.将查询到的酒店数据(Hotel)转换为文档类型数据(HotelDoc)
  • 3.利用JavaRestClient中的Bulk批处理,实现批量新增文档
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
package cn.itcast.hotel;

import cn.itcast.hotel.pojo.Hotel;
import cn.itcast.hotel.pojo.HotelDoc;
import cn.itcast.hotel.service.IHotelService;
import com.alibaba.fastjson.JSON;
import org.apache.http.HttpHost;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.get.GetRequest;
import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.xcontent.XContentType;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.io.IOException;
import java.util.List;

@SpringBootTest
public class HotelDocumentTest {
private RestHighLevelClient client;

@Autowired
private IHotelService hotelService;

@Test
void testBulkRequest() throws IOException {

// 批量查询酒店数据
List<Hotel> hotels = hotelService.list();

// 1. 创建Request
BulkRequest request = new BulkRequest();
// 2. 准备参数,添加多个新增的Request
for (Hotel hotel : hotels) {
// 转换为文档类型HotelDoc
HotelDoc hotelDoc = new HotelDoc(hotel);
// 创建新增文档Request对象
request.add(new IndexRequest("hotel")
.id(hotel.getId().toString())
.source(JSON.toJSONString(hotelDoc), XContentType.JSON));
}
// 3. 发送请求
client.bulk(request, RequestOptions.DEFAULT);
}

@BeforeEach
void setUp() {
this.client = new RestHighLevelClient(RestClient.builder(
HttpHost.create("http://192.168.127.132:9200")
// 集群可写多个
// HttpHost.create("http://192.168.127.131:9200"),
// HttpHost.create("http://192.168.127.131:9200")
));
}

@AfterEach
void tearDown() throws IOException {
this.client.close();
}
}