ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

2021最新版 ElasticSearch 7.6.1 教程详解 爬虫jsoup+es模拟京东搜索(狂神说)

2021-05-03 16:30:19  阅读:294  来源: 互联网

标签:文档 swy 索引 jsoup elasticsearch new 7.6 最新版 ElasticSearch


文章目录


相关了解:

  • es搜索 6.x 7.x 差别很大,6.x的API(原生 API,RestFul高级)
  • 应用领域很广,包括在大数据相关上面使用

一、ElasticSearch 简介

1.了解创始人 Doug Cutting

  • 1998.9.4,谷歌成立,做搜索引擎起家
  • 一位名叫 Doug Cutting 的工程师,也迷上搜索引擎,做了一个用于文本搜索的函数库,命名为 Lucene
  • Lucene 是 Java 写的,目标是各种中小型应用加入全文检索功能,好用且开源,深受程序员喜爱
  • 2001年底,Lucene 成为 Apache 软件基金会的一个子项目
  • 2004年,Doug Cutting 在 Lucene 基础上开发了开源搜索引擎,Nutch
  • Nutch 建立在 Lucene 基础上,增加了网络爬虫和网页相关功能,在业界影响力比Lucene 更大
  • 随着时间推移,无论是 谷歌还是 Nutch 都面临搜索体积不断增加的问题,谷歌开始优化自己的算法,
  • 2003年,谷歌公开介绍了自己的谷歌文件系统 GFS,这是谷歌为了存储海量搜索数据二设计的专用文件系统
  • 2004年,Doug Cutting 基于谷歌的论文,实现了分布式文件存储系统,简称 NDFS
  • 2004年,谷歌又发布论文,介绍自己的 MapReduce 编程模型,用于大规模数据集的并行分析运算
  • 2005年,Doug Cutting 又基于谷歌的 MapReduce 模型,在Nutch上实现了该功能,大大提高速度
  • 2006年,雅虎公司招了 Doug Cutting
  • Doug Cutting 加盟雅虎之后,将 NDFS 和 MapReduce 进行改造,这就是大名鼎鼎的 Hadoop
  • 2006年,谷歌又发论文了,BigTable,这是一种分布式数据存储系统,用来处理海量数据的非关系型数据库
  • Doug Cutting 当然不会错过,在自己的Hadoop系统里面引入BigTable,命名 HBase
  • 2008年1月,Hadoop 成功上位,正式成为 Apache 基金会的顶级项目

2.Lucene 简介

  • Lucene 是一套信息检索工具包,是 jar 包,不是搜索引擎系统
  • 包含:索引结构,读写索引的工具,排序,搜索规则,工具类

ElasticSearch 和 Lucene 的关系:

  • ElasticSearch 是基于 Lucene 做了一些封装和增强,上手很简单

3.ElasticSearch 简介

ElasticSearch 简称 ES,是一个开源的高扩展的分布式全文检索引擎,它可以近乎实时的存储,检索数据;本身扩展性很好,可以扩展到上百台服务器上,处理PB级别的数据。ES也是用Java开发并使用Lucene作为其核心实现所有的索引和搜索的功能,但是他的目的是通过简单的 RestFul API来隐藏Lucene的复杂性,让全文搜索变得更简单

2016年1月,ElasticSearch 超过 Solr,成为排名第一的搜索引擎应用

谁在使用:

  • 维基百科
  • The Guardian 国外新闻网站
  • Stack Over Flow
  • GitHub
  • 电商网站
  • 日志数据分析,logstash采集日志,ES进行复杂数据分析,ELK技术,ElasticSearch+logstash-kibana
  • 上平价格监控网站
  • BI系统,商业智能,比如分析某些数据趋势
  • 国内:站内搜索,电商,招聘,门户,IT系统搜索,数据分析(ES热门使用的场景)

4.ElasticSearch 和 Solr 的区别

ElasticSearch 用于 全文搜索、结构化搜索、分析

Solr 是 Apache 下的一个顶级开源项目,采用Java开发,基于 Lucene 的全文搜索服务器,Solr 提供了比 Lucene 更为丰富的查询语言,同时实现了可配置,可扩展,并对索引、搜索性能进行了优化

Solr 可以独立运行在 Jetty 等Servlet容器中,

Solr 是一个独立的企业级搜索应用服务器,实际上就是封装了 Lucene,对外提供类似于 Web-service的API接口,用户可以通过http请求,想搜索引擎服务器提交一定格式的文件,生成索引,也可以通过提出查找请求,得到结果

ElasticSearch vs Solr:

  • ES 基本是开箱即用,解压就可以使用,非常简单,Solr 的使用略复杂
  • Solr 利用 Zookeeper 进行分布式管理,ElasticSearch 自身带有分布式协调管理功能
  • Solr 支持更多格式的数据,比如,JSON,XML,CSV ,ElasticSearch 仅支持 JSON 文件格式
  • Solr 官网提供的功能更多,ElasticSearch 本身更专注核心功能,高级功能多由第三方插件提供,如图形化界面需要 kibana 友好支持
  • Solr 查询快,但更新搜索引擎慢,适合用于电商扥个查询多的应用
  • ES 建立搜索引擎模块,查询慢,即时性查询快,适用于facebook、新浪等实时搜索应用
  • Solr 是传统搜索应用的有力解决方案,但ElasticSearch 更适用于新型的实时型搜索应用
  • Solr比较成熟,有一个更大、更成熟的用户、开发贡献社区,而ElasticSearch 相对开发维护者较少,更新又太快,学习使用成本较高
  • ElasticSearch 是未来的使用趋势

5.了解ELK

ELK 是 ElasticSearch、Logstash、Kibana 三大开源框架首字母大写的简称。市面上面也称作 Elastic Stack ,其中 ElasticSearch 是一个基于 Lucene、分布式、通过 ResrFul 方式进行交互的近实时搜索平台台框架。像类似百度、谷歌这种大数据全文搜索引擎的场景都可以使用ElasticSearch 作为底层支持框架,可见 ElasticSearch 提供的搜索功能很强大。

市面上我们简称ElasticSearch 为ES。Logstash 是ELK中央数据流引擎,用于从不同目标(文件/数据存储/MQ)收集的不同格式数据,经过过滤后支持输出到不同目的地(文件/MQ/redis/elastisearch/kafka等),Kibana 可以将 ElasticSearch 的收据通过友好的界面展示出来,提供实时分析的功能。

