SpringBoot集成ES
版权申明:本文为原创文章,转载请注明原文出处
elasticsearch被广泛用于分布式的全文检索,本文将介绍如何在Spring Boot项目中集成使用ES
软件版本信息
- SpringBoot:
2.3.0.RELEASE
- elasticsearch:
7.6.2
- ik分词器:
7.6.2
注意:ik分词器的版本必须和ES版本保持一致,否则会启动报错的。
创建Spring Boot项目
利用IDEA创建Spring Boot项目,选择如下三个依赖Lombok(可选)、Web、ES
或者也可以用手动添加pom依赖:
1 |
|
指定ES集群
Elasticsearch 7中TransportClient
被标记为了过时,并且未来就在Elasticsearch 8中移除,官网强烈推荐我们使用High Level REST Client
来连接到ES集群(参考官网文档:官网说明)。所以我们不推荐使用过时的spring.data.elasticsearch.cluster-name
来指定ES集群,而是使用Java Bean的方式来创建一个连接ES的客户端。创建一个EsConfig类,内容如下:
1 | package com.itf.demo.es; |
到此,我们的Spring Boot就完成了ES的集成。
ES相关操作功能
创建一个EsDemoController,提供创建索引、新建文档、检索文档三个功能。内容如下:
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
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148package com.itf.demo.es;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.indices.CreateIndexRequest;
import org.elasticsearch.client.indices.CreateIndexResponse;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.index.query.MultiMatchQueryBuilder;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author ye17186
* @date 2020-05-27
*/
public class EsDemoController {
/**
* ik分词器配置文件
*/
private static final String IK_SETTINGS_FILE = "es-index-settings-ik.yml";
private static final String DOC_FIELD_TITLE = "title";
private static final String DOC_FIELD_CONTENT = "content";
private static final String DOC_FIELD_DESCRIPTION = "description";
private static final String HIGHLIGHT_PRE_TAG = "<span class=\"highlight\">";
private static final String HIGHLIGHT_POST_TAG = "</span>";
RestHighLevelClient client;
/**
* 创建索引
*
* @param addIndexRequest 请求体
* @return 创建结果
* @throws IOException es异常
*/
public CreateIndexResponse index( AddIndexRequest addIndexRequest)throws IOException {
CreateIndexRequest request = new CreateIndexRequest(addIndexRequest.getIndex());
if (addIndexRequest.getIk()) {
Settings settings = Settings.builder().loadFromStream(IK_SETTINGS_FILE, new ClassPathResource(IK_SETTINGS_FILE).getInputStream(), true).build();
request.settings(settings);
}
return client.indices().create(request, RequestOptions.DEFAULT);
}
/**
* 新建一个文档
*
* @param addRequest 请求体
* @return 新建结果
* @throws IOException es异常
*/
public AddDocResponse doc( AddDocRequest addRequest)throws IOException {
Map<String, String> doc = new HashMap<>();
doc.put(DOC_FIELD_TITLE, addRequest.getDoc().getTitle());
doc.put(DOC_FIELD_CONTENT, addRequest.getDoc().getContent());
doc.put(DOC_FIELD_DESCRIPTION, addRequest.getDoc().getDescription());
IndexRequest request = new IndexRequest().index(addRequest.getIndex()).source(doc);
IndexResponse result = client.index(request, RequestOptions.DEFAULT);
AddDocResponse response = new AddDocResponse();
response.setId(result.getId());
response.setIndex(result.getIndex());
return response;
}
/**
* 搜索文档
*
* @param searchDocRequest 搜索对象
* @return 文档列表
* @throws IOException es异常
*/
public List<DemoDoc> search(SearchDocRequest searchDocRequest) throws IOException {
SearchSourceBuilder builder = new SearchSourceBuilder();
// 1、构造查询条件(只搜索标题和正文内容,不搜索文档描述)
MultiMatchQueryBuilder qBuilder = new MultiMatchQueryBuilder(searchDocRequest.getKey(), DOC_FIELD_TITLE, DOC_FIELD_CONTENT, DOC_FIELD_DESCRIPTION);
builder.query(qBuilder);
// 构建高亮效果
if (Boolean.TRUE.equals(searchDocRequest.isHighlight())) {
HighlightBuilder hBuilder = new HighlightBuilder().field(DOC_FIELD_TITLE).field(DOC_FIELD_CONTENT);
hBuilder.preTags(HIGHLIGHT_PRE_TAG);
hBuilder.postTags(HIGHLIGHT_POST_TAG);
builder.highlighter(hBuilder);
}
SearchRequest request = new SearchRequest();
request.indices(searchDocRequest.getIndex());
request.source(builder);
SearchResponse esResponse = client.search(request, RequestOptions.DEFAULT);
List<DemoDoc> list = new ArrayList<>();
esResponse.getHits().forEach(item -> {
DemoDoc doc = new DemoDoc();
Map<String, Object> docObj = item.getSourceAsMap();
doc.setEsId(item.getId());
doc.setDescription((String) docObj.get(DOC_FIELD_DESCRIPTION));
// 处理高亮结果
if (Boolean.TRUE.equals(searchDocRequest.isHighlight())) {
item.getHighlightFields().forEach((k, v) -> {
String text = v.fragments()[0].toString();
if (DOC_FIELD_TITLE.equals(k)) {
doc.setTitle(text);
} else if (DOC_FIELD_CONTENT.equals(k)) {
doc.setContent(text);
}
});
} else {
doc.setTitle((String) docObj.get(DOC_FIELD_TITLE));
doc.setContent((String) docObj.get(DOC_FIELD_CONTENT));
}
list.add(doc);
});
return list;
}
}里面有一些实体类,我们贴出来:
创建索引请求:AddIndexRequest
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23package com.itf.demo.es;
import java.io.Serializable;
import lombok.Data;
/**
* @author ye17186
* @date 2020-05-26
*/
public class AddIndexRequest implements Serializable {
private static final long serialVersionUID = -1302118006477723757L;
/**
* 索引名
*/
private String index;
/**
* 是否使用ik分词
*/
private Boolean ik;
}创建文档请求:AddDocRequest
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24package com.itf.demo.es;
import java.io.Serializable;
import lombok.Data;
/**
* @author ye17186
* @date 2020-05-26
*/
public class AddDocRequest implements Serializable {
private static final long serialVersionUID = 962783059289210959L;
/**
* es索引
*/
private String index;
/**
* 文档对象
*/
private DemoDoc doc;
}文档对象:DemoDoc
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
31package com.itf.demo.es;
import java.io.Serializable;
import lombok.Data;
/**
* @author ye17186
* @date 2020-05-27
*/
public class DemoDoc implements Serializable {
private static final long serialVersionUID = -4405978680214369148L;
private String esId;
/**
* 文档标题
*/
private String title;
/**
* 文档内容
*/
private String content;
/**
* 文档描述
*/
private String description;
}创建文档响应:AddDocResponse
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23package com.itf.demo.es;
import java.io.Serializable;
import lombok.Data;
/**
* @author ye17186
* @date 2020-05-26
*/
public class AddDocResponse implements Serializable {
private static final long serialVersionUID = 190213968835835783L;
/**
* es索引
*/
private String index;
/**
* 文档ID
*/
private String id;
}检索文档请求:SearchDocRequest
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
29package com.itf.demo.es;
import java.io.Serializable;
import lombok.Data;
/**
* @author ye17186
* @date 2020-05-26
*/
public class SearchDocRequest implements Serializable {
private static final long serialVersionUID = 3713476005328602810L;
/**
* es索引
*/
private String index;
/**
* 搜索关键字
*/
private String key;
/**
* 是否高亮
*/
private boolean highlight;
}检索文档响应:SearchDocResponse
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
30package com.itf.demo.es;
import java.io.Serializable;
import java.util.List;
import lombok.Data;
/**
* @author ye17186
* @date 2020-05-26
*/
public class SearchDocResponse implements Serializable {
private static final long serialVersionUID = -2746189513729052108L;
/**
* es索引
*/
private String index;
/**
* 搜索关键字
*/
private String key;
/**
* 匹配到的文档对象
*/
private List<DemoDoc> docs;
}验证
启动该Spring Boot项目,通过Postman等工具访问对应接口。