浅谈ElasticSearch原理

1,544 阅读9分钟

前言

随着大数据技术的发展,基于关系型数据库的查询无法满足庞大数据量下的秒级返回速度,es成为面试中的一项重要加分项。今天爆肝一波es相关八股文,供自己跳槽时复习参考,也跟大家分享一波。

基本概念

  1. index索引

    • 索引类比称mysql中的database数据库,存储数据的地方
  2. type类型

    • 类型用于定义数据结构,类似mysql的一张表,属于index中的逻辑分类
    • 但是在同索引中所有相同名字的字段的 mapping 定义必须是一致的,因为在底层 Lucene 只会存一份。后续es删除了type的概念
  1. mapping
    • 定义存储字段类型
  1. document
    • 类比mysql中一行数据,不同之处在于es中每个文档可以有不同的字段
  1. field字段
    • 类比mysql中的字段,属于es的最小单位
  1. shard分片
    1. 一个分片是一个底层的工作单元,仅保存全部数据的一部分,文档被存储到分片内。
    2. 分片是数据的容器,文档保存在分片内,分片又被分配到集群内的各个节点里。
    3. 单台机器无法存储大量数据,es可以将一个索引中的数据切分称多个shard,分布在多台机器上存储。有了shard就可以横向扩展,存储更多数据。
    4. 分散搜索、分析到多台机器上分散压力,提高吞吐量和性能
    5. 主分片:在索引建立的时候就已经确定了主分片数,但是副本分片数可以随时修改,索引内任意一个文档都归属于一个主分片,所以主分片的数目决定着索引能够保存的最大数据量。
    6. 副分片:一个副本分片只是一个主分片的拷贝。副本分片作为硬件故障时保护数据不丢失的冗余备份,并为搜索和返回文档等读操作提供服务。
  1. replica副本
    • 任何一个服务器随时可能发生故障,丢失shard,因此每个shard都有多个副本,replica可以在shard发发生故障时提供备用服务,保证数据不丢失

    • 多个replica还可以提升搜索操作的吞吐量和性能

什么是倒排索引

  1. 每个文档都对应一个文档id,文档的内容被表示为一系列关键词集合,比如,某个文档经过分词提取了20个关键字,每个关键字都会记录它在文档中出现的次数和位置
  1. 倒排索引就是关键字到文档id的映射关系,每个关键字对应一系列的文档id,这样用户搜索关键字可以根据倒排索引快速定位到文档
  2. 倒排索引中词汇根据字典序升序排列,一个词对应多个文档id

ElasticSearch为什么快

  1. 相比与传统mysql数据库,会根据主键id字段建立b+树聚簇索引, 非主键字段建立b+树非聚簇索引查找到对应主键回表查询数据,而对于全文检索like%张三则走不到索引。

name:

TermPosting List(文档id集合)
张三【1】
张四【2】
李四【3】
李五【4】

age:

TermPosting List(文档id集合)
23【2,3】
24【1,4】
  1. posting list

    1. Elasticsearch会为每个field都建立了一个倒排索引,张三、李四为term(分词),而[1,4]就是posting List。Posting list就是一个int的数组,存储了所有包含某个term的文档id
    2. 通过posting list这种索引方式似乎可以很快进行查找,比如要找age=24的同学,很快就会找到,id是1,4的同学。但是,如果有上千万的记录呢?如果是想通过name来查找呢?所以需要将Term进行排序
  2. term dict

    1. 为了快速找到某个特定的term,将所有的term进行排序。再采用二分查找法查找term。时间复杂度logN,类似B-Tree的方式
  3. term index

    1. 包含term的一些前缀。所以term index 占用的空间只有term的的几十分之一。在内存里可以放更多的term index。缓存所有的term index到内存里是可以的。 Term Index,就像字典里的索引页一样,A开头的有哪些term,分别在哪页,可以理解term index是一颗树存储在内存中

image

ElasticSerach基本语法

  1. query:代表查询,搜索 类似于SQL的select关键字

  2. aggs:代表聚合,类似于SQL的group by 关键字,对查询出来的数据进行聚合 求平均值最大值等

  3. highlight:对搜索出来的结果中的指定字段进行高亮显示,搜索“中华人民共和国万岁”,结果里面符合搜索关键字 全部是红色的高亮显示。

  4. sort: 指定字段对查询结果进行排序显示,类比SQL的order by关键字

  5. from和*size: 对查询结果分页,类似于SQL的limit关键字

  6. post_filter:后置过滤器,在聚合查询结果之后,再对查询结果进行过滤。

ElastcSearch的字段类型

  1. string类型
  2. text类型
  3. keyword类型
  4. 数值类型
  5. 日期类型
  6. 布尔类型
  7. 二进制