收集清洗数据 => 搜索、存储 => Kibana

市面上很多开发,只要提高ELK都能够说出他是一个日志分析架构技术栈的总称,但实际上ELK不仅仅适用于日志分析,它还可以支持其他任何数据分析和收集的场景,日志分析和收集只是更具有代表性,并非唯一性

在这里插入图片描述
大数据:选择

二、软件安装

最低要求 JDK 1.8,maven,web 项目需要有前端环境 node.js相关

官网(比较慢):https://www.elastic.co/cn/downloads/?elektra=home&storm=hero

ElasticSearch: https://mirrors.huaweicloud.com/elasticsearch/?C=N&O=D

logstash: https://mirrors.huaweicloud.com/logstash/?C=N&O=D

可视化界面:elasticsearch-head.https://github.com/mobz/elasticsearch-head

kibana: https://mirrors.huaweicloud.com/kibana/?C=N&O=D

ik分词器 https://github.com/medcl/elasticsearch-analysis-ik

实际生产环境使用 Linux 版本,这里我们学习使用,Windows版本即可

ELK 三件套解压即可使用,

1.ElasticSearch

解压压缩包,
在这里插入图片描述
熟悉目录
在这里插入图片描述

  • bin 启动目录
  • config 配置目录
    log4j2 日志配置文件,jvm参数默认1g(内存小的需要自己配置),elasticsearch.yml 核心配置,其中默认端口9200
    在这里插入图片描述
  • lib 相关 jar 包
  • modules 功能模块
  • plugins 插件
  • logs 日志

启动:

进入bin目录,双击启动 elasticsearch.bat

如果启动成功,命令行会显示,可以访问地址为 127.0.0.1:9200,
在这里插入图片描述

访问地址可以看到json数据,表示启动成功,访问成功

在这里插入图片描述

2.ElasticSearch Head

直接查看后台json数据并不友好,我们需要使用可视化工具

elasticSearch head:https://github.com/mobz/elasticsearch-head

查看目录结构可以得知,这是一个前端项目,需要提前安装node.js

如何启动这个前端项目?查看项目说明

在这里插入图片描述
解压缩文件,进入文件根目录,执行命令行 cnpm install ,安装相关依赖,npm 会根据package.json中配置的依赖进行安装

cnpm是淘宝的镜像,安装速度更快一些
在这里插入图片描述
依赖下载成功
在这里插入图片描述
启动项目 npm run start
在这里插入图片描述
启动成功,访问 http://localhost:9100

发现页面没有数据,因为存在跨域问题,9100端口访问9200端口
在这里插入图片描述
在这里插入图片描述
配置 elasticsearch.yml 核心配置文件,添加配置,注意yml语法空格缩进

http.cors.enabled: true
http.cors.allow-origin: "*"

表示开启可以跨域访问,允许所有都可以访问,保存,关闭文件

关闭 elasticsearch ,重新启动,

先访问测试 9200端口,可以看到数据,再访问 9100,可以看到访问成功
在这里插入图片描述
界面简介:

  • 索引先简单理解为一个数据库,可以建立索引,索引中存放文档就相当于存放数据

在这里插入图片描述
未来的数据就存放在这里面
在这里插入图片描述
这个 head 我们就把他当做数据库连接工具即可,后续我们进行查询可以使用 kibana 工具,效率会更加提高很多

3.Kibana

Kibana 是一个针对 elasticsearch 的开源分析及可视化平台,用来搜索、查看交互存储在 elasticsearch 索引中的数据。使用 Kibana 可以通过各种图表进行高级数据分析及展示,Kibana 让海量数据更容易理解。它操作简单,基于浏览器的用户界面可以快速创建仪表盘(dashboard)实时显示 elasticsearch 查询动态,设置 Kibana 非常简单,无需编码或者额外的基础架构,几分钟内就可以完成 Kibana 安装并启动 elasticsearch 索引监测

官网:https://www.elastic.co/cn/downloads/?elektra=home&storm=hero

注意:Kibana 下载的版本一定要和 ElasticSearch 的版本一致

解压缩,可以看到这也是个完整的前端工程项目,

Kibana 已经包含了依赖,且有bin目录,进入bin目录,右键管理员运行 kibana.bat 文件,启动比较慢,

在这里插入图片描述
访问 5601 端口
在这里插入图片描述
访问页面测试可以使用 Postman、curl、elasticsearch-head、这里我们就使用 kibana

以后的搜索测试 请求语句 可以写在这里,通过kibana 来向搜索引擎 elasticsearch 进行查询请求
在这里插入图片描述
kibana 默认英文,如何汉化?

修改插件中的国际化设置,进入目录 kibana-7.6.1-windows-x86_64\x-pack\plugins\translations\translations,可以看到有中文的国家化文件,里面包含了中文翻译对照
在这里插入图片描述
我们修改 kibana 核心配置文件,在 kibana-7.6.1-windows-x86_64\config 目录下,kibana.yml 添加国际化配置,默认是英文

在这里插入图片描述

i18n.locale: "zh-CN"

重启 kibana,访问测试
在这里插入图片描述

三、ElasticSearch 使用详解

1.ES 核心概念

  1. 索引
  2. 字段类型(mapping)
  3. 文档(documents)

集群,节点,索引,类型,文档,分片,映射是什么?

elasticsearch是面向文档,关系型数据库和elasticsearch客观的对比!一切都是json

Relational DBElasticsearch
数据库(database)索引(indices)
表(tables)types
行(rows)documents
字段(columns)fields

在这里插入图片描述
物理设计

elasticsearch 在后台把每个索引划分成多个分片。每个分片可以在集群中的不同服务器间迁移

初始一个人就是一个集群,默认集群名字 elasticsearch
在这里插入图片描述
逻辑设计

一个索引类型中,包含多个文档,当我们索引一篇文档时,可以通过这样的一个顺序找到它:索引 => 类型 => 文档id,通过这个组合我们就能索引到某个具体的文档。注意:ID不必是整数,实际上它是一个字符串。

文档

文档就是我们的一条条的数据

之前说elasticsearch是面向文档的,那么就意味着索弓和搜索数据的最小单位是文档,,elasticsearch中,文档有几个重要属性:

  • 自我包含,一篇文档同时包含字段和对应的值,也就是同时包含 key:value !
  • 可以是层次型的,一个文档中包含自文档,复杂的逻辑实体就是这么来的! {就是一 个json对象! 可以用fastjson进行自动转换!}
  • 灵活的结构,文档不依赖预先定义的模式,我们知道关系型数据库中,要提前定义字段才能使用,在elasticsearch中,对于字段是非常灵活的,我们可以忽略某字段,或者动态的添加一个新的字段。

