高性能分布式搜索引擎。
数据库模糊搜索比较慢,但用搜索引擎快多了。
下面是一些搜索引擎排名
Lucene是一个Java语言的搜索引擎类库(一个工具包),apache公司的顶级项目。
优势:易扩展、高性能(基于倒排索引)
elasticsearch优势:
支持分布式,可水平扩展
提供Restful接口,可被任何语言调用
elasticsearch随着技术发展越来越完善,已经不是一个孤立的技术了,有一套完整的技术栈,简称ELK(kibana、Logstash、Beats),被广泛应用在日志数据分析、实时监控等领域。
安装ES
推荐Docker命令一键安装。
安装Kibana
一个图形界面的工具,会帮助我们连接ES,提供图形化的操作,还能自动补全。
推荐Docker命令一键安装。
Kibana提供了一个工具Dev tool,它可以帮助我们向ES发送HTTP请求,而且自带提示!!!
倒排索引
传统MySQL关系数据库只会给文档建立id索引。
而elasticsearch采用倒排索引:不仅会给文档建立id索引,还会给拆开的词条建立索引。
- 文档:每条数据就是一个文档
- 词条:文档按照语义分成的词语
会给词条建一个索引,将来根据词条来检索速度会非常快。
以下图为例,其实我们搜了两次,第一次拿词条来词条列表找,第二次拿着找到的文档id到文档列表里找文档。而传统关系数据库,只能全表扫描。
正向索引先去找文档,看文档里是否包含词条。
倒排索引先去找词条,得到文档id,再去找文档。(要经历两次检索)
IK分词器
英文分词很简单,因为单词间有空格。仲文分词必须按语义进行分析。
把这个插件(ik)放到插件目录里。
analyzer可以中文分词的:ik_smart、ik_max_word
IK分词器允许词典扩展。
ES核心概念
叫索引可能会混淆,我们通常把他理解成索引库。因为MySQL里给id加的那个也叫索引。索引和数据库里的表table的概念有点接近。要保证json文档他们的结构一致、数据类型一致,叫做映射。
下图是ES和MySQL数据库一些概念的对比👇
索引库操作
Mapping映射属性
Mapping映射类似于建表
keyword不可拆分的词
索引库操作
keyword不可拆,text可拆
在elasticsearch里,不允许对索引库做修改操作(指不能对已有的索引库字段做修改,但允许添加新的字段)。
文档操作
上节课学完索引库的各种操作,相当于在MySQL里去创建表,表有了之后,我们要学着操作数据。在索引库里,我们操作的是文档。
文档CRUD
完全符合Restful风格
全量修改,改的话全部都要改。
增量/局部修改,修改指定的。
批量处理
一个一个文档处理效率太低,这次学习批量处理。
JavaRestClient
ES给我们提供的java客户端,JavaRestClient。
这套客户端就是帮我们向restful接口发请求的。
客户端初始化
步骤:引依赖->对SpringBoot原有默认的ES版本进行覆盖->初始化RestHighLevelClient
例:
商品表Mapping映射
上节课已经完成es的java客户端的初始化,之后的几节课我们将学习如何利用这个客户端实现索引库及文档的各种操作。
创建商品索引库首先要确定商品的Mapping映射。
索引库操作
文档操作
上节课学习es的java客户端操作索引库的各种API,并创建了一个索引库。有了索引库我们就可以向里面写入文档,进行文档操作了。
source 源
request.source请求参数里的数据直接用数据库里的。但是数据库里的和索引库的字段不完全一样,我们要怎样保证他们一样呢?
首先定义一个实体,这个索引要和索引库的mapping映射结构一致。
直接复制一份po,然后把其中不需要的属性删掉。(简单无需技术含量)
根据id查数据库,查到数据库数据转化为文档数据,用到糊涂工具包BeanUtil.copyProperties(item,ItemDoc.class)拷贝数据。
得到的文档数据放到source方法请求参数必须是JSON,用工具类JSONUtil转换
新增文档操作如上,接下来我们学习文档其他增删改查的API。
发送请求结果获取到的request对象里面是完整的Json数据
而解析结果就是获取到的request对象里的source
批处理
一次只能操作一个文档效率太低,es提供了这种批处理的restful接口,之前我们是用ADP请求的方式去调用的,这回我们学习如何利用java客户端去做批处理。
一次全查可能会爆,所以下面的例子采用分页查询。 (使用Page)
结果通过record取出,做一个判断,是否没查到任何数据(一个健壮性判断)。
没查到数据就不用往下走,直接return;查到了再往索引库里写。
参数id不是写死的,而是要改成获取到的request遍历的item.id(int型要改成String)
source里的要变成JSON,而且要用我们改好的po实体类Itemdoc,而不是item。
while用来翻页的。
DSL查询
前面已经学习了es索引库和文档的各种增删改查操作了,其中我们查询文档都是根据id查询的,但是这种查询方式并不能满足我们所有的业务场景的需求,我们实际项目中不一定是根据id搜索的,他的搜索条件往往比较复杂。这时我们就需要一种新的查询方式,ES就给我们提供了一个DSL的查询,来实现这种复杂条件的查询。
快速入门
因为是查询,所以这里是GET。
GET /索引库名/_search
match_all{}:匹配/查询所有,{}里面如果啥也没有,就是没有查询条件,那就查所有
es内部默认有限制,单次允许查询最大数据不能超过1万
gte:>= 大于等于
hits:查询命中的数据
叶子查询
全文检索查询就是之前的倒排索引查询。
精确搜索,输入的搜索条件,都是相对简单不可分割的词。
range范围,term直接比较字段值。
下面以全文检索为例:
multi_match与match类似,但multi_match允许多个字段查询。
fileds数组里可以放你想查询的(多个)字段。
上图是match匹配。
默认情况下,所有的全文检索查询都会有相关的算分score,这样就能实现匹配度越高、排名越靠前。
上面是multi_match。
因为只查询了一个name字段,所以得出的结果应该和match查询一样。
精确查询用的最多的查询就是term查询。(term不分词,适合搜不分词的字段,我们上节课的multi_match和match就自带分词。所以term查询可以用在品牌、种类等等字段上)
FIELD写字段
除了有term的,还要range带范围的。
term只能搜不可分割的那种词。
range: (上面的例子price价格范围查询)
gt 大于不能等于,gte 大于等于
lt 小于不能等于, lt 小于等于
根据id查询
复合查询
布尔查询(bool)
布尔查询可以组合一个或多个查询的子句,组合的方式就是逻辑运算,与或非。
不参与算分:通常情况下,用户输入关键字做搜索,这种情况下,我们应该给他算分。但是其他的用来做过滤筛选的,我们通常情况下,都不应该参与算分。
filter和must区别:都是与,但是filter不参与算分。
参与算分的字段越多,条件越多,计算得分时消耗的性能越多,效率会低,所以能不参与算分的,我们尽可能不参与。
语法👇
例子👇
有相关度得分的must,得分排名越高越靠前。
在must,should,must_not,filter里面都是可以添加任意多的叶子查询的。
总结:
通常像关键字的搜索(用户输入内容的搜索),都是有一个匹配度的问题的,都应该参与算分,通常放到must或should。
一些过滤条件,不参与算分,通常放到filter或must_not。
function_score
dis_max
略,这俩基于某种算法修改查询时的文档相关性算分,从而改变文档排名。
排序和分页
我们学完了各种DSL的查询方式,并且拿到查询结果了。我们还需要对查询的结果去做排序和分页。ES允许我们在指定查询条件的同时,指定一些排序和分页的参数。
下面的例子就是在查询条件得到结果的基础上,es会根据你指定的排序字段做排序。
sort是一个数组,也就是我们是可以指定多个排序字段的。如果指定多个排序字段,它会按照第一个指定的字段去做排序,以此类推。
desc 降序排序
销量降序,价格升序,下面例子
排序的功能就实现好了,接下来我们实现分页功能。
深度分页问题
es其实有限制:from+size不能超过1万条。
高亮显示
在上节课学习了对搜索结果排序和分析的功能,ES除了可以对结果做排序分页,还可以实现结果的高亮显示。那么什么是高亮显示,以及它的使用语法。
之前没有讲过,其实在倒排索引的时候,不仅仅会记录词条及包含词条的文档的id,还会去记录这个词条在文档中的位置。fields是复数形式,那么高亮字段其实是可以指定多个的。
因为要高亮,所以一定要带搜索关键字,没有关键字没法高亮,所以这里一定是用全文检索查询,用match,或者multi_match都可以的。
这样就可以给关键字加标签了,source里面不会加,因为source是源,源就是源文档。但是这个搜索结果里,和source同级的,有一个highlight,这里面可以看到加了标签!!
fields属性的标签加不加都可以,因为默认加+<em>标签。
所以你会发现我们的搜索条件query、分页条件from size、排序条件sort和高亮条件highlight他们都是同一级的。
JavaRestClient查询
在上一章学习了基于DSL语法的各种不同的查询,要想实现业务功能,最终还是要用java代码。
接下来学习基于javaRestClient的各种查询API。
快速入门
以简单的查询所有为例子。match_all
1.构建请求并发起请求👇
request.source就是对应的一整个JSON。
查询条件,里面的QueryBuilders,利用他可以得到任何你想要的查询条件。
例👇
2.解析结果👇
例👇
查询可以分成两部分:
第一部分是请求的构建和发送。三步:1.构建request对象,2.给request对象添参数(核心记住两个API,source里面有各种如query、from size、highlight、sort等,query里面构建具体的查询条件记住querybuilders里面有大量方法构建条件),3.发请求。
第二部分是结果解析。
构建查询条件
全文查询👇
match和mult_match
精确查询👇
term和range
复合查询👇
布尔查询
案例训练👇
Elasticsearch02-08.JavaRestClient查询-构建查询条件_哔哩哔哩_bilibili
总结:查询条件的构建API只需要记住一个API,querybuilders。
排序和分页
上节课我们学了如何用java的客户端构建复杂的查询条件,这节课我们学了如何用java的客户端实现排序和分页。
例👇
高亮显示
关键字做高亮处理。
例👇
为了使代码简化,解析结果本来是很长的一段,被手动封装成方法了,方便看。
但是允许结果却没有高亮,为什么呢?
这是因为被封装的方法写的是getsource来取出结果,而getsource是源,不可能被修改。
所以我们不能去source里的结果,而是应该取和source同级的高亮的结果。
这里重新写一下高亮解析。我们的source是不带高亮结果的,如果要取高亮,必须用source同级的highlight。
需要注意的是,我们取出高亮结果又可能是fragments数组,这个数组里可能有多个字符串,要对他做一个拼接。
数据聚合
目前为止,我们已经学完了es的数据存储和搜索的各种功能,es不仅仅可以做数据的存储和搜索,还可以做海量数据的分析及运算。这种数据的分析和运算的功能,就成为数据聚合。
其实聚合就是对文档数据的统计分析和运算。
之前我们学习关系型数据库时,如MySQL,就提供了一些聚合函数(如求平均值的AVG函数、求和SUM、计数count)。这些聚合函数起作用就是对数据库里的数据进行统计分析和运算。
桶聚合的分组就类似MySQL关系数据库里面的group by
DSL聚合
例👇
+条件
RestClient聚合
用java客户端实现聚合功能。
例👇
然后解析结果👇
例👇