ElasticSerach的_source字段

  • es在创建索引文档时,会将所有的字段json序列化,保存为_source字段
  • 功能
  • 重做索引
    • 修改mapping和分析器
    • 高亮提醒
    • 便于调试
  • 是否保存
    • 取决于什么类型的数据,日志类型的索引基本不用保存

    • 为了避免过多占用磁盘空间,可以开启文件压缩

ElasticSerach的调度处理

  • 写数据

image

  1. 在文档写入时,会根据_routing来计算(OperationRouting类)得出文档要写入哪个分片
  2. 写入请求只会写主分片,当主分片写入成功后,会同时把写入请求发送给所有的副本分片,当副本分片写入成功后,会传回返回信息给主分片,主分片得到所有副本分片的返回信息后,再返回给客户端。(类似kafka副本机制)
  • 搜索数据
  1. 客户端发送请求到一个 coordinate node(调度节点)
  2. 协调节点将搜索请求转发到该索引所有的 shard 对应的 primary shard或 replica shard 上
    • query phase
      1. 每个 shard 将自己的搜索结果(一些 doc id )返回给协调节点,由协调节点进行数据的合并、排序、分页等操作,产出最终结果
    • fetch phase(读数据过程):
      1. 接着由协调节点根据 doc id 去各个节点上拉取实际的 doc 数据,最终返回给客户端
      2. 写请求是写入 primary shard,然后同步给所有的 replica shard;
      3. 读请求可以从 primary shard 或 replica shard 读取,采用的是随机轮询算法

ElasticSearch深度分页

  • scroll分页
    • 使用scroll分页可以模拟一个游标.记录当前读取的文档位置.
    • 这个分页用法会在 es服务端维护一个当前索引的快照信息,在此快照创建以后任何新增的数据,都无法在这个快照中查询到,所以这种分页用法不能用于实时查询数据,而是用于一次查询大量的数据.
  • search_after分页
    • 是一种假分页方式,根据上一页的最后一条数据来确定下一页的位置

    • 同时在分页请求的过程中,如果有索引数据的增删改查,这些变更也会实时的反映到游标上。为了找到每一页最后一条数据,每个文档必须有一个全局唯一值

    • 官方推荐使用 _uid 作为全局唯一值,但是只要能表示其唯一性就可以。

ElasticSearch的写入过程

  1. 数据先写入内存buffer(lucene内存) ,在buffer里的数据搜索不到;同时写入translog文件
  2. buffer在一定的时间或者容量满了,会将内存buffer数据刷新到操作系统内存(es内存)中的segment文件,此时数据可见。 此动作1s执行1次
  3. translog文件默认每5秒刷新到磁盘中
  4. 异步从缓存中将segment刷新到磁盘,记录commit ponit,segment会定时merge
    1. 将多个segment合并成一个,将新的segement写入磁盘

    2. 新增一个 commit point,标识所有新的 segment

    3. 新的 segment 被打开供搜索使用

    4. 删除旧的 segment

ElasticSearch的删除和更新过程

  1. 删除和更新都是写操作,但是由于 Elasticsearch 中的文档是不可变的,因此不能被删除或者改动以展示其变更;所以 ES 利用 .del 文件 标记文档是否被删除,磁盘上的每个段都有一个相应的.del 文件
  1. 如果是删除操作,文档其实并没有真的被删除,而是在 .del 文件中被标记为 deleted 状态。该文档依然能匹配查询,但是会在结果中被过滤掉。
  2. 如果是更新操作,就是将旧的 doc 标识为 deleted 状态,然后创建一个新的 doc。
  1. 每次segment merge 的时候,会将多个 segment 文件合并成一个,同时这里会将标识为 deleted 的 doc 给物理删除掉,不写入到新的 segment 中,然后将新的 segment 文件写入磁盘,这里会写一个 commit point ,标识所有新的 segment 文件,然后打开 segment 文件供搜索使用,同时删除旧的 segment 文件

ElasticSearch的搜索过程

  1. 搜素分为两个阶段执行,Query、Fetch
  2. Query
    1. 客户端发送请求到 coordinate node,协调节点将搜索请求广播到所有的 primary shard 或 replica shard。每个分片在本地执行搜索并构建一个匹配文档的大小为 from + size 的优先队列。每个分片返回各自优先队列中 所有文档的 ID 和排序值 给协调节点,由协调节点及逆行数据的合并、排序、分页等操作,产出最终结果。
  1. Fetch
    1. 协调节点根据 doc id 去各个节点上查询实际的 document 数据,由协调节点返回结果给客户端。
    2. coordinate node 对 doc id 进行哈希路由,将请求转发到对应的 node,此时会使用 round-robin 随机轮询算法,在 primary shard 以及其所有 replica 中随机选择一个,让读请求负载均衡。
    3. 接收请求的 node 返回 document 给 coordinate node 。
    4. coordinate node 返回 document 给客户端。