ElasticSearch
简介
ElasticSearch
是一款非常强大的开源搜素引擎,可以帮助我们从海量数据中快速找到需要的内容
ElasticSearch
结合kibana
、Logstash
、Beats
,也就是elastic stack
(ELK)。被广泛应用在日志数据分析、实时监控等领域
基本概念
倒排索引
倒排索引的概念是基于MySQL这样的正向索引而言的
正向索引
例如给下表中的id创建索引:
id | title | price |
---|---|---|
1 | 小米手机 | 3499 |
2 | 华为手机 | 4999 |
3 | 华为小米充电器 | 49 |
4 | 小米手环 | 49 |
如果是基于id查询,那么直接走索引,查询速度非常快。
但是实际应用里,用户并不知道每一个商品的id,他们只知道title(商品名称),所以对于用户的查询方式,是基于title(商品名称)做模糊查询,只能是逐行扫描数据
1 | select id, title, price from tb_goods where title like %手机% |
逐行扫描,也就是全表扫描,随着数据量的增加,其查询效率也会越来越低。当数据量达到百万时,这将是一场灾难
倒排索引
- 倒排索引中有两个非常重要的概念
- 文档(Document):用来搜索的数据,**其中的每一条数据就是一个文档**。
- 词条(Term):对文档数据或用户搜索数据,利用某种算法分词,得到的具备含义的词语就是词条
- 创建倒排索引是对正向索引的一种特殊处理,流程如下
- 将每一个文档的数据利用算法分词,得到一个个词条
- 创建表,每行数据包括词条、词条所在文档id、位置等信息
- 因为词条唯一性,可以给词条创建索引,例如hash表结构索引
词条(term) | 文档id |
---|---|
小米 | 1,3,4 |
手机 | 1,2 |
华为 | 2,3 |
充电器 | 3 |
手环 | 4 |
- 以搜索华为手机为例
- 用户输入条件
华为手机
,进行搜索。 - 对用户输入的内容分词,得到词条:华为、手机。
- 拿着词条在倒排索引中查找,可以得到包含词条的文档id为:1、2、3。
- 拿着文档id到正向索引中查找具体文档
- 用户输入条件
- 虽然要先查询倒排索引,再查询正向索引,但是无论是词条还是文档id,都建立了索引,所以查询速度非常快,无需全表扫描
正向和倒排
- 那么为什么一个叫做正向索引,一个叫做倒排索引呢?
正向索引
是最传统的,根据id索引的方式。但是根据词条查询是,必须先逐条获取每个文档,然后判断文档中是否包含所需要的词条,是根据文档查找词条的过程
- 而
倒排索引
则相反,是先找到用户要搜索的词条,然后根据词条得到包含词条的文档id,然后根据文档id获取文档,是根据词条查找文档的过程
- 二者优缺点?
- 正向索引
- 优点:可以给多个字段创建索引,根据索引字段搜索、排序速度非常快
- 缺点:根据非索引字段,或者索引字段中的部分词条查找时,只能全表扫描
- 倒排索引
- 优点:根据词条搜索、模糊搜索时,速度非常快
- 缺点:只能给词条创建索引,而不是字段,无法根据字段做排序
- 正向索引
ES的一些概念
ElasticSearch中有很多独有的概念,与MySQL中略有差别,但也有相似之处
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 |
分词器
- 分词器的作用是什么?
- 创建倒排索引时对文档分词
- 用户搜索时,对输入的内容分词
- IK分词有几种模式?
- ik_smart:智能切分,粗粒度
- ik_max_word:最细切分,细粒度
- IK分词器如何拓展词条?如何停用词条?
- 利用config目录的IKAnalyzer.cfg.xml文件添加拓展词典和停用词典
- 在词典中添加拓展词条或者停用词条
CRUD
- 创建文档:POST /{索引库名}/_doc/{id}
- 查询文档:GET /{索引库名}/_doc/{id}
- 删除文档:DELETE /{索引库名}/_doc/{id}
- 修改文档
- 全量修改:PUT /{索引库名}/_doc/{id}
- 增量修改:POST /{索引库名}/_update/{id}
DSL
分类
常见的查询类型包括:
查询所有:查询出所有数据,一般测试用。例如
- match_all
全文检索(full text):利用分词器对用户输入的内容分词,然后去倒排索引库中匹配。例如
- match查询:单字段查询
- multi_match查询:多字段查询,任意一个字段符合条件就算符合查询条件
精确查询一般是查找keyword、数值、日期、boolean等类型字段。所以不会对搜索条件分词。常见的有
term
:根据词条精确值查询range
:根据值的范围查询
地理查询(geo):根据经纬度查询。例如
- geo_distance
- geo_bounding_box
复合查询(compound):复合查询可以将上述各种查询条件组合起来,合并查询条件。例如
- bool
- function_score
布尔查询补充
- must:必须匹配的条件,可以理解为
与
- should:选择性匹配的条件,可以理解为
或
- must_not:必须不匹配的条件,不参与打分,可以理解为
非
- filter:必须匹配的条件,不参与打分
查询后处理
排序
- 普通字段排序
- 地理坐标排序
分页
- ES默认情况下只返回
top10
的数据。而如果要查询更多数据就需要修改分页参数了。 - ES中通过修改from、size参数来控制要返回的分页结果
from
:从第几个文档开始size
:总共查询几个文档
- 类似于mysql中的
limit ?, ?
深分页问题
ES中查询后面的第990到1000条的数据也是像MySQL一样,查询出前1000条再过滤,那么压力就会很大
即使是分了集群,其实也是要在各个集群中都取前1000条,然后在各个集群中将这些1000条汇总再取,会对内存和CPU产生非常大的压力,因此ES会禁止
form + size > 10000
的请求
分页查询的常见实现方案以及优缺点
- from + size:
- 优点:支持随机翻页
- 缺点:深度分页问题,默认查询上限是10000(from + size)
- 场景:百度、京东、谷歌、淘宝这样的随机翻页搜索(百度现在支持翻页到75页,然后显示
提示:限于网页篇幅,部分结果未予显示。
)
- after search:
- 优点:没有查询上限(单词查询的size不超过10000),可以解决深分页问题
- 缺点:只能向后逐页查询,不支持随机翻页
- 场景:没有随机翻页需求的搜索,例如手机的向下滚动翻页
高亮
高亮显示的实现分为两步
- 给文档中的所有关键字都添加一个标签,例如
<em>
标签 - 页面给
<em>
标签编写CSS样式
数据同步
ES中的数据来自于MySQL的数据库,因此MySQL数据发生改变时,ES也必须跟着改变,这就是ES与MySQL之间的数据同步问题
方案:
- 同步调用
- 优点:实现简单
- 缺点:业务耦合度高
- 异步通知
- 优点:低耦合,实现难度一般
- 缺点:依赖MQ的可靠性
- 监听binlog
- 优点:完全解除服务间的耦合
- 缺点:开启binlog增加数据库负担、实现复杂度高