尽管我们可以随意的新增或者忽略某个字段,但每个字段的类型非常重要,比如一个年龄字段类型,可以是字符串也可以是整形。因为elasticsearch会保存字段和类型之间的映射及其他的设置。这种映射具体到每个映射的每种类型,这也是为什么在elasticsearch中,类型有时候也称为映射类型。

索引

索引就是数据库!

索引是映射类型的容器,elasticsearch 中的索引是一个非常大的文档集合。索|存储了映射类型的字段和其他设置。然后它们被存储到了各个分片上了。我们来研究下分片是如何工作的。

物理设计:节点和分片如何工作

一个集群至少有一 个节点,而一个节点就是一个elasricsearch进程,节点可以有多个索引默认的,如果你创建索引,那么索引将会有5个分片(primary shard,又称主分片)构成,每一个主分片会有一个副本(replica shard,又称复制分片)

在这里插入图片描述
上图是一个有3个节点的集群,可以看到主分片P和对应的复制分片R都不会在同一个节点内,这样有利于某个节点挂掉了,数据也不至于丢失。实际上,一个分片是一个Lucene索引,一个包含倒排索引的文件目录,倒排索引的结构使得elasticsearch在不扫描全部文档的情况下,就能告诉你哪些文档包含特定的关键字。不过,等等,倒排索引是什么鬼?

集群、节点、索引、分片 之间的关系:

  • 一个集群包含一个或多个节点,每个节点独立包含完整数据,节点也分主从节点
  • 一个节点就是一个 Elasticsearch 服务(实例)
  • 节点内创建索引,索引可以分成多个主分片,每个分片包含部分数据
  • 每个主分片还会有对应的从分片(副本),与主分片数据相同,个数自定,主分片不会与他的副本在一个节点内,这是为了增加高可用
  • Elasticsearch 中的分片其实就是 Lucene 索引
  • 一个分片就是一个 Lucene 实例

详细关系参照:Elasticsearch 集群、节点、索引、分片、副本概念
在这里插入图片描述

倒排索引

elasticsearch使用的是一种称为倒排索引的结构,采用Lucene倒排索作为底层。这种结构适用于快速的全文搜索,一个索引由文
档中所有不重复的列表构成,对于每一个词,都有一个包含它的文档列表。例如,现在有两个文档,每个文档包含如下内容:

Study every day, good good up to forever  # 文档1包含的内容
To forever, study every day,good good up  # 文档2包含的内容

为为创建倒排索引,我们首先要将每个文档拆分成独立的词(或称为词条或者tokens),然后创建一个包含所有不重复的词条的排序列表,然后列出每个词条出现在哪个文档:

termdoc_1doc_2
Studyx
Tox
every
forever
day
studyx
good
every
tox
up

比如,我们搜索 to forever,只需要查看包含每个词条的文档

termdoc_1doc_2
tox
forever
total21

两个文档都匹配,但是第一个文档比第二个匹配程度更高。如果没有别的条件,现在,这两个包含关键字的文档都将返回。

再来看一个示例,比如我们通过博客标签来搜索博客文章。那么倒排索引列表就是这样的一个结构:

博客文章(原始数据)博客文章(原始数据)索引列表(倒排索引)索引列表(倒排索引)
博客文章ID标签标签博客文章ID
1pythonpython1,2,3
2pythonlinux3,4
3linux,python
4linux

如果要搜索含有python标签的文章,那相对于查找所有原始数据而言,查找倒排索引后的数据将会快的多。只需要查看标签这一栏,然后获取相关的文章ID即可。完全过滤掉无关的所有数据,提高效率!

当然,前提是要先生成索引列表

elasticsearch的索引和Lucene的索引对比

在elasticsearch中,索引(库)这个词被频繁使用,这就是术语的使用。在elasticsearch中,索引被分为多个分片,每份分片是一个Lucene的索引。所以一个elasticsearch索引是由多 个Lucene索引组成的。别问为什么,谁让elasticsearch使用Lucene作为底层呢!如无特指,说起索引都是指elasticsearch的索引。

接下来的一切操作都在kibana中Dev Tools下的Console里完成。基础操作!

ik分词器

什么是IK分词器 ?

分词:

  • 即把一段中文或者别的划分成一个个的关键字,我们在搜索时候会把自己的信息进行分词,会把数据库中或者索引库中的数据进行分词,然后进行一个匹配操作,默认的中文分词是将每个字看成一个词。
  • 比如“我爱狂神”会被分为"我",“爱”,“狂”,“神” ,这显然是不符合要求的,所以我们需要安装中文分词器ik来解决这个问题。

如果要使用中文,建议使用ik分词器!

IK提供了两个分词算法:

  • ik_ smart和ik_ max_ word
  • ik_ smart为最少切分,ik_ max_ _word为最细粒度划分!

下载:https://github.com/medcl/elasticsearch-analysis-ik

版本不全到这里找:https://elasticsearch.cn/download/

下载完毕后,直接放到目录中 elasticsearch\elasticsearch-7.6.1\plugins 即可,注意将分词器的目录名改为 ik
在这里插入图片描述

重启 elasticsearch,在启动过程中可以看到,elasticsearch 加载了 ik 分词器
在这里插入图片描述

重启失败原因:

  • elasticsearch 与 ik 分词器版本一定要完全对应上,只对应大版本号不够

  • 如何查看 ik版本号,查看目录下 plugin-descriptor.properties 文件,
    在这里插入图片描述

  • 解压后,压缩包删除,分词器目录取名ik

  • kabana 和 head 最好也关掉,一起重启

如何确认 elasticsearch 启动成功加载插件?启动 elasticsearch bin 目录中提供的工具 elasticsearch-plugin.bat

进入 elasticsearch bin 目录启动命令行 elasticsearch-plugin list
在这里插入图片描述
表示加载成功

测试使用

进入 kibana 界面 Dev Tools 菜单,发起请求,选择分词算法

【ik_smart】(最少切分)测试:

GET _analyze
{
  "analyzer": "ik_smart",
  "text": "我是社会主义接班人"
}

发起请求,右侧可以看到分词结果
在这里插入图片描述
【ik_max_word】(最细粒度划分)测试

