1.Elasticsearch 简介
Elaticsearch,简称为ES,ES是一个开源的高扩展的分布式全文检索引擎,它可以近乎实时的存储、检索数据;本身扩展性很好,可以扩展到上百台服务器,处理 PB 级别(大数据时代)的数据。ES由 Java 语言开发并使用 Lucene 作为其核心来实现所有索引和搜索的功能,但是它的目的是通过简单的 RESTFULL API 来隐藏 Lucene 的复杂性,从而让全文搜索变得简单。Logstash 负责数据的采集,处理(丰富数据,数据转型等),Kibana 负责数据展,分析及管理。Elasticsearch 处于最核心的位置,它可以帮我们对数据进行快速地搜索及分析。
2. ES 的下载安装(Linux安装)
2.1 ES 要求:JDK1.8以上!
1.查询要安装jdk的版本:
命令: yum -y list java*
2.安装jdk1.8
命令:yum install -y java-1.8.0-openjdk.x86_64
3.查询jdk版本
命令: java -version
这样就安装成功了。默认给安装到usr/lib/jvm/ 还有一种手动的
2.2下载 ES
Linux版本
下载地址: [https://www.elastic.co/cn/downloads/past-releases/elasticsearch-7-6-1]: https://www.elastic.co/cn/downloads/past-releases/elasticsearch-7-6-1
2.3 安装ES
压缩包上传
Xftp Xshell 个人免费申请
https://www.netsarang.com/zh/free-for-home-school/
通过 XFTP 这个上传到服务器或者虚拟机指定文件夹位置:
位置:/usr/local/src/software
XShell 工具连接到服务器或者虚拟机
ES解压
tar -zxvf elasticsearch-7.6.1-linux-x86_64.tar.gz
改文件夹名称,方便:mv elasticsearch-7.6.1 elaticSeach7
ES相关配置
基础配置
ES 本身相当一个数据库
elasticsearch7 文件夹创建 data
文件夹,用于存放数据:mdkir data
进入 data
文件夹给于文件夹权限,执行 pwd
data /usr/local/src/software/elaticseach7/data
ES目录介绍
bin: ES启动文件 elasticsearch.bat / elasticsearch
config:配置目录
data:数据目录
jdk,lib:java运行环境以及依懒包
logs:日志目录
modules,plugins:模块及插件目录,head插件可以存放在plugins目录下
修改配置文件elasticseach.yml
,进入 elasticseach7
的 confing
文件夹,编辑 elasticseach.yml 文件夹: vim elasticseach.yml
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2k8mxaTy-1615343315058)(C:\Users\heng\AppData\Roaming\Typora\typora-user-images\image-20210308110744983.png)]
修改完成 按 :wq
保存退出,回到elasticsearch7 文件夹, 进入 logs 文件夹, pwd
查看文件夹路径,复制
重新回到 config 目录编辑 elasticsearch.yml 文件:
- cd /usr/local/src/software/elasticsearch7/config
- vim elasticsearch.yml
跨域配置
在config目录下的elasticsearch.yml文件末尾添加跨域允许
# 跨域问题
http.cors.enabled: true
http.cors.allow-origin: "*"
http.cors.allow-headers: Authorization,X-Requested-with,Content-Length,Content-Type
配置流程参考:
3. ES 的分词器插件
ES 默认自带有分词器,只支持英文分词,需要安装中文分词插件
3.1 IK 分词器下载
IK 分词器 Github 地址:https://github.com/medcl/elasticsearch-analysis-ik
下载 等应版本:https://github.com/medcl/elasticsearch-analysis-ik/releases/tag/v7.6.1
使用 Xshell 上传 原来的位置
3.2 分词器解压
- 进入
plugins
文件夹, 新建一个ik
文件夹,用于存放IK
分词器插件:
- 回到 software 文件夹, 将 IK 分词器解压到 ik 文件夹:unzip elasticsearch-analysis-ik-7.6.1.zip -d /usr/local/src/software/elasticsearch7/plugins/ik
没有这个指令 先下载 unzip 命令 :yum install unzip zip
重新执行 :unzip elasticsearch-analysis-ik-7.6.1.zip -d /usr/local/src/software/elasticsearch7/plugins/ik
3.4 IK 分词器的配置文件
- 进入 ik 目录下的 config 目录:
- cd /usr/local/src/software/elasticsearch7/plugins/ik/config
- 查看:ll
扩展分词配置
如果出现一些网络热词,我们想对其继续分词配置,我们需要到 ik 文件夹中 config 文件夹中的IKAnalyzer.cfg.xml
去配置: vim IKAnalyzer.cfg.xml
如果需要加一些额外的网络新词,可以把这些词放到 自己新建的 ext_dict 文件中,每个词直接都要换行,就像extra_main.doc文件的格式一样就行
4.启动与关闭ES
4.1 ES 服务启动和关闭
- 进入 bin 目录: cd /usr/local/src/software/elasticsearch7/bin 再执行命令:./elasticsearch
- 运行ES服务! 后台运行命令:
./elasticsearch -d
- 关闭ES 服务: ps -ef|grep elastic
- 查看进程,
- ps -elf
- 并使用 kill -9 进程id 来结束进程
入坑一:
不能以 root 用户去启动 ES 服务
解决方案
- 新建一个用户elasticsearch,命令:
adduser elasticsearch
- 在software 目录下 赋予 elasticsearch7 这个文件夹权限给 elasticsearch 用户,命令: chown -R elasticsearch elasticsearch7
- 切换 elasticsearch 用户,使用
su elasticsearch
命令,重新回到 bin 目录执行 ES 服务‘
入坑二:
解决方案
在 elasticsearch 的 config 目录下,修改 elasticsearch.yml 配置文件
入坑三:
ERROR: [1] bootstrap checks failed
[1]: max virtual memory areas vm.max_map_count [65530] is too low, increase to at least [262144]
解决方案
- 修改配置sysctl.conf
- vim /etc/sysctl.conf
- 在最后一行添加下面配置:
- vm.max_map_count=655360
- 保存退出并执行命令:
- sysctl -p
重新启动 elasticsearch 服务
访问成功:
还有个 坑 服务器1核2G的 内存小 不能运行 需要修改
看 海贼王的 原章修改 :Linux环境下ElasticSearch的安装与使用
5.ES中基本概念
5.1关系型数据库和ES对比
Relational DB | Elasticsearch |
数据库(database) | 索引(indices) |
表(tables) | 类型(types) |
行(一条记录)(rows) | 文档(documents) |
字段(columns) | 属性(fields) |
5.2 接近实时(NRT Near Real Time)
Elasticsearch 是一个接近实时的搜索平台,从索引一个文档直到这个文档被搜索到有一个轻微的延迟(通知1秒内)
5.3 索引(index)
一个索引就是一个拥有几分相类似特征的文档的集合。比如说,你可以有一个客户数据索引,另一个产品目录的索引,还有一个订单数据的索引。一个索引由一个名字标识(必须全部是小写字母的),并且当我们要对这个索引中的文档进行索引、搜索、更新和删除的时候,都要使用到这个名字。索引类似关系型数据库Database的概念。在一个集群中,如果你想,可以定义任意多的索引。
5.4 类型(type)
在一个索引中,你可以定义一种或多种类型。一个类型是你的索引的一个逻辑的分类/分区,其语义完全由你来定。通常,会为具有一组共同字段的文档定义一个类型。假设你运营一个博客平台并且将你所有的数据存储到一个索引中。在这个索引中,你可以为用户数据定义一个类型,为博客数据定义另一个类型还有评论数据也可以定义另一个类型。类型类似于关系型数据库中Table的概念
NOTE:在5.X版本以前可以在一个索引中定义多个类型,6.X之后版本也可以使用,不推荐,在7~8.X版本中彻底移除一个索引中创建多个类型
5.5 映射(Mapping)
Mapping是ES中的一个很重要的内容,它类似于传统关系型数据中table的schema,用于定义一个索引(index)中的类型(type)的数据的结构
在ES中,我们可以手动创建type(相当于table)和mapping(相关与schema),也可以采用默认创建方式。在默认配置下,ES可以根据插入的数据自动创建type及其mapping. mapping中主要包括字段名、字段数据类型和字段索引类型
5.6 文档(document)
一个文档是一个可被索引的基础信息单元,类似于表中的一条记录。比如,你可以拥有某一个员工的文档,也可以拥有某个商品的一个文档
文档以采用了轻量级的数据交换格式JSON来表示
6. ES 常用命令
6.1索引操作
使用命令行的方式 curl 发送请求:
查看ES服务健康状态:
curl -X GET "ip地址:9200/_cat/health?v"
查看ES服务中的节点:
curl -X GET "ip地址:9200/_cat/indices?v"
查看ES服务中的所有索引:
新增索引:
curl -X PUT “ip地址:9200/myindex”
查看索引:
curl -X GET “ip地址:9200/_cat/indices?v”
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SfO5SxBy-1615343315067)(C:\Users\heng\AppData\Roaming\Typora\typora-user-images\image-20210309095222486.png)]
删除索引:
curl -X DELETE “ip地址:9200/myindex”
使用服务器 curl
手动输入请求 ES
服务不方便,所有使用Postman 请求方法
新建索引:(使用Postman)
新建文档并指定id:
PUT IP地址:9200/myindex/_doc/1
根据id查询数据:
GET IP地址:9200/myindex/_doc/1
根据id修改数据:
PUT IP地址:9200/myindex/_doc/1
根据id删除数据:
DELETE IP地址:9200/myindex/_doc/1
6.2 索引搜索
ES 添加些数据
PUT IP 地址:9200/myindex/_doc/1
{
"title":"海贼王",
"content":"船长是路飞,副船长是索隆~"
}
PUT IP 地址:9200/myindex/_doc/2
{
"title":"火影忍者",
"content":"七代火影是鸣人,八代火影是木叶丸~"
}
PUT IP 地址:9200/myindex/_doc/3
{
"title":"一拳超人",
"content":"主角是埼玉,配角是杰诺斯~"
}
PUT IP 地址:9200/myindex/_doc/4
{
"title":"进击的巨人",
"content":"人类最牛的是兵长,巨人最菜的是男主~"
}
PUT IP 地址:9200/myindex/_doc/5
{
"title":"名侦探柯南",
"content":"男主是柯南,女主不确定~"
}
PUT IP 地址:9200/myindex/_doc/6
{
"title":"海贼王路飞",
"content":"路飞是要成为海贼我的男人~"
}
PUT IP 地址:9200/myindex/_doc/7
{
"title":"路飞的果实能力",
"content":"路飞是吃了橡胶果实的男人~"
}
搜索全部
GET IP地址:9200/myindex/_search
结果:
{
"took": 100,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 7,
"relation": "eq"
},
"max_score": 1.0,
"hits": [
{
"_index": "myindex",
"_type": "_doc",
"_id": "2",
"_score": 1.0,
"_source": {
"title": "火影忍者",
"content": "七代火影是鸣人,八代火影是木叶丸~"
}
},
{
"_index": "myindex",
"_type": "_doc",
"_id": "3",
"_score": 1.0,
"_source": {
"title": "一拳超人",
"content": "主角是埼玉,配角是杰诺斯~"
}
},
{
"_index": "myindex",
"_type": "_doc",
"_id": "4",
"_score": 1.0,
"_source": {
"title": "进击的巨人",
"content": "人类最牛的是兵长,巨人最菜的是男主~"
}
},
{
"_index": "myindex",
"_type": "_doc",
"_id": "5",
"_score": 1.0,
"_source": {
"title": "名侦探柯南",
"content": "男主是柯南,女主不确定~"
}
},
{
"_index": "myindex",
"_type": "_doc",
"_id": "6",
"_score": 1.0,
"_source": {
"title": "海贼王路飞",
"content": "路飞是要成为海贼我的男人~"
}
},
{
"_index": "myindex",
"_type": "_doc",
"_id": "7",
"_score": 1.0,
"_source": {
"title": "路飞的果实能力",
"content": "路飞是吃了橡胶果实的男人~"
}
},
{
"_index": "myindex",
"_type": "_doc",
"_id": "8",
"_score": 1.0,
"_source": {
"title": "海贼王",
"content": "船长是路飞,副船长是索隆~"
}
}
]
}
}
根据单个条件搜索
GET IP地址/myindex/_search?q=title:海贼王
或者
GET IP地址/myindex/_search?q=content:路飞
结果:
{
"took": 3,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 3,
"relation": "eq"
},
"max_score": 1.9062529,
"hits": [
{
"_index": "myindex",
"_type": "_doc",
"_id": "8",
"_score": 1.9062529,
"_source": {
"title": "海贼王",
"content": "船长是路飞,副船长是索隆~"
}
},
{
"_index": "myindex",
"_type": "_doc",
"_id": "6",
"_score": 1.8387749,
"_source": {
"title": "海贼王路飞",
"content": "路飞是要成为海贼我的男人~"
}
},
{
"_index": "myindex",
"_type": "_doc",
"_id": "7",
"_score": 1.8387749,
"_source": {
"title": "路飞的果实能力",
"content": "路飞是吃了橡胶果实的男人~"
}
}
]
}
}
根据多个条件搜索
GET IP地址:9200/myindex/_search
{
"query":{
//多个匹配
"multi_match":{
//查询条件 路飞
"query":"路飞",
// 从title 和 content 字段中匹配是否存在 路飞 数据
"fields":["title","content"]
}
}
}
结果:
{
"took": 6,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 3,
"relation": "eq"
},
"max_score": 2.2700202,
"hits": [
{
"_index": "myindex",
"_type": "_doc",
"_id": "6",
"_score": 2.2700202,
"_source": {
"title": "海贼王路飞",
"content": "路飞是要成为海贼我的男人~"
}
},
{
"_index": "myindex",
"_type": "_doc",
"_id": "7",
"_score": 1.9412584,
"_source": {
"title": "路飞的果实能力",
"content": "路飞是吃了橡胶果实的男人~"
}
},
{
"_index": "myindex",
"_type": "_doc",
"_id": "8",
"_score": 1.9062529,
"_source": {
"title": "海贼王",
"content": "船长是路飞,副船长是索隆~"
}
}
]
}
}
7. SpringBoot 整合 ES
7.1 引入依赖
<!--elasticsearch 可以中文搜索-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
<version>2.2.5.RELEASE</version>
</dependency>
7.2 ES 相关配置
application.yml 中配置
spring:
thymeleaf:
mode: HTML
profiles:
active: dev
messages:
basename: i18n/messages
# elasticsearch 配置
rest:
# ip是服务器ip地址
uris: http://8.xxx.xxx.xxx:9200
# 账号 有账号密码 就配置 没有不需要
username: root
# 密码
password: @@7750731hua
7.3 相关注解介绍
ES 几个常用注解
- @Document: 声明索引库配置
- indexName:索引库名称
- type:映射类型。如果未设置,则使用小写的类简单名称(版本4.0以上 不推荐使用)
- shards: 分片数量,默认 5
- replicas: 副本数量, 默认 1
- @id:声明实体类的id
- @Field:声明字段属性
- type: 字段的数据类型
- analyzer: 指定在存储时候使用的分词类型
- searchAnalyzer:指定在搜索时候使用的分词器类型
- index: 是否创建索引
8.1 SpringBoot 实操
推荐观看海贼王文章
Spring Data 形式:SpringBoot 操作ES增删改
RestHighLevelClient 形式:SpringBoot整合ES7.6的API(RestHighLevelClient)
- 三种形式 (API使用)
- 主 RestHighLevelClient 客户端使用 加依赖就 可 使用
- 副 SpringData 也 就是 jpa形式 使用ElasticsearchRepository 调用API
- 副 Jest 也是 调用API 2018年已 停止更新 (不推荐使用)
介绍RestHighLevelClient 实操
Maven:
<!--elasticsearch 可以中文搜索-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
<version>2.2.5.RELEASE</version>
</dependency>
<!--json-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.32</version>
</dependency>
<!--lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.10</version>
</dependency>
实体类:
@Data
public class DiscussPost {
private int id;
private String blogName;
private String goods;
public DiscussPost(int id, String blogName, String goods) {
this.id = id;
this.blogName = blogName;
this.goods = goods;
}
}
测试类:
/**
* @Description: ex7.6.x客户端测试 API
*/
@SpringBootTest
public class ElasticsearchTest {
@Autowired
@Qualifier("restHighLevelClient")
private RestHighLevelClient client;
/**
* 索引创建 Request:PUT xin_index
*/
@Test
void testCreateIndex() throws IOException {
// 1.创建索引请求
CreateIndexRequest request = new CreateIndexRequest("xin_index");
// 2.执行创建请求 IndicesClient 请求后获得响应
CreateIndexResponse createIndexResponse = client.indices().create(request, RequestOptions.DEFAULT);
//输出结果
System.out.println(createIndexResponse);
}
/**
* 获取索引 GET
*/
@Test
void testExisIndex() throws IOException {
// 1.获取索引库的请求
GetIndexRequest request = new GetIndexRequest("xin_index");
// 2.执行获取索引库的请求
boolean exists = client.indices().exists(request, RequestOptions.DEFAULT);
System.out.println(exists);// 索引库存在 输出 true 否则 false
}
/**
* 删除索引 DELETE
*/
@Test
void testDeleteIndex() throws IOException {
// 1.删除索引库的请求
DeleteIndexRequest request = new DeleteIndexRequest("xin_index");
// 2.执行删除索引库的请求
AcknowledgedResponse delete = client.indices().delete(request, RequestOptions.DEFAULT);
// 输出结果
System.out.println(delete.isAcknowledged());// 删除成功输出true,否则为false
}
/**
* 添加文档
*/
@Test
void testAddDocument() throws IOException {
// 1.创建对象
DiscussPost user = new DiscussPost(4,"恒新","书");
// user.setId(1);
// user.setBlogName("恒新");
// user.setGoods("书");
// 2.创建请求
IndexRequest request = new IndexRequest("xin_index");
// 3.构建请求规则:PUT /csp_index/_doc/1
request.id("4");
request.timeout(TimeValue.timeValueSeconds(1));
//request.timeout("1s");
// 4.将user对象数据放入请求,json 数据: 需要用到fastjson
request.source(JSON.toJSONString(user), XContentType.JSON);
// 导下json依赖就用下面的
//request.source(JSON.toJSONString(user), XContentType.JSON);
// 5.客户端发送请求,获取响应的结果
IndexResponse indexResponse = client.index(request, RequestOptions.DEFAULT);
// 输出结果
// IndexResponse[index=csp_index,type=_doc,id=1,version=1,result=created,seqNo=0,primaryTerm=1,shards={"total":2,"successful":1,"failed":0}]
System.out.println(indexResponse.toString());
System.out.println(indexResponse.status());// CREATED:表示创建成功
}
/**
* 获取文档,判断是否存在
*/
@Test
void testIsExists() throws IOException {
// 1.获取文档信息请求
GetRequest getRequest = new GetRequest("xin_index","1");
// 2.执行获取文档信息的请求
GetResponse getResponse = client.get(getRequest, RequestOptions.DEFAULT);
System.out.println(getResponse.getSourceAsString());// {"DiscussPost{id=1, blogName='恒新', goods='书'}":"JSON"}
System.out.println(getResponse);
//{"_index":"xin_index","_type":"_doc","_id":"1","_version":1,"_seq_no":0,"_primary_term":1,"found":true,"_source":{"DiscussPost{id=1, blogName='恒新', goods='书'}":"JSON"}}
}
/**
* 更新文档信息
*/
@Test
void testUpdateDocument() throws IOException {
// 1.更新文档请求
UpdateRequest updateRequest = new UpdateRequest("xin_index", "1");
// 设置请求超时时间
updateRequest.timeout("1s");
// user数据对象封装到json中
DiscussPost user = new DiscussPost(3,"恒久","羽毛球");
// user.setBlogName("恒久");
// user.setGoods("羽毛球");
updateRequest.doc(JSON.toJSONString(user), XContentType.JSON);
// 2.执行更新文档请求
UpdateResponse updateResponse = client.update(updateRequest, RequestOptions.DEFAULT);
// 输出结果
System.out.println(updateResponse.status());// OK:表示更新成功
}
/**
* 删除文档记录
*/
@Test
void testDeleteDocument() throws IOException {
// 1.删除文档请求
DeleteRequest deleteRequest = new DeleteRequest("xin_index", "1");
deleteRequest.timeout("1s");
// 2.执行删除文档请求
DeleteResponse deleteResponse = client.delete(deleteRequest, RequestOptions.DEFAULT);
// 输出结果
System.out.println(deleteResponse.status());// OK:表示删除成功
}
/**
* 批量插入数据
*/
@Test
void testBulkRequest() throws IOException{
// 1.批处理请求
BulkRequest bulkRequest = new BulkRequest();
bulkRequest.timeout("10s");
// user 数据集合
ArrayList<DiscussPost> list = new ArrayList<>();
//DiscussPost user = new DiscussPost();
//DiscussPost user = new DiscussPost();
list.add(new DiscussPost(0,"路飞","恶魔果实"));
list.add(new DiscussPost(1,"索隆","剑术"));
list.add(new DiscussPost(2,"山治","厨师"));
System.out.println(list);
for (int i = 0; i < list.size(); i++) {
// 批量更新,修改,删除 都是在此进行操作
bulkRequest.add(
new IndexRequest("xin_index")
// 批量赋值文档id: 如果不在自己赋值文档id,会默认生成随机的文档id
.id("" + (i + 1))
// ArrayList转换成json
.source(JSON.toJSONString(list.get(i)), XContentType.JSON)
);
}
// 2.执行批量插入请求
BulkResponse bulkResponse = client.bulk(bulkRequest, RequestOptions.DEFAULT);
// 输出结果
System.out.println(bulkResponse.status());// OK: 表示批量插入成功!
}
/**
* ES中数据搜索
* SearchRequest 搜索请求
* SearchSourceBuilder 条件构造
* HighlightBuilder 构建高亮
* TermQueryBuilder 精确查询
* XXXQueryBuilder 构建我们需要用到的命令
*/
@Test
void testSearch() throws IOException {
// 1.创建搜索请求
SearchRequest searchRequest = new SearchRequest("xin_index");
// 2.构建搜索条件:条件构造器 SearchSourceBuilder
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
//高亮结果的条件构造器
HighlightBuilder highlightBuilder = new HighlightBuilder();
highlightBuilder.field("blogName");// 要高亮的字段
highlightBuilder.requireFieldMatch(false);//不需要多个字段高亮,如果需要设置true
highlightBuilder.preTags("<span style='color:blue'>");
highlightBuilder.postTags("</span>");
// 条件构造器,开启搜索结果高亮,并加入高亮结果的条件构造器
sourceBuilder.highlighter(highlightBuilder);
/**
* 查询条件,使用QueryBuilders工具类
* QueryBuilders.termQuery() 精确查询
* QueryBuilders.matchAllQuery() 匹配所有
*/
//TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("name", "xin");// 精确查询
//MatchAllQueryBuilder matchAllQueryBuilder = QueryBuilders.matchAllQuery();// 搜索所有数据
MatchQueryBuilder matchQueryBuilder = QueryBuilders.matchQuery("blogName", "索隆");// 搜索字段name为路飞的数据
//查询条件(matchQueryBuilder)放入条件构造器
sourceBuilder.query(matchQueryBuilder);
// 条件构造器,开启分页条件: 从第1个数据开始,每页展示5条结果数据
sourceBuilder.from(0);
sourceBuilder.size(5);
// 条件构造器,搜索请求超时时间60s
sourceBuilder.timeout(new TimeValue(60, TimeUnit.SECONDS));
// 将条件构造器放入搜索请求
searchRequest.source(sourceBuilder);
// 执行搜索请求,并获得searchResponse响应
SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
// 搜索得到的所有结果都封装在hits里面,拿数据从hits里面获取
SearchHits hits = searchResponse.getHits();
// System.out.println("-------");
// System.out.println(JSON.toJSONString(hits));
// System.out.println("-------");
// 遍历hits:解析结果,并将结果放入resultList集合
ArrayList<Map<String, Object>> resultList = new ArrayList<>();
for (SearchHit documentFields : searchResponse.getHits()) {
// 获取高亮的字段
Map<String, HighlightField> highlightFields = documentFields.getHighlightFields();
HighlightField name = highlightFields.get("blogName");// 获取高亮的字段
Map<String, Object> sourceAsMap = documentFields.getSourceAsMap();// 先获取原来未高亮的结果
// 解析高亮的字段, 将原来未高亮的title字段换成高亮的字段
if (name != null) {
Text[] fragments = name.fragments();
String newName = "";
for (Text text : fragments) {
newName += text;
}
// 高亮字段替换原来内容
sourceAsMap.put("blogName", newName);
}
resultList.add(documentFields.getSourceAsMap());
}
// 遍历resultList
resultList.forEach(item -> {
System.out.println(item);// {name=<span style='color:red'>路</span><span style='color:red'>飞</span>, age=1}
});
}
}