1.了解倒排索引
1.1.正向索引
MySql的索引就是采用正向索引而设计的,如下表所示:
id | name | price |
---|---|---|
1 | 小米手机 | 2000 |
2 | 华为手机 | 3000 |
3 | 苹果手机 | 4000 |
根据MySql知识为id设立主键聚集索引,如果是根据id查询那么就可以直接得到整行数据,因为聚集索引下面的结点就是存储的行数据。
但如果是基于name来做模糊查询,例如
select * from tb_phone where name like '%手机%'
那么就算你为name字段创建索引也是只能逐行扫描数据,也就是全表扫描,当你的数据量达到一定程度的时候效率将会非常的低。
1.2.倒排索引
倒排索引的概念:
- 文档(
Document
):用来搜索的数据,其中的每一条数据就是一个文档 - 词条(
Term
):对文档数据利用某种算法进行分词,得到的具备含义的词语,例如:我是中国人,可以分为:我、是、中国人、中国、人这样的几个词条。
为了避免上述全表扫描的问题才创建的倒排索引,流程如下
- 将每一个文档的数据利用分词器进行分词,得到一个个的词条
- 创建表,每行数据包括词条,词条所在的文档id,位置等信息
- 因为词条具有唯一性,可以给词条创建索引,例如hash索引
对上述表格创建倒排索引,如下表所示:
词条(Term) | 文档id |
---|---|
小米 | 1 |
华为 | 2 |
苹果 | 3 |
手机 | 1,2,3 |
搜索流程如下(以搜索"华为手机"为例)
- 用户输入条件"
华为手机
"进行搜索 - 对用户输入的内容分词,得到词条:
华为
,手机
- 根据词条去倒排索引查找,得到包含词条的文档id:1,2,3
- 拿着文档id根据mysql正向索引查找具体的数据
1.3.优缺点
正向索引
- 优点
- 可以给多个字段创建索引
- 根据索引字段搜索,排序速度非常快
- 缺点
- 扫描非索引字段或者索引字段的部分词条只能全表扫描
倒排索引
- 优点
- 根据词条搜索,模糊搜索的时候速度非常快
- 缺点
- 只能给词条创建索引,而不是字段
- 无法根据字段进行排序
2.ElasticSearch的概念
2.1.文档和字段
ElasticSearch是面向**文档(Document)**进行存储的,文档数据会被序列化成Json字符串存储到ElasticSearch中,如下图对应关系:
Json文档中包含的字段(Field),类似于数据库中的列。
2.2.索引和映射
索引(Index):相同类型的文档集合,相当于数据库中的表。
例如:
- 所有用户文档,就可以组织在一起,称为用户的索引;
- 所有商品的文档,可以组织在一起,称为商品的索引;
- 所有订单的文档,可以组织在一起,称为订单的索引;
映射(mapping):索引中文档字段的约束信息,相当于表的结构约束。
例如:字段类型的规定,integer,date等。
2.3.MySql和ElasticSearch的比较
MySql | ElasticSearch | 说明 |
---|---|---|
Table | Index | 索引(index),就是文档的集合,类似数据库的表(table) |
Row | Document | 文档(Document),就是一条条的数据,类似数据库中的行(Row),文档都是JSON格式 |
Column | Field | 字段(Field),就是JSON文档中的字段,类似数据库中的列(Column) |
Schema | Mapping | Mapping(映射)是索引中文档的约束,例如字段类型约束。类似数据库的表结构(Schema) |
SQL | DSL | DSL是elasticsearch提供的JSON风格的请求语句,用来操作elasticsearch,实现CRUD |
- MySql:擅长事务类型操作,可以确保数据的安全和一致性
- ElasticSearch:擅长海量数据的搜索、分析、计算
两者结合使用,对安全性较高的写操作,使用mysql实现,对查询性能要求较高的搜索需求,使用
3.使用Docker安装ElasticSearch和Kibana
注意:Docker的安装参考(96条消息) 若依前后端分离框架的windows jar包和linux使用docker的部署_随便取个名字.的博客-CSDN博客
3.1.部署单点es
3.1.1.创建网络
因为我们还需要部署kibana容器,因此需要让es和kibana容器互联。这里先创建一个网络:
docker network create es-net
3.1.2.加载镜像
可以直接去DockerHub的es官网选择指定的版本拉取,如果直接执行docker pull elasticsearch
将默认拉取最新版本,本次学习安装的是7.12.1版本,所以执行命令:
docker pull elasticsearch:7.12.1
同理对于kibana
的安装也是按照上图所示,注意版本保持一致
3.1.3.运行
运行docker命令,部署单点es:
docker run -d \
--name es \
-e "ES_JAVA_OPTS=-Xms512m -Xmx512m" \
-e "discovery.type=single-node" \
-v es-data:/usr/share/elasticsearch/data \
-v es-plugins:/usr/share/elasticsearch/plugins \
--privileged \
--network es-net \
-p 9200:9200 \
-p 9300:9300 \
elasticsearch:7.12.1
命令解释:
-e "cluster.name=es-docker-cluster"
:设置集群名称(这里是单节点,所以没有设置)-e "http.host=0.0.0.0"
:监听的地址,可以外网访问-e "ES_JAVA_OPTS=-Xms512m -Xmx512m"
:内存大小(默认是1024m,也就是1G)-e "discovery.type=single-node"
:非集群模式-v es-data:/usr/share/elasticsearch/data
:挂载逻辑卷,绑定es的数据目录-v es-logs:/usr/share/elasticsearch/logs
:挂载逻辑卷,绑定es的日志目录-v es-plugins:/usr/share/elasticsearch/plugins
:挂载逻辑卷,绑定es的插件目录--privileged
:授予逻辑卷访问权--network es-net
:加入一个名为es-net的网络中(也就是上面创建的网络)-p 9200:9200
:端口映射配置
在浏览器中输入:http://xxxx:9200 即可看到elasticsearch的响应结果:
3.2.部署Kibana
kibana可以给我们提供一个elasticsearch的可视化界面,便于我们学习。
3.2.1.部署
拉取完kibana镜像后直接运行以下docker命令
docker run -d \
--name kibana \
-e ELASTICSEARCH_HOSTS=http://es:9200 \
--network=es-net \
-p 5601:5601 \
kibana:7.12.1
参数介绍
--network es-net
:加入一个名为es-net的网络中,与elasticsearch在同一个网络中-e ELASTICSEARCH_HOSTS=http://es:9200"
:设置elasticsearch的地址,因为kibana已经与elasticsearch在一个网络,因此可以用容器名直接访问elasticsearch-p 5601:5601
:端口映射配置
kibana启动一般会比较慢,稍微多等待一会即可
在浏览器输入 http://xxxx:5601 即可进入kibana可视化界面
3.2.2.DevTools
kibana提供了devtools界面,它可以方便我们编写DSL语句来操作elasticsearch,不然也可以借助postman工具来发送请求来操作elasticsearch。
通过上图可以看出默认的分词器的分词效果针对于中文来说效果并不好,它并不能够安装中文代表的意思来进行分词,所以下面安装目前主流的分词器ik
分词器
3.3.安装IK分词器
3.3.1.在线安装IK分词器
# 进入容器内部
docker exec -it elasticsearch /bin/bash
# 在线下载并安装
./bin/elasticsearch-plugin install https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v7.12.1/elasticsearch-analysis-ik-7.12.1.zip
#退出
exit
#重启容器
docker restart elasticsearch
上面方法主要是直接在github上加载ik分词器进入插件目录,相对来说会比较慢
3.3.2.离线安装IK分词器
-
查看数据卷目录
安装插件需要知道elasticsearch的plugins目录位置,而我们前面运行es容器的时候用了数据卷挂载,因此需要查看elasticsearch的数据卷目录,通过下面命令查看:
docker volume inspect es-plugins
说明plugins目录被挂载到了
/var/lib/docker/volumes/es-plugins/_data
-
解压缩分词器安装包
直接进入ik分词器官网,下载对应es版本的安装包,解压缩重新命名为ik文件夹
-
上传到es容器挂载的插件目录
将ik文件夹上传到挂载的插件目录,如下图所示
-
重启es容器
docker restart es
-
测试
ik分词器包含两种模式:
ik_smart
:最少切分(eg:程序员就是拆成程序员)ik_max_word
:最细切分(eg:程序员可以拆成程序员,程序,员)
3.3.3.扩展和停用词典
es的ik分词器能拆分我们中文应该就是底层有一本包含了许多中文词汇的词典,当拆分的词存在这个字典中才进行拆分,但肯定还有许多的词语并不包含在里面,所以当需要扩展词汇的时候操作如下。
-
打开IK分词器config目录:
-
在
IKAnalyzer.cfg.xml
配置文件内容添加:<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd"> <properties> <comment>IK Analyzer 扩展配置</comment> <!--用户可以在这里配置自己的扩展字典 --> <entry key="ext_dict">ext.dic</entry> <!--用户可以在这里配置自己的扩展停止词字典--> <entry key="ext_stopwords">stopword.dic</entry> <!--用户可以在这里配置远程扩展字典 --> <!-- <entry key="remote_ext_dict">words_location</entry> --> <!--用户可以在这里配置远程扩展停止词字典--> <!-- <entry key="remote_ext_stopwords">words_location</entry> --> </properties>
-
新建文件ext.dic,加入想要添加的词语进入即可,注意以回车换行
白嫖 奥力给
-
新建文件stopword.dic 添加停用词
的 了 哦 啊
-
重启es和kibana进行测试
GET /_analyze { "analyzer": "ik_smart", "text": [ "白嫖的真香,奥利给!" ] }
注意当前文件的编码必须是 UTF-8 格式,严禁使用Windows记事本编辑