GET _analyze
{
  "analyzer": "ik_max_word",
  "text": "我是社会主义接班人"
}

可以看到二者的拆分区别
在这里插入图片描述
思考:

  • ik 分词器为什么知道怎么拆分呢?因为它需要参照分词器字典
  • 如果拆分的词不符合我们的实际需求怎么办?需要自己加到分词器字典里

ik分词器如何增加配置

进入分词器目录 elasticsearch\elasticsearch-7.6.1\plugins\ik\config ,这个目录包含了各种字典,

我们可以创建的自己的字典,然后配置到 IKAnalyzer.cfg.xml 文件中

新建字典文件,比如,swy.dic,编辑内容,比如添加

泥萌好
swy

这样,泥萌好,swy,就会默认成为一个词,被ik分词器识别

在配置文件 IKAnalyzer.cfg.xml 中,添加

<entry key="ext_dict">swy.dic</entry>

重启es,查看启动日志可以看到,我们的新的分词字典已经被加载

在这里插入图片描述
开始测试,
在这里插入图片描述
在这里插入图片描述
可以看到,我们自定义的词已经被看做一个完整的词,以后工作,我们即可配置自己需要的词

2.命令模式的使用

Rest风格说明

一种软件架构风格,而不是标准。只是提供了一组设计原则和约束条件,它主要用于客户端可服务器交互类的软件,基于这个风格设计的软件可以更简洁,更有层次,更易于实现缓存等机制

methodurl地址描述
PUTlocalhost:9200/索引名称/类型名称/文档id创建文档(指定文档id)
POSTlocalhost:9200/索引名称/类型名称创建文档(随机文档id)
POSTlocalhost:9200/索引名称/类型名称/文档id/_update修改文档
DELETElocalhost:9200/索引名称/类型名称/文档id删除文档
GETlocalhost:9200/索引名称/类型名称/文档id通过文档id查询文档
POSTlocalhost:9200/索引名称/类型名称/_search查询所有的数据

基础测试

  1. 创建一个索引,并添加数据
PUT /索引名/类型名/文档id

注意,PUT 后面有空格
在这里插入图片描述
查看 elasticsearch 后台数据
在这里插入图片描述
本质上是我们添加了一条数据
在这里插入图片描述
完成了自动增加索引,数据成功添加

需要注意的是,只要可以发送规定格式的请求就可完成操作,不一定使用kibana,postman,也可以,但是用kibana很专业,而且输入时有提示,降低出错率

如何给数据中的数据指定类型?

  • 字符串类型:text、keyword
  • 数值类型:long、integer、short、byte、double、float、half float、scaled float
  • 日期类型:date
  • 布尔类型:boolean
  • 二进制类型:binary
  • 等等

官方有详细讲解

指定字段类型,再次添加数据,这里我们先不添加数据,只是制定规则
在这里插入图片描述
查看后台控制,可以看到,新增加了一个索引test2,但是没有数据
在这里插入图片描述

  1. 获取索引规则信息,GET请求

在这里插入图片描述

  1. 查看默认信息

创建索引的时候,如果不指定字段属性类型,则会使用默认类型,当然也可以显示的声明

在这里插入图片描述
查看后台数据
在这里插入图片描述
发送请求查看数据,可以看到,age默认给了long类型,birthday默认给了date类型,name默认给了text类
在这里插入图片描述

  1. 修改操作,第一种,还是直接使用PUT即可,然后覆盖

在这里插入图片描述
但是有个缺点,对于修改来说,如果旧的数据有一个属性,新修改的指令里没有添加这个属性,那么修改后这个属性就会消失

由于之前我们己经创建这个数据,所以这次创建直接将原来的覆盖,而且version还显示了版本号增加了

第二种,使用正统的修改指令 POST

在这里插入图片描述
删除索引,使用 DELETE
在这里插入图片描述

cat命令

获取健康值

在这里插入图片描述

其实 elasticsearch-head后台管理页面就是不断地向服务器发送请求,获得的数据

查看所有信息
在这里插入图片描述
根据提示可以在 _cat后面添加很多指令进行查看

关于文档的基本操作(重点)

创建文档

  1. 添加数据
PUT /swy/user/1
{
  "name": "swy01",
  "age": 25,
  "desc": "every will be ok",
  "tags": ["高","富","帅"]
}

得到结果

{
  "_index" : "swy",
  "_type" : "user",
  "_id" : "1",
  "_version" : 1,
  "result" : "created",
  "_shards" : {
    "total" : 2,
    "successful" : 1,
    "failed" : 0
  },
  "_seq_no" : 0,
  "_primary_term" : 5
}

查看后台数据
在这里插入图片描述
同样的方法,在添加多条数据
在这里插入图片描述

  1. 获取数据 GET
    在这里插入图片描述
  2. 更新数据

在这里插入图片描述
不推荐使用put,推荐使用post,只需该对应的字段即可,不必添加所有的字段

POST swy/user/1/_update
{
  "doc": {
    "name": "Mike"
  }
}

在这里插入图片描述
在这里插入图片描述

  1. 搜素操作(简单操作)

通过id查询

GET swy/user/_search?q=name:Mike

在这里插入图片描述

复杂操作查询

复杂操作查询:select(排序,分页,高亮,模糊查询,精准查询)

查询具体的参数使用 json

  1. 条件查询
GET swy/user/_search
{
  "query": {
    "match": {
      "name": "jack"
    }
  }
}

在这里插入图片描述

  1. 结果过滤,查询并输出的结果不需要那么多字段
GET swy/user/_search
{
  "query": {
    "match": {
      "name": "jack"
    }
  },
  "_source": ["name","desc"]
}

在这里插入图片描述
注意:之后使用Java操作es,所有的方法和对象就是这里的key

  1. 排序操作,sort 表示通过哪个字段排序

这里用的升序,

GET swy/user/_search
{
  "query": {
    "match": {
      "name": "swy"
    }
  },
  "sort": [
    {
      "age": {
        "order": "desc"
      }
    }
  ]
}

在这里插入图片描述

  1. 分页查询,需要包含从哪里开始,以及页面大小

数据下标从0开始,与其他数据库是一样的

GET swy/user/_search
{
  "query": {
    "match": {
      "name": "swy"
    }
  },
  "sort": [
    {
      "age": {
        "order": "desc"
      }
    }
  ],
  "from": 0,
  "size": 1
}

在这里插入图片描述

  1. 多条件查询,使用bool,

must(相当于and),should(相当于or),must_not(不等于xxx条件)

