高性能分布式搜索引擎。
数据库模糊搜索比较慢,但用搜索引擎快多了。
下面是一些搜索引擎排名
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 降序排序
销量降序,价格升序,下面例子