赞
踩
ElasticSearch(下文简称为ES)是一款非常强大的开源搜索引擎,可以从海量数据中快速找到需要的内容。例如:在GitHub搜索代码、在电商网站搜索商品、在百度搜索答案等。
ElasticSearch结合Kibana、Logstash、Beats,被广泛应用在日志数据分析、实时监控等领域。即平常所说的Elastic Stack(ELK)。
ElasticSearch底层是基于Lucene来实现的。Lucene是一个Java语言的搜索引擎类库,是Apache公司的顶级项目,由DougCutting于1999年研发。官网地址:https://lucene.apache.org/。
2004年Shay Banon基于Lucene开发了Compass;2010年Shay Banon 重写了Compass,取名为ElasticSearch。相比Lucene,ElasticSearch优势更明显,它不仅支持分布式,可水平扩展,还提供Restful接口,可被任意语言调用。
例如,有一个数据表tb_goods
,其id
字段创建了索引:
如果是根据id
查询,那么可以直接走索引,查询速度非常快。这种索引就是正向索引。
但如果是基于title
字段做模糊查询,只能是逐行扫描数据,流程如下:
1)用户搜索数据,条件是title
符合"%手机%"
;
2)逐行获取数据,比如获取到id
为1的数据;
3)判断数据中的title
是否符合用户搜索条件;
4)如果符合则放入结果集,不符合则丢弃。
逐行扫描,也就是全表扫描,随着数据量增加,其查询效率也会越来越低。当数据量达到数百万时,就是一场灾难。
倒排索引中有两个非常重要的概念:
Document
):用来搜索的数据,其中的每一条数据就是一个文档。例如一个网页、一个商品信息;Term
):对文档数据或用户搜索数据,利用某种算法分词,得到的具备含义的词语就是词条。例如:我是中国人,就可以分为:我、是、中国人、中国、国人这样的几个词条。创建倒排索引是对正向索引的一种特殊处理,流程如下:
1)将每一个文档的数据利用算法分词,得到一个个词条;
2)创建表,每行数据包括词条、词条所在文档id、位置等信息;
3)因为词条唯一性,可以给词条创建索引。
如上图,“小米”这个词条分别存在于id为1、3、4的文档中。
倒排索引的搜索流程如下(以搜索"华为手机"为例):
1)用户输入条件“华为手机”进行搜索;
2)对用户输入内容分词,得到词条:“华为”、“手机”;
3)拿着词条在倒排索引中查找,可以得到包含词条的文档id:1、2、3;
4)拿着文档id到正向索引中查找具体文档。
先查询倒排索引,再查询倒排索引,但是无论是词条、还是文档id都建立了索引,查询速度非常快,而无需全表扫描。
正向索引一般是根据id索引来查询。但根据关键词查询时,必须先逐条获取每个文档,然后判断文档中是否包含所需要的关键词,是根据文档找词条的过程。
倒排索引则相反,是先找到用户要搜索的词条,根据词条得到保存词条的文档的id,然后根据id获取文档,是根据词条找文档的过程。
优点 | 缺点 | |
---|---|---|
正向索引 | 可以给多个字段创建索引,根据索引字段搜索、排序速度非常快 | 根据非索引字段,或者索引字段中的部分词条查找时,只能全表扫描 |
倒排索引 | 根据词条搜索、模糊搜索时,速度非常快 | 只能给词条创建索引,而不是字段;无法根据字段做排序 |
ES是面向文档(Document)存储的,它可以是数据库中的一条商品数据,或一个订单信息。文档数据会被序列化为json格式后存储在ES中,而json文档中往往包含很多的字段(Field),类似于数据库中的列。 例如:
索引(Index),就是相同类型的文档的集合。 例如:所有用户文档组织在一起,称为用户的索引;所有商品的文档组织在一起,称为商品的索引。
因此,可以把索引当做是数据库中的表。
数据库中的表会有约束信息,用来定义表的结构、字段的名称、类型等信息。类似地,索引中有映射(mapping),是索引中文档的字段的约束信息。
MySQL | Elasticsearch | 说明 |
---|---|---|
Table | Index | 索引(index),就是文档的集合,类似数据库的表(table) |
Row | Document | 文档(Document),就是一条条的数据,类似数据库中的行(Row),文档都是JSON格式 |
Column | Field | 字段(Field),就是JSON文档中的字段,类似数据库中的列(Column) |
Schema | Mapping | Mapping(映射),就是索引中文档的约束,类似数据库的表结构(Schema) |
SQL | DSL | DSL是ES提供的JSON风格的请求语句,用来操作ES,实现CRUD |
MySQL擅长事务类型操作,可以确保数据的安全和一致性;而ES擅长海量数据的搜索、分析、计算。因此在企业中,往往是两者结合使用:
由于需要部署ES和Kibana两个容器,因此需要让ES和Kibana容器互联,为此先创建一个网络:
docker network create es-net
从镜像仓库拉取elasticsearch:7.12.1
镜像:
docker pull elasticsearch:7.12.1
但由于网络问题,拉取失败了。这里直接使用已经下载好的镜像,上传到虚拟机后,执行以下命令加载镜像:
docker load -i es.tar
docker run -d \
--name es \
-e "http.host=0.0.0.0" \
-e "ES_JAVA_OPTS=-Xms512m -Xmx512m" \
-e "discovery.type=single-node" \
-v es-data:/usr/share/elasticsearch/data \
-v es-logs:/usr/share/elasticsearch/logs \
-v es-plugins:/usr/share/elasticsearch/plugins \
--privileged \
--network es-net \
-p 9200:9200 \
-p 9300:9300 \
elasticsearch:7.12.1
命令解释:
-e "http.host=0.0.0.0"
:监听的地址,可以外网访问-e "ES_JAVA_OPTS=-Xms512m -Xmx512m"
:设置内存大小-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
、-p 9300:9300
:端口映射配置在浏览器访问:http://192.168.153.128:9200
,看到ES的响应结果即部署成功:
docker pull kibana:7.12.1
同样,由于网络原因,镜像拉取失败了。这里也直接使用已经下载好的镜像,上传到虚拟机后,执行以下命令加载镜像:
docker load -i kibana.tar
docker run -d \
--name kibana \
-e ELASTICSEARCH_HOSTS=http://es:9200 \
--network=es-net \
-p 5601:5601 \
kibana:7.12.1
命令解释:
-e ELASTICSEARCH_HOSTS=http://es:9200"
:设置ES的地址,因为Kibana已经与ES在一个网络中,因此可以用容器名直接访问ES--network=es-net
:加入一个名为es-net的网络中,与ES在同一个网络中-p 5601:5601
:端口映射配置在浏览器输入地址访问:http://192.168.153.128:5601
,看到Kibana页面即部署成功:
Kibana中提供了一个DevTools界面,这个界面可以编写DSL来操作ES,并且对DSL语句有自动补全功能:
分词器的作用是:创建倒排索引时对文档分词;用户搜索时,对输入的内容分词。
# 进入容器内部
docker exec -it es /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 es
此时ES插件的数据卷目录/var/lib/docker/volumes/es-plugins/_data
下可以看到安装的ik插件:
IK分词器包含两种模式:
ik_smart
:智能切分,粗粒度ik_max_word
:最细切分,细粒度在Kibana提供了DevTools中进行测试:
可见,这两个分词模式得到的结果是不一样的。
日常生活中,有很多新的词语,在原有的词汇列表中并不存在。比如:“奥力给”,“栓Q” 等等。
所以IK分词器提供了扩展词汇的功能,以不断地更新词汇。
# 进入容器内部
docker exec -it es /bin/bash
# 进入分词器插件目录
cd /usr/share/elasticsearch/config/analysis-ik
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>
</properties>
ext.dic
文件,内容如下:奥力给
栓Q
docker restart es
docker logs -f es
在互联网中,有很多词汇是不允许在网络上传递的,例如关于宗教、政治等敏感词语。为此,IK分词器提供了强大的停用词功能,让我们在索引时就直接忽略停用词汇表中的内容。
# 进入容器内部
docker exec -it es /bin/bash
# 进入分词器插件目录
cd /usr/share/elasticsearch/config/analysis-ik
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>
</properties>
stopword.dic
文件,内容如下:你太美
docker restart es
docker logs -f es
索引类似于数据库中的表,mapping映射就类似于表结构。因此,要向ES中存入数据,就必须先创建“表”和“表结构”。
mapping映射属性就是对索引库中文档的约束,常见的mapping映射属性有:
type:数据类型,常见的类型有:
index:是否创建索引,默认为true
analyzer:使用哪种分词器
properties:该字段的子字段
例如下面这个文档:
{
"age": 1000,
"weight": 52.1,
"isMarried": false,
"info": "战斗力最强的人",
"email":"swk@xyj.cn",
"score":[99.1, 99.5, 98.9],
"name":{
"firstName": "孙",
"lastName": "悟空"
}
}
基本语法:
基本语法:
倒排索引结构虽然不复杂,但是一旦数据结构改变(比如改变了分词器),就需要重新创建倒排索引,这又是无法接受的。
因此索引库一旦创建,就无法修改mapping。但是却允许添加新的字段到mapping中,因为这个操作不会对倒排索引产生影响。
基本语法:
基本语法:
…
本节完,更多内容请查阅分类专栏:微服务学习笔记
感兴趣的读者还可以查阅我的另外几个专栏:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。