GET swy/user/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "name": "swy"
          }
        },
        {
          "match": {
            "age": 250
          }
        }
      ]
    }
  }
}

在这里插入图片描述

  1. 过滤器 filter,

这里附加了范围

GET swy/user/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "name": "swy"
          }
        }
      ],
      "filter": {
        "range": {
          "age": {
            "gte": 100,
            "lte": 300
          }
        }
      }
    }
  }
}

在这里插入图片描述

  1. 匹配多个条件,tags,比如根据性格标签,可以计算出权重

多个条件使用空格分开即可

GET swy/user/_search
{
  "query": {
    "match": {
      "tags": "白 富 美"
    }
  }
}

我们可以看到,匹配度越高,分值越高
在这里插入图片描述

  1. 精确查询

term查询是直接通过倒排索引指定的词条进程精确查找的

关于分词

  • term,直接查询精确的
  • match,会使用分词器解析,先分析文档,再通过分析的文档进行查询

关于两个类型

  • text类型可以被分词解析
  • keyword不会被分词解析

举个例子,创建索引

PUT testdb
{
  "mappings": {
    "properties": {
      "name": {
        "type": "text"
      },
      "desc": {
        "type": "keyword"
      }
    }
  }
}

添加数据

PUT testdb/_doc/1
{
  "name": "狂神说Java name",
  "desc": "狂神说Java desc"
}

改变id,以及属性参数,添加多条数据
在这里插入图片描述
当成 keyword 方式分词,是看做一个整体
在这里插入图片描述
standard 普通方式,普通分词处理,当然我们也可以使用中文分词
在这里插入图片描述
开始查询

当我们搜索 name属性(text类型)时,由于这种数据默认可以被分词器解析,所以,即使我们搜索部分单词,也可以找到完整相关数据

GET testdb/_search
{
  "query": {
    "term": {
      "name": "狂"
    }
  }
}

在这里插入图片描述
当我们搜素 desc 属性(keyword类型)时,整个属性值被看做一个整体,搜索单个词无法找到,只有搜索整体才有结果

GET testdb/_search
{
  "query": {
    "term": {
      "desc": "狂"
    }
  }
}

在这里插入图片描述

GET testdb/_search
{
  "query": {
    "term": {
      "desc": "狂神说Java desc"
    }
  }
}

在这里插入图片描述

结论:keyword 属性的字段不会分词器解析,设置属性的时候需要注意

  1. 多个值匹配的精确查询

先添加一些数据,

PUT testdb/_doc/3
{
  "t1": "22",
  "t2": "2020-04-06"
}
PUT testdb/_doc/4
{
  "t1": "33",
  "t2": "2020-04-07"
}

开始查询

GET testdb/_search
{
  "query": {
    "bool": {
      "should": [
        {
          "term": {
            "t1": "22"
          }
        },
        {
          "term": {
            "t1": "33"
          }
        }
      ]
    }
  }
}

在这里插入图片描述

  1. 高亮查询

搜索的结果中包含搜索词条的部分,用高亮显示

查询的时候,添加高亮属性,并设置需要高亮的字段

搜索相关的结果,会被自动加上标签

GET swy/user/_search
{
  "query": {
    "match": {
      "name": "swy"
    }
  },
  "highlight": {
    "fields": {
      "name": {}
    }
  }
}

在这里插入图片描述
自定义高亮属性,添加所需要的标签的前缀,后缀
在这里插入图片描述
小结:

  • 匹配
  • 按条件匹配
  • 精确匹配
  • 区间范围匹配
  • 匹配字段过滤
  • 多条件匹配
  • 高亮查询

这些 MySQL 也可以做,只不过效率比较低

尤其在海量数据的情况下,es的性能优势非常明显

四、SpringBoot 集成 ElasticSearch

1.准备工作

官方文档:https://www.elastic.co/guide/index.html

找到客户端文档,进入Java Rest Client ,选择高级客户端,

客户端相关:

在这里插入图片描述
原生 maven 依赖

<dependency>
    <groupId>org.elasticsearch.client</groupId>
    <artifactId>elasticsearch-rest-high-level-client</artifactId>
    <version>7.6.2</version>
</dependency>

初始化 Initialization

RestHighLevelClient client = new RestHighLevelClient(
        RestClient.builder(
                new HttpHost("localhost", 9200, "http"),
                new HttpHost("localhost", 9201, "http")));

用完关闭

client.close();

2.API 使用

项目准备

创建maven项目作为父项目,删除多余文件,创建子模块springboot项目,添加项目依赖
在这里插入图片描述
在这里插入图片描述
检查springboot-starter下载的依赖,es依赖版本是否与我们安装的版本一致,如果不一致,将连接不上,一定要确保一致
在这里插入图片描述
添加与本地版本相匹配的依赖

<dependency>
    <groupId>org.elasticsearch.client</groupId>
    <artifactId>elasticsearch-rest-high-level-client</artifactId>
    <version>7.6.1</version>
</dependency>
<dependency>
	<groupId>com.alibaba</groupId>
	<artifactId>fastjson</artifactId>
	<version>1.2.70</version>
</dependency>

在这里插入图片描述

项目初始化

添加配置类,注入bean

@Configuration
public class ElasticSearchClientConfig {
    @Bean
    public RestHighLevelClient restHighLevelClient() {
        RestHighLevelClient client = new RestHighLevelClient(
                RestClient.builder(
                        new HttpHost("127.0.0.1", 9200, "http")));
        return client;
    }
}

源码分析

查看依赖 spring-boot-autoconfigure,elasticsearch

源码中提供的rest对象
在这里插入图片描述

API 索引操作

使用前确保,elasticsearch 已经启动

编写测试类,有了之前通过 kibana 的使用,我们现在开始转为使用Java API进行操作

@SpringBootTest
class EsApiApplicationTests {

	@Autowired
	@Qualifier("restHighLevelClient")
	private RestHighLevelClient client;

	// 测试索引的创建
	@Test
	void testCreateIndex() throws IOException {
		// 1.创建索引的请求
		CreateIndexRequest request = new CreateIndexRequest("swy_index");
		// 2.客户端执行请求,请求后获得响应
		CreateIndexResponse response = client.indices().create(request, RequestOptions.DEFAULT);
		System.out.println(response);
	}
}

