Elastic Search 导学
ES是什么
一个强大的开源搜索引擎,可以帮我们从海量数据中快速找到我们想要的内容。
除了搜索外还支持的其他功能:
-
高亮显示搜索词。
-
数据分析、可视化。
-
系统监控。
总之,ES很NB就是了。
两大索引——倒排索引 和 正排索引
首先这里说的索引是一种键值映射关系。所谓正排索引 和 倒排索引只是看你如何设计键值对的。
我们用下面的一张普通的MySQL表作为例子:
首先不用我说你应该知道id是这张表的主键。
- 正排索引的key为id,value为对应行。这体现了 “由主键找数据” 的自然逻辑。
- 倒排索引的key为一个关键词,value为包含这个关键词的id列表。这体现了 “由内容反查主键” 的逆向思维。
其中倒排索引就是搜索引擎们能够通过用户输入的关键词快速搜到一大堆相关数据的秘密武器!
为了直观感受倒排索引,这里我们以title字段为例建立一个倒排索引:
首先会对内容进行处理,拆分成一个个关键词(分词),最终得到这样的表。
基于倒排索引的搜索流程:
MySQL和ES的关系
核心概念对比
这是基于7.17.28这个版本的概念对比。不同的大版本差异有点大。
在ES中有3大核心概念:索引(Index)、映射(Mapping)、文档(Document)。
接下来用一个表格来直观阐述它们在MySQL中的“同义词”。
| Elastic Search | MySQL |
|---|---|
| 索引 | 表 |
| 映射 | 表结构 |
| 文档 | 表中的记录 |
注意⚠:
这里的“索引”和前面的“两大索引”里面说的“索引”不是一个东西!**请你不要钻牛角尖!**其实我也不理解为什么ES会搞一个这么容易令人迷惑的概念。
二者的关系
二者是一种互补的关系。
MySQL更擅长事务相关操作(说人话就是数据的增删改),而ES更擅长数据的查询、分析操作。
因此在Java后端开发中,我们一般是让二者配合使用的。
用一张图体现二者在Java后端开发的用武之地:
注意:一般简单查询(比如根据id查询)还是走MySQL。如果查询比较复杂的话才走ES。
安装
1.安装 1Panel
1Panel本身是基于Docker的Linux面板,安装它以后也会顺带安装Docker + Docker Compose。
有时候因为网络问题可能会导致Docker无法正常安装。如果你遇到了这种情况,那么你可以参照这个教程下载Docker:【1Panel三分钟搭建Minio - 编程导航 - 程序员编程学习交流社区】
我这里就不赘述如何安装1Panel了。
最后和你分享一下我的镜像加速配置:
▼text复制代码https://docker.m.daocloud.io/ https://docker.1panel.live/ https://dockerproxy.1panel.live/ https://docker.1ms.run/ https://docker.1panel.top/
反正我用这套镜像加速配置下image嘎嘎快。
2.正式安装
① 使用git拉取我的一键启动项目。
Ubuntu好像一开始是自带git的,如果你用的Linux发行版没有git,那你先装一个先。
▼text复制代码git clone https://gitee.com/yang-mingzhang/elastic-search-with-ik-and-kibana-starter.git
② 进入这个项目的根目录,然后运行以下命令:
一键启动ES + Kibana服务:
▼bash复制代码docker-compose up -d
第一次运行会自动下载镜像,因此会比较慢,请耐心等待:
成功后:
一键删除ES + Kibana服务:
▼text复制代码docker-compose down注意⚠:删除的是容器而不是镜像!
只要镜像还在,之后就真的是一键启动了!
③ 访问Kibana客户端
在浏览器地址栏输入http://你的虚拟机IP:5601即可。
注意⚠:
刚启动ES服务时,如果你立即访问这个网址,可能会出现访问不了的情况。
这是正常的,那是因为Kibana 和 ES服务器还未初始化好。我反正是刷了大概20s左右的样子才刷出来的。
认识IK分词器
对汉字分词友好。
何为分词
我前面在倒排索引这一部分简单提了一嘴“分词”这个概念。
ES正是对文档内容进行分词,然后建立倒排索引。
之后用户就能通过关键词搜索到相关文档。
ES其实内置了一些分词器,但是对中文支持很差,它是把每一个汉字当作一个词。
测试分词——标准分词器 大战 IK分词器
不信?那我们来对鸽鸽的名言进行分词吧!
素材:
全民制作人们大家好,我是练习时长两年半的个人练习生蔡徐坤。喜欢唱、跳、rap、篮球,music!
如何测试分词效果?
用Kibana的开发者工具发起如下RESTful请求即可:
▼json复制代码POST _analyze { "text": "素材内容", "analyzer": "分词器名字" }
我们先用ES默认的分词器【标准分词器,standard】对素材进行分词,结果如下:
正如你所见,可能老外初次认识中文的时候是一个字一个字的看的doge。
然后看看ik分词器:
⚠注意:
ik分词器提供了两种分词模式,它们分别是智能模式【ik_smart】和细粒度模式【ik_max_word】。这里先以智能模式进行测试,后面再具体介绍二者区别。
虽然看起来还是有点怪怪的,但是你至少发现了词语的存在吧。
想要知道为什么会出现这样的现象,我们还得简单了解一下分词的原理。
IK分词器两种模式的区别
为举例方便,我将以“中华人民共和国”这个词举例。
- 智能模式
- 采用最粗粒度拆分,仅输出最可能的词语组合。这个模式下,直接输出“中华人民共和国”这个最大的词,其内部的小词它是不会再继续分的,也就是最粗粒度。
- 细粒度模式
- 将文本进行最细粒度拆分,穷尽所有可能的词语组合。这个模式下还可以继续拆分“中华人民共和国”内部的小词,比如:“中华”、“中华人民”、“人民”、“共和国”等等词语。
由此可见:
前者产生的倒排索引占用的空间要小一些,但是会降低搜索到文档的概率;后者则是恰好反过来的。
如何选择呢?
如果是对文档建立倒排索引这个场景,那么用细粒度模式最为合适,这样文档被搜到的概率也就越大。如果是用户通过关键词搜索文档这个场景,那么用智能模式最为合适,可以提高搜索结果的相关性。
分词的原理
标准分词器会把“中国”这个词傻傻地拆分成“中”、“国”这两个词。而IK分词器就比较聪明了,它能正确地将“中国”识别成为一个词。
其实IK分词器内置了一个汉语词典(你可以类比为我们小时候用过的《现代汉语词典》),这里面记录了所有可能的词语。
其实一开始IK分词器不知道“中国”是一个词,在它眼里这只是一个普通的由“中”和“国”两个字符组成的字符串而已。然后它会拿着这个字符串去汉语词典里面查,如果查到了,这时IK分词器才会把这个字符串当作一个词语。 怎么样?其实也不是很复杂对吧~
当然,如果某个字符串要是没被收录到这个词典之中,IK分词器还是会采用和标准分词器一样的策略,即单字分词。例如如“奥力给”这个网络词语,我相信经常在互联网冲浪的大伙肯定不陌生,但是7.17.28这个版本的IK分词器的汉语词典里并没有收录这个词。
现在你能猜到为什么之前用IK分词器来给鸽鸽的名言分词的结果为什么怪怪的了吧?本质是因为里面的好多词并没有收录到IK分词器内置的汉语词典中。
为IK分词器内置的词典添砖加瓦
我们都知道互联网上的信息是爆炸式增长的。当初设计IK分词器内置词典的那批人怎么可能预料到这么多的网络词语的诞生呢?
还好他们给我们留了一手,使得我们可以往这个汉语词典当中添加一些自定义的词。
我们现在移步到IK分词器的配置文件所在目录下: 【PS:我用的WSL】
我们随便点进去一个dic文件看看里面的内容吧。
现在你应该理解分词的本质了吧?
然后再来看看IK分词器的核心配置文件。
其中这个entry标签的内容部分填的就是我们自定义词典文件的路径。
这里需要说明一下**【拓展词典】和【拓展停止字典】**这两个概念:
- 拓展词典
- 用于补充内置词典未收录的词(拓展词)。
- 拓展停止字典
- 用于存放需要被过滤掉的词汇(停用词)。
- 它们不会被建立倒排索引,也就是说不会被搜索到。
- 这类词汇一般是介词、语气词、敏感词等等。其中常见的介词、语气词等已经被包括了,但是敏感词需要我们自己指定。
为了方便,我就在当前的config目录下新建一个customer文件夹用于存放我们自定义的【拓展词典】和【拓展停止字典】。
拓展词典的文件我就命名为ext_dict.dic,拓展停止字典的文件我就命名为ext_stopwords.dic。
然后在核心配置文件中指明这两个文件的路径:
好啦,那我们随便写几个词测试一下吧。
前面我展示过默认的dic文件里的内容,我们发现每个词语独占一行。因此我们自定义的dic文件也要遵循这个规则。
我添加的内容为:
拓展词:“全民制作人”、“两年半”
停用词:“我”、“是”
最后重启一下ES服务器我们的词库才会生效【拓展点:IK分词器其实支持词典的热更新功能,即修改词典后无需重启ES服务器,但是默认是不开启的。喜欢折腾的同学可以自行尝试】。
测试结果:
现在IK分词器认识了“全民制作人”和“两年半”这两个词,并且“我”和“是”这两个词被排除了!
接下来学什么?
我为什么要写这个总结?只是因为我在找ES教程学习的时候发现很多教程把ES当作一个数据库来教的,然后按照惯例地介绍ES中的CRUD操作。
可是ES的本质是什么?人家是专门做搜索的啊!!!所以我感觉介绍ES增删改操作对于我们搞Java后端开发来说似乎有点多余。为什么?谁家好人会用不支持事务的ES【不清楚未来会不会支持,反正7.17.28这个版本是没有的】来增删改数据啊?
有的教程开篇就花大量篇幅介绍ES底层原理,如果你是需要面试,学这些内容是理所应当。但是对于大多数同学而言,他们只是想快速知道如何用ES解决业务问题。因此对于他们而言,在连ES能在业务中做什么都还不清楚的前提下过早接触底层原理,这是一种不科学的学习方式! 这就好比你需要会造车才会开车么?
我认为在你能够熟练应用ES解决常见的业务问题后,你才有动力和兴趣去学习ES的底层原理。
说了这么一大堆,那么对于我们普通Java后端开发者而言我们应该重点学习什么呢?
- ES的查询【超重点!】
- 使用什么工具实现MySQL和ES的数据实时同步
- 分布式、高可用这些就见仁见智吧,因为我连单体项目都还没玩明白,因此我不会过早接触这些内容。
不只是学ES,你学习其他技术时,就应该思考这些问题!先会用这些技术解决实际业务问题,如果你兴趣来了再去学技术的底层原理也不迟。当然这不适用于着急面试找工作的同学,因为我们无法改变 “面试造火箭,工作打螺丝” 这个大环境!
