Elasticsearch由浅入深(十一)内核原理

Stella981
• 阅读 784

倒排索引组成结构以及索引不可变原因

对于倒排索引是非常适合用来进行搜索的
它的结构:
(1)包含这个关键词的document list
(2)包含这个关键词的所有document的数量:IDF(inverse document frequency)
(3)这个关键词在每个document中出现的次数:TF(term frequency)
(4)这个关键词在这个document中的次序
(5)每个document的长度:length norm
(6)包含这个关键词的所有document的平均长度
其实本质上主要是为了计算相关度分数

_score = boost * idf * tf 
此时boost = 2.2, idf = 0.18232156, tf = 0.5116279

idf = log(1 + (N - n + 0.5) / (n + 0.5))
此时n = 2 (n, number of documents containing term), 
N = 2(N, total number of documents with field)

tf = freq / (freq + k1 * (1 - b + b * dl / avgdl))
此时freq = 1(freq, occurrences of term within document), 
k1 = 1.2(k1, term saturation parameter), 
b = 0.75(b, length normalization parameter), 
d1 = 4 (dl, length of field), 
avgdl = 5.5(avgdl, average length of field)

倒排索引的不可变好处

(1)不需要锁,提升了并发能力,避免锁的问题
(2)数据不变,一直保存在OS cache中,只要cache内存足够
(3)filter cache一直驻留在内存
(4)可以压缩,节省cpu和io开销
这个对应的就是primary shard的数量不变,不能修改field的属性(将date改成text)

倒排索引不可变的坏处

(1)每次都需要重新构建整个索引

document写入原理

(1)数据写入buffer
(2)commit point
(3)buffer中的数据写入新的index segment
(4)等待在OS cache中的index segment被fsync强制刷到磁盘上
(5)新的index segment被打开,供search使用
(6)buffer被清空

下面做几点说明:

1、在Elasticsearch中,底层用的是lucene,lucene底层的index是分为多个segment的,每个segment都会存放部分数据。
2、如果是删除操作,每次commit的时候,就会生成一个.del文件,标明哪个index segment的哪个document被删除了。
3、如果是更新操作,实际上是将的doc标记为deleted,然后将新的document写入新的index segment中。下次search过来的时候,也许会匹配到一个document的多个版本,但是之前的版本已经被标记为deleted了,所以只会返回最新版本的doc
4、如果搜索请求过来,在index segment中,匹配到了id=1的doc,此时会发现在.del文件中已经被标识为deleted了,这种数据就会被过滤掉,不会作为搜索结果返回。
图示如下:

Elasticsearch由浅入深(十一)内核原理

写入流程近实时NRT(filesystem cache,refresh)

现有的流程的问题,每次都必须等待fsync将segment刷入磁盘,才能将segment打开供search使用,这样的话,从一个document写入,到它可以被搜索,可能会超过1分钟,这也就不是近实时的搜索了。主要的瓶颈在于fsync从磁盘IO写数据进磁盘是很耗时的。
ES写入流程的改进:
(1)数据写入buffer
(2)每个一定时间,buffer中的数据被写入segment文件,但是先写入OS cache
(3)只要segment写入OS cache,那就直接打开供search使用,不立即执行commit
数据写入OS cache,并被打开供搜索的过程,叫做refresh,默认是每隔一秒refresh一次,也就是说,每隔一秒就会将buffer中的数据写入OS cache中,写入一个新的index segment file。所以ES是近实时的,数据写入到可以被搜索,默认是1秒。
一般不用修改,让ES自己搞定就好了,要修改的话,通过refresh_interval参数即可
格式:

Elasticsearch由浅入深(十一)内核原理

写入流程的实现 durability可靠存储(translog,flush)

最终流程:

(1)数据写入buffer缓存和translog日志文件
(2)每隔一秒,buffer中的数据被写入新的segment file,并进入os cache,此时segment被打开并供search使用
(3)buffer被清空
(4)重复1~3,新的segment不断添加,buffer不断被清空,而translog中的数据不断累加
(5)当translog长度达到一定程度的时候,commit操作发生
    (5.1)buffer中的所有数据,写入一个新的segment,并写入os cache,打开供使用
    (5.2)buffer被清空
    (5.3)一个commit point被写入磁盘,标明了所有的index segment
    (5.4)filesystem cache中的所有index segment file缓存数据,被fsync强制刷到磁盘上
    (5.5)现有的translog被清空,创建一个新的translog

translog

对Lucene的更改仅在Lucene提交期间持久保存到磁盘,这是一项相对昂贵的操作,因此无法在每次索引或删除操作后执行。如果进程退出或硬件发生故障,Lucene将在一次提交之后和另一次提交之前发生的更改将从索引中删除。

因为Lucene提交对于每个单独的更改都执行起来太昂贵,所以每个分片副本还有一个事务日志,称为与之关联的translog。所有索引和删除操作在由内部Lucene索引处理之后但在确认之前写入translog。在发生崩溃的情况下,最新的已确认但尚未包含在上一个Lucene提交中的事务可以在分片恢复时从translog中恢复。