运行测试,创建成功
在这里插入图片描述
查看后台数据,索引已经创建,默认为空
在这里插入图片描述
测试获取索引,判断是否存在

	// 测试索引是否存在
	@Test
	void testExistIndex() throws IOException {
		// 1.创建索引的请求
		GetIndexRequest request = new GetIndexRequest("swy_index");
		// 2.客户端执行请求,请求后获得响应
		boolean exist =  client.indices().exists(request, RequestOptions.DEFAULT);
		System.out.println("测试索引是否存在-----"+exist);
	}

在这里插入图片描述
测试删除索引

	// 删除索引
	@Test
	void testDeleteIndex() throws IOException {
		DeleteIndexRequest request = new DeleteIndexRequest("swy_index");
		AcknowledgedResponse delete = client.indices().delete(request,RequestOptions.DEFAULT);
		System.out.println("删除索引--------"+delete.isAcknowledged());
	}

在这里插入图片描述

API 文档操作

创建实体类

@Data
@AllArgsConstructor
@NoArgsConstructor
@Component
public class User {
    private String name;
    private int age;
}

编写测试类

添加文档

	// 测试添加文档
	@Test
	void testAddDocument() throws IOException {
		User user = new User("swy",18);
		IndexRequest request = new IndexRequest("swy_index");
		request.id("1");
		// 设置超时时间
		request.timeout("1s");
		// 将数据放到json字符串
		request.source(JSON.toJSONString(user), XContentType.JSON);
		// 客户端发送请求,获取响应结果
		IndexResponse response = client.index(request,RequestOptions.DEFAULT);
		System.out.println("添加文档-------"+response.toString());
		System.out.println("返回状态-------"+response.status());
	}

在这里插入图片描述
在这里插入图片描述
获取文档,判断是否存在

	// 测试文档是否存在
	@Test
	void testExistDocument() throws IOException {
		// 测试文档的 没有index
		GetRequest request= new GetRequest("swy_index","1");
		// 没有indices()了
		boolean exist = client.exists(request, RequestOptions.DEFAULT);
		System.out.println("测试文档是否存在-----"+exist);
	}

在这里插入图片描述
获取文档信息

	// 测试获取文档
	@Test
	void testGetDocument() throws IOException {
		GetRequest request= new GetRequest("swy_index","1");
		GetResponse response = client.get(request, RequestOptions.DEFAULT);
		System.out.println("测试获取文档-----"+response.getSourceAsString());
		System.out.println("测试获取文档-----"+response);
	}

返回的内容和命令得到的是一样的
在这里插入图片描述
更新文档信息

	// 测试修改文档
	@Test
	void testUpdateDocument() throws IOException {
		User user = new User("托克马克", 200);
		// 修改是id为1的
		UpdateRequest request= new UpdateRequest("swy_index","1");
		request.timeout("1s");
		request.doc(JSON.toJSONString(user),XContentType.JSON);
		UpdateResponse response = client.update(request, RequestOptions.DEFAULT);
		System.out.println("测试修改文档-----"+response);
		System.out.println("测试修改文档-----"+response.status());
	}

在这里插入图片描述
在这里插入图片描述
删除文档

	// 测试删除文档
	@Test
	void testDeleteDocument() throws IOException {
		DeleteRequest request= new DeleteRequest("swy_index","1");
		request.timeout("1s");
		DeleteResponse response = client.delete(request, RequestOptions.DEFAULT);
		System.out.println("测试删除文档------"+response.status());
	}

在这里插入图片描述
真实的项目一般都会批量插入数据

	//测试批量添加文档
	@Test
	void testBulkAddDocument() throws IOException {
		ArrayList<User> userlist = new ArrayList<User>();
		userlist.add(new User("swy1",5));
		userlist.add(new User("swy2",6));
		userlist.add(new User("swy3",40));
		userlist.add(new User("swy4",25));
		userlist.add(new User("swy5",15));
		userlist.add(new User("swy6",35));
		// 批量操作的Request
		BulkRequest request = new BulkRequest();
		request.timeout("1s");
		// 批量处理请求
		for (int i = 0; i < userlist.size(); i++) {
			request.add(
					new IndexRequest("swy_index")
							.id(""+(i+1))
							.source(JSON.toJSONString(userlist.get(i)),XContentType.JSON)
			);
		}
		BulkResponse response = client.bulk(request, RequestOptions.DEFAULT);
		// response.hasFailures()是否是失败的
		System.out.println("测试批量添加文档-----"+response.hasFailures());
	}

在这里插入图片描述
在这里插入图片描述
批量更新、批量删除 都同理

查询操作

  • SearchRequest 搜索请求
  • SearchSourceBuilder 请求条件构造,
  • highlighter 设置高亮
  • TermQueryBuilder 精确查询
  • MatchAllQueryBuilder 匹配全部查询
  • xxxQueryBuilder 对应了我们刚才看到的所有命令
	// 测试查询文档
	@Test
	void testSearchDocument() throws IOException {
		SearchRequest request = new SearchRequest("swy_index");
		// 构建搜索条件
		SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
		// 设置了高亮
		sourceBuilder.highlighter();
		// term name为swy1的
		TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("name", "swy1");
		// 匹配所有
		// MatchAllQueryBuilder matchAllQueryBuilder = QueryBuilders.matchAllQuery();
		sourceBuilder.query(termQueryBuilder);
		sourceBuilder.timeout(new TimeValue(60, TimeUnit.SECONDS));
		request.source(sourceBuilder);
		SearchResponse response = client.search(request, RequestOptions.DEFAULT);
		// 查询结果都封装在hit中
		System.out.println("测试查询文档-----" + JSON.toJSONString(response.getHits()));
		System.out.println("=====================");
		for (SearchHit documentFields : response.getHits().getHits()) {
			System.out.println("测试查询文档--遍历参数--" + documentFields.getSourceAsMap());
		}
	}

在这里插入图片描述

五、实现项目-京东搜索

1.项目搭建

新建模块,springboot,添加依赖
在这里插入图片描述
在这里插入图片描述
修改elasticsearch版本

<properties>
	<java.version>1.8</java.version>
	<elasticsearch.version>7.6.1</elasticsearch.version>
</properties>

添加依赖

<dependency>
	<groupId>com.alibaba</groupId>
	<artifactId>fastjson</artifactId>
	<version>1.2.70</version>
</dependency>

springboot核心配置

server.port=9090
# 关闭thymeleaf缓存
spring.thymeleaf.cache=false

导入页面素材

链接:https://pan.baidu.com/s/1M5uWdYsCZyzIAOcgcRkA_A
提取码:qk8p

