天天看点

6.X elasticsearch实战学习笔记_底层原理

一、倒排索引

  1. 倒排索引

    词项(term) : 搜索时的一个单位,代表文本中某个词

    倒排索引结果是一种将词项映射得到文档的数据结构

  2. 倒排索引建立步骤

    a. 提取词项

    首先对文档分词,英文文档用空格分隔

    去除无实际意义的词,如is、a、in、as等

    对单词统一大小写

    单复数,过去式、进行时转换

    过滤标点符号

    【本步骤,将无用的过滤掉并统一词项格式】

    b. 建立倒排索引

    将词项映射到文档

    【将提取的词项,映射到文档,一个词项可对应多个文档】

    c. 建立词项出现的频率、位置和偏移量

    文档ID:用于根据词项定位文档的原始信息

    频率:记录词项在文档出现的次数,用于搜索相关性算分

    位置:记录在文档中是第几个关键字,用于词组查询

    偏移量:记录开始和结束的位置,用于做高亮显示

6.X elasticsearch实战学习笔记_底层原理

二、 底层内部原理

  1. 倒排索引不可变性

    倒排索引写进磁盘永不会被改变

  • 因此无需锁,不必担心多进程同时修改数据问题
  • 大部分读请求直接请求内存,不命中磁盘
  • 不会因为数据改变而重建缓存中数据
  • 单个大的倒排索引允许数据被压缩
  • 不支持部分文档更新
  • 新文档可被搜索,需重建整个倒排索引,限制索引包含数据量,索引更新频率
  1. Lucene按段搜索(per-segment)
  • 段文件(segment file):存储倒排索引的文件,每个segment是一个倒排索引。文档写入lucene,并且生成完整的segment后才能被搜索
  • 提交点(Commit point):记录所有已知段的文件
  • 事务日志(translog):防止es宕机导致数据丢失,es每次写入数据同时写入translog。

ps:在倒排索引的不可变前提下,实现倒排索引的数据增删改

  • 使用更多索引,按段搜索
  • 一个lucene索引包含:segment的集合、Commit point文件
  • 按segment搜索,每个segment是一个倒排索引,通过增加新的索引反应最近的修改,而不重写整个倒排索引,当有数据查询请求,每个倒排索引都被遍历,从最早的开始,查询完后对结果合并。
  • 实现按段搜索,索引工作流程
    1. 当新文档被索引时,先收集到内存缓存
    1. (提交缓存)将缓存中对象转换为segment存储到磁盘,在Commit point 记录新段信息
    1. (开启新段)新的段被open,此时新段包含的文档可被搜索
    1. 清空内存缓存数据,等接受新文档
  • 文档的删除和更新
    1. 每个Commit point 包含一个.del文件,该文件会列出这些被删除文档的段信息
    1. 当一个文档被删时,实际只在.del文件中被标记删除,被标记删除的文档依然可被查询得到,但在最终结果被返回前从结果集中删除
    1. 当一个文档更新时,旧文档被标记删除,新文档被索引到一个新的段,两个文档可能被一个查询匹配到,但在结果返回前会在结果集中删除
  • ps:段合并后,标记删除的文档会移除
  • 查询流程
    1. 查询被触发
    1. 从Commit point 获取已知段信息,按顺序查询所有段
    1. 聚合所有段的查询结果
    1. 较小成本实现新文档添加到索引
  • 按段搜索的问题
    1. 每次commit一个新segment,需将数据fsync到物理磁盘,fsync代价大,每次索引一个文档就fsync一次,代价很大
  1. 近实时
  • 为解决按segment搜索的问题,先将写入内容缓存的lucene数据转换为segment存入文件系统缓存,等合适时机再将文件系统缓存中的数据提交,fsync到磁盘持久化
    1. 先将文档写入内存缓存
    1. 将内存缓存中数据转为segment,存入文件系统缓存,重新reopen,该过程是refresh(一般1秒refresh一次)
    1. 等合适时机,将文件系统缓存中数据提交,fsync到磁盘持久化
  • 引入文件系统缓存的遗留问题
    1. 没flush到磁盘的数据,若发生断电、宕机,缓存数据会丢失
  • 断电、宕机数据不丢失
  • es引入translog模块,将将数据同时写入内存缓存(lucene)和translog,数据发生丢失时,可从translog重新将数据恢复
  1. es索引数据完整流程
    1. 写lucene和translog
  • 当索引文档(写数据时),先将文档写入lucene,此时lucene在内存中,然后写translog,写成功后将请求发给用户
    1. 使搜索可见
  • 将内存中对象转为segment,再reopen,该操作为refresh
    1. 刷Translog日志
  • 将内存中的translog刷到磁盘,默认5秒一次
    1. 执行lucene提交(flush)
  • 将内存中segment刷到磁盘,更新commit point,清空translog,打开新的translog,默认translog达到512M,flush一次
  1. 段合并
  • 自动refresh,每秒会创建一个新的segment,不加处理会导致搜索变慢
  • 段合并流程
    1. 合并进程选一部分大小相似的segment,在后台 合并到更大的segment,不会中断索引和搜索
    1. 合并结束后,老segment被删,新segment被flush到磁盘,写入一个包含新segment且排除旧的和较小的segment,新的commit point
    1. 新的segment被用来搜索,老的segment被删

继续阅读