简介

ElasticSearch是一款非常强大的开源搜素引擎,可以帮助我们从海量数据中快速找到需要的内容

ElasticSearch结合kibanaLogstashBeats,也就是elastic stack(ELK)。被广泛应用在日志数据分析、实时监控等领域

img

基本概念

倒排索引

倒排索引的概念是基于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 %手机%

逐行扫描,也就是全表扫描,随着数据量的增加,其查询效率也会越来越低。当数据量达到百万时,这将是一场灾难

倒排索引

  • 倒排索引中有两个非常重要的概念
    1. 文档(Document):用来搜索的数据,**其中的每一条数据就是一个文档**。
    2. 词条(Term):对文档数据或用户搜索数据,利用某种算法分词,得到的具备含义的词语就是词条
  • 创建倒排索引是对正向索引的一种特殊处理,流程如下
    • 将每一个文档的数据利用算法分词,得到一个个词条
    • 创建表,每行数据包括词条、词条所在文档id、位置等信息
    • 因为词条唯一性,可以给词条创建索引,例如hash表结构索引
词条(term) 文档id
小米 1,3,4
手机 1,2
华为 2,3
充电器 3
手环 4
  • 以搜索华为手机为例
    1. 用户输入条件华为手机,进行搜索。
    2. 对用户输入的内容分词,得到词条:华为、手机。
    3. 拿着词条在倒排索引中查找,可以得到包含词条的文档id为:1、2、3。
    4. 拿着文档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

  1. 创建文档:POST /{索引库名}/_doc/{id}
  2. 查询文档:GET /{索引库名}/_doc/{id}
  3. 删除文档:DELETE /{索引库名}/_doc/{id}
  4. 修改文档
    • 全量修改: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

布尔查询补充

  1. must:必须匹配的条件,可以理解为
  2. should:选择性匹配的条件,可以理解为
  3. must_not:必须不匹配的条件,不参与打分,可以理解为
  4. filter:必须匹配的条件,不参与打分

查询后处理

排序

  1. 普通字段排序
  2. 地理坐标排序

分页

  • 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),可以解决深分页问题
    • 缺点:只能向后逐页查询,不支持随机翻页
    • 场景:没有随机翻页需求的搜索,例如手机的向下滚动翻页

高亮

高亮显示的实现分为两步

  1. 给文档中的所有关键字都添加一个标签,例如<em>标签
  2. 页面给<em>标签编写CSS样式

数据同步

ES中的数据来自于MySQL的数据库,因此MySQL数据发生改变时,ES也必须跟着改变,这就是ES与MySQL之间的数据同步问题

方案:

  • 同步调用
    • 优点:实现简单
    • 缺点:业务耦合度高
  • 异步通知
    • 优点:低耦合,实现难度一般
    • 缺点:依赖MQ的可靠性
  • 监听binlog
    • 优点:完全解除服务间的耦合
    • 缺点:开启binlog增加数据库负担、实现复杂度高