下载链接:https://download.csdn.net/download/weixin_47257749/18351882

把 template、static文件复制到resources目录下
在这里插入图片描述
创建 controller

@Controller
public class IndexController {
    
    @RequestMapping({"/","/index"})
    public String index() {
        return "index";
    }
}

启动项目,访问测试:http://localhost:9090/

在这里插入图片描述

2.爬取数据

ElasticSearch 搜索的数据从哪里获取?

  • 数据库、消息队列、爬虫

爬取数据:获取请求返回的页面信息,筛选出我们想要的数据,jsoup 包可以实现,

jsoup可以解析网页,不可以解析媒体

导入依赖

<dependency>
	<groupId>org.jsoup</groupId>
	<artifactId>jsoup</artifactId>
	<version>1.10.2</version>
</dependency>

创建实体类,用于封装商品信息

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Content {
    private String title;
    private String img;
    private String price;
    // 可以自己添加属性完善功能
}

写一个工具类,解析网页

@Component
public class HtmlParseUtil {
    // 测试一下
    public static void main(String[] args) throws IOException {
        new HtmlParseUtil().parseJD("vue").forEach(System.out::println);
    }
    public static List<Content> parseJD(String keyword) throws IOException {
        /// 使用前需要联网
        // 请求url
        String url = "http://search.jd.com/search?keyword=" + keyword;
        // 1.解析网页(jsoup 解析返回的对象是浏览器Document对象)
        Document document = Jsoup.parse(new URL(url), 30000);
        // 使用document可以使用在js对document的所有操作
        // 2.获取元素(通过id),id自己查网页
        Element j_goodsList = document.getElementById("J_goodsList");
        // 3.获取J_goodsList ul 每一个
        Elements lis = j_goodsList.getElementsByTag("li");
        // System.out.println(lis);
        // 4.获取li下的 img、price、name
        // list存储所有li下的内容
        List<Content> contents = new ArrayList<Content>();
        for (Element li : lis) {
            // 由于网站图片使用懒加载,将src属性替换为data-lazy-img
            String img = li.getElementsByTag("img").eq(0).attr("data-lazy-img");// 获取li下 第一张图片
            String name = li.getElementsByClass("p-name").eq(0).text();
            String price = li.getElementsByClass("p-price").eq(0).text();
            // 封装为对象
            Content content = new Content(name,img,price);
            // 添加到list中
            contents.add(content);
        }
        // System.out.println(contents);
        // 5.返回 list
        return contents;
    }
}

在这里插入图片描述
抓取的数据交给 elasticsearch 即可用于 es 实现搜索

PS:好好珍惜,爬了一次,再就爬不进去了,getElementById 拿到的只剩 null 了

3.业务编写

添加 elasticsearch 配置类

@Configuration
public class ElasticSearchClientConfig {
    @Bean
    public RestHighLevelClient restHighLevelClient() {
        RestHighLevelClient client = new RestHighLevelClient(
                RestClient.builder(
                        new HttpHost("127.0.0.1", 9200, "http")));
        return client;
    }
}

在 elasticsearch 后台管理页面创建一个空索引 jd_goods
在这里插入图片描述

创建业务service

@Service
public class ContentService {
    @Autowired
    private RestHighLevelClient restHighLevelClient;
    // 1.解析数据放入 es 中
    public Boolean parseContent(String keywords) throws Exception {
        List<Content> contents = new HtmlParseUtil().parseJD(keywords);
        // 把查询的数据放入es中
        BulkRequest bulkRequest = new BulkRequest();
        bulkRequest.timeout("2s");
        for (int i = 0;i < contents.size();i++) {
            bulkRequest.add(new IndexRequest("jd_goods").source(JSON.toJSONString(contents.get(i)), XContentType.JSON));
        }
        BulkResponse bulk = restHighLevelClient.bulk(bulkRequest, RequestOptions.DEFAULT);
        return !bulk.hasFailures();
    }
    // 2.到es中查询获取这些数据
    public List<Map<String, Object>> searchPage(String keyword, int pageNo, int pageSize) throws IOException {
        if (pageNo <= 1) {
            pageNo = 1;
        }
        // 条件搜索
        SearchRequest searchRequest = new SearchRequest("jd_godds");
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        // 分页
        sourceBuilder.from(pageNo);
        sourceBuilder.size(pageSize);
        // 精准匹配
        TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("title", keyword);
        sourceBuilder.query(termQueryBuilder);
        sourceBuilder.timeout(new TimeValue(60, TimeUnit.SECONDS));
        // 执行搜索
        searchRequest.source(sourceBuilder);
        SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
        // 解析结果
        ArrayList<Map<String, Object>> list = new ArrayList<>();
        for (SearchHit documentFields : searchResponse.getHits().getHits()) {
            list.add(documentFields.getSourceAsMap());
        }
        return list;
    }
}

创建业务controller

@RestController
public class ContentController {
    @Autowired
    private ContentService contentService;
    // 先从京东抓取数据并存入es中
    @GetMapping("/parse/{keyword}")
    public Boolean parse(@PathVariable("keyword") String keywords) throws Exception {
        return contentService.parseContent(keywords);
    }
    // 在es中搜索数据返回结果
    @GetMapping("/search/{keyword}/{pageNo}/{pageSize}")
    public List<Map<String, Object>> search(@PathVariable("keyword") String keyword,
                                            @PathVariable("pageNo") int pageNo,
                                            @PathVariable("pageSize") int pageSize) throws IOException {
        return contentService.searchPage(keyword, pageNo, pageSize);
    }
}

测试成功后,现拿到了数据,还差前端页面展示,使用 Vue

4.前端页面展示

下载vue相关文件

随便找一处空目录,进入目录cmd,执行命令

npm install vue
npm install axios

找到 node_modules\vue\dist 目录下 vue.js,node_modules\axios\dist 目录下 axios.js

复制到我们项目的静态目录中
在这里插入图片描述
改造我们 index.html 页面,实现前后端分离

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="utf-8"/>
    <title>狂神说Java-ES仿京东实战</title>
    <link rel="stylesheet" th:href="@{/css/style.css}"/>
    <script th:src="@{/js/jquery.min.js}"></script>