Elasticsearch flush是执行Lucene提交并启动新的translog的过程。在后台自动执行刷新以确保translog不会变得太大,这将使得在恢复期间重放其操作需要相当长的时间。手动执行刷新的能力也通过API公开,尽管很少需要。

translog设置

translog中的数据仅在fsync编辑和提交translog时持久保存到磁盘 。如果发生硬件故障,自上次translog提交以来写入的任何数据都将丢失。

默认情况下,fsync如果index.translog.durability设置为async或request 在每个索引,删除, 更新或 批量请求结束时设置为(默认),则Elasticsearch会每隔5秒提交一次translog 。更确切地说,如果设置为request,则fsync在主数据库和每个已分配的副本服务器上成功编辑和提交translog之后,Elasticsearch将仅向客户端报告索引,删除,更新或批量请求的成功 。

以下可动态更新的每索引设置控制translog的行为:

index.translog.sync_interval
    fsync无论写入操作 如何,translog都经常被写入磁盘并提交。默认为5s。小于的值100ms是不允许的。
index.translog.durability
    是否fsync在每个索引,删除,更新或批量请求之后提交translog。此设置接受以下参数:
        request
        (默认)fsync并在每个请求后提交。如果发生硬件故障,所有已确认的写入都已提交到磁盘。
        async
        fsync并在每个背景中提交sync_interval。如果发生硬件故障,将丢弃自上次自动提交以来的所有已确认写入。
index.translog.flush_threshold_size
    translog存储尚未安全保存在Lucene中的所有操作(即,不是Lucene提交点的一部分)。尽管这些操作可用于
    读取,但如果要关闭并且必须恢复,则需要重新编制索引。此设置控制这些操作的最大总大小,以防止恢复时间
    过长。达到最大大小后,将发生刷新,生成新的Lucene提交点。默认为512mb。
index.translog.retention.size
    要保留的translog文件的总大小。保留更多的translog文件会增加在恢复副本时执行基于同步操作的机会。如
    果translog文件不足,副本恢复将回退到基于文件的同步。默认为512mb
index.translog.retention.age
    保留translog文件的最长持续时间。默认为12h。

PUT /my_index/_settings
{
    "index.translog.durability": "async",
    "index.translog.sync_interval": "5s"
}

图示如下:

Elasticsearch由浅入深(十一)内核原理

数据恢复

假设os cache中囤积了一些数据,但是此时不巧,宕机了,os cache中的数据全部丢失,那么我们怎么进行数据恢复呢?
我们知道写doc的时候也会写入translog,那么translog就存储了上一次flush直到现在最近的数据变更记录。机器被重启之后,disk上的数据并没有丢失,此时就会将translog文件中的变更记录进行回收,重新执行之前的各种操作,在buffer中执行,在重新刷一个一个的segment到os cache中,等待下一次commit发生即可。

海量磁盘文件的合并(segment merge,optimize)

每秒一个segment file,会导致文件过多,而且每次search都要搜索所有的segment,很耗时。所以在Elasticsearch内部会默认在后台执行segment merge操作(forcemerge),在merge的时候,被标记为deleted的document也会被彻底物理删除掉。
每次merge的操作流程:
(1)选择一些有相似大小的segment,merge成一个大的segment
(2)将新的segment flush到磁盘上去
(3)写一个新的commit point,包括了新的segment,并且排除旧的那些segment
(4)将新的segment打开供搜索
(5)将旧的segment删除 

POST /my_index/_optimize?max_num_segments=1,尽量不要手动执行,让它自动默认执行就可以了
点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
添砖java的啾 添砖java的啾
3年前
distinct效率更高还是group by效率更高?
目录00结论01distinct的使用02groupby的使用03distinct和groupby原理04推荐groupby的原因00结论先说大致的结论(完整结论在文末):在语义相同,有索引的情况下groupby和distinct都能使用索引,效率相同。在语义相同,无索引的情况下:distinct效率高于groupby。原因是di
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
待兔 待兔
5个月前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
Jacquelyn38 Jacquelyn38
3年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
Wesley13 Wesley13
3年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Stella981 Stella981
3年前
Django中Admin中的一些参数配置
设置在列表中显示的字段,id为django模型默认的主键list_display('id','name','sex','profession','email','qq','phone','status','create_time')设置在列表可编辑字段list_editable
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Stella981 Stella981
3年前
ELK学习笔记之ElasticSearch的索引详解
0x00ElasticSearch的索引和MySQL的索引方式对比Elasticsearch是通过Lucene的倒排索引技术实现比关系型数据库更快的过滤。特别是它对多条件的过滤支持非常好,比如年龄在18和30之间,性别为女性这样的组合查询。倒排索引很多地方都有介绍,但是其比关系型
Python进阶者 Python进阶者
11个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这