</head>
<body class="pg">
<div class="page">
    <div id="app" class=" mallist tmall- page-not-market ">
        <!-- 头部搜索 -->
        <div id="header" class=" header-list-app">
            <div class="headerLayout">
                <div class="headerCon ">
                    <!-- Logo-->
                    <h1 id="mallLogo">
                        <img th:src="@{/images/jdlogo.png}" alt="">
                    </h1>
                    <div class="header-extra">
                        <!--搜索-->
                        <div id="mallSearch" class="mall-search">
                            <form name="searchTop" class="mallSearch-form clearfix">
                                <fieldset>
                                    <legend>天猫搜索</legend>
                                    <div class="mallSearch-input clearfix">
                                        <div class="s-combobox" id="s-combobox-685">
                                            <div class="s-combobox-input-wrap">
                                                <input v-model="keyword"  type="text" autocomplete="off" id="mq"
                                                       class="s-combobox-input"  aria-haspopup="true">
                                            </div>
                                        </div>
                                        <button type="submit" @click.prevent="searchKey" id="searchbtn">搜索</button>
                                    </div>
                                </fieldset>
                            </form>
                            <ul class="relKeyTop">
                                <li><a>狂神说Java</a></li>
                                <li><a>狂神说前端</a></li>
                                <li><a>狂神说Linux</a></li>
                                <li><a>狂神说大数据</a></li>
                                <li><a>狂神聊理财</a></li>
                            </ul>
                        </div>
                    </div>
                </div>
            </div>
        </div>
        <!-- 商品详情页面 -->
        <div id="content">
            <div class="main">
                <!-- 品牌分类 -->
                <form class="navAttrsForm">
                    <div class="attrs j_NavAttrs" style="display:block">
                        <div class="brandAttr j_nav_brand">
                            <div class="j_Brand attr">
                                <div class="attrKey">
                                    品牌
                                </div>
                                <div class="attrValues">
                                    <ul class="av-collapse row-2">
                                        <li><a href="#"> 狂神说 </a></li>
                                        <li><a href="#"> Java </a></li>
                                    </ul>
                                </div>
                            </div>
                        </div>
                    </div>
                </form>
                <!-- 排序规则 -->
                <div class="filter clearfix">
                    <a class="fSort fSort-cur">综合<i class="f-ico-arrow-d"></i></a>
                    <a class="fSort">人气<i class="f-ico-arrow-d"></i></a>
                    <a class="fSort">新品<i class="f-ico-arrow-d"></i></a>
                    <a class="fSort">销量<i class="f-ico-arrow-d"></i></a>
                    <a class="fSort">价格<i class="f-ico-triangle-mt"></i><i class="f-ico-triangle-mb"></i></a>
                </div>
                <!-- 商品详情 -->
                <div class="view grid-nosku" >
                    <div class="product" v-for="result in results">
                        <div class="product-iWrap">
                            <!--商品封面-->
                            <div class="productImg-wrap">
                                <a class="productImg">
                                    <img :src="result.img">
                                </a>
                            </div>
                            <!--价格-->
                            <p class="productPrice">
                                <em v-text="result.price"></em>
                            </p>
                            <!--标题-->
                            <p class="productTitle">
                                <a v-html="result.title"></a>
                            </p>
                            <!-- 店铺名 -->
                            <div class="productShop">
                                <span>店铺: 狂神说Java </span>
                            </div>
                            <!-- 成交信息 -->
                            <p class="productStatus">
                                <span>月成交<em>999笔</em></span>
                                <span>评价 <a>3</a></span>
                            </p>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>
</div>
<script th:src="@{/js/vue.js}"></script>
<script th:src="@{/js/axios.js}"></script>
<script>
    new Vue({
        el:"#app",
        data:{
            "keyword": '', // 搜索的关键字
            "results":[] // 后端返回的结果
        },
        methods:{
            searchKey(){
                var keyword = this.keyword;
                console.log(keyword);
                axios.get('search/'+keyword+'/0/20').then(response=>{
                    console.log(response.data);
                    this.results=response.data;
                })
            }
        }
    });
</script>
</body>
</html>

5.高亮显示

修改 service业务层,基于方法2的代码,我们创建方法3

	// 3、 在2的基础上进行高亮查询
    public List<Map<String, Object>> highlightSearch(String keyword, Integer pageNo, Integer pageSize) throws IOException {
        SearchRequest searchRequest = new SearchRequest("jd_goods");
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        // 精确查询,添加查询条件
        TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("title", keyword);
        searchSourceBuilder.timeout(new TimeValue(60, TimeUnit.SECONDS));
        searchSourceBuilder.query(termQueryBuilder);
        // 分页
        searchSourceBuilder.from(pageNo);
        searchSourceBuilder.size(pageSize);
        // 高亮 =========
        HighlightBuilder highlightBuilder = new HighlightBuilder();
        highlightBuilder.field("title");
        highlightBuilder.preTags("<span style='color:red'>");
        highlightBuilder.postTags("</span>");
        searchSourceBuilder.highlighter(highlightBuilder);
        // 执行查询
        searchRequest.source(searchSourceBuilder);
        SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
        // 解析结果 ==========
        List<Map<String, Object>> list = new ArrayList<>();
        for (SearchHit documentFields : searchResponse.getHits().getHits()) {
            // 使用新的字段值(高亮),覆盖旧的字段值
            Map<String, Object> sourceAsMap = documentFields.getSourceAsMap();
            // 高亮字段
            Map<String, HighlightField> highlightFields = documentFields.getHighlightFields();
            HighlightField title = highlightFields.get("title");
            // 替换
            if (title != null){
                Text[] fragments = title.fragments();
                StringBuilder new_title = new StringBuilder();
                for (Text text : fragments) {
                    new_title.append(text);
                }
                sourceAsMap.put("title",new_title.toString());
            }
            list.add(sourceAsMap);
        }
        return list;
    }
}

controller 将接受方法修改为高亮业务

	// 在es中搜索数据返回结果
    @GetMapping("/search/{keyword}/{pageNo}/{pageSize}")
    public List<Map<String, Object>> search(@PathVariable("keyword") String keyword,
                                            @PathVariable("pageNo") int pageNo,
                                            @PathVariable("pageSize") int pageSize) throws IOException {
        return contentService.highlightSearch(keyword, pageNo, pageSize);
    }

修改 index.html 页面,使其可以解析高亮标签

<!--标题-->
<p class="productTitle">
    <a v-html="result.title"></a>
</p>

标签:文档,swy,索引,jsoup,elasticsearch,new,7.6,最新版,ElasticSearch
来源: https://blog.csdn.net/weixin_47257749/article/details/116330755

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有