【Elasticsearch】 之 Translog/FST/FOR/RBM算法

news2024/11/28 20:57:33

目录

Translog

FST/FOR/RBM算法解析

FST

FOR(Frame of Reference):

RBM(Roaring Bitmaps)-(for filter cache)


Translog

es是近实时的存储搜索引。近实时,并不能保证被立刻看到。数据被看到的时候数据已经作为一个提交点,被写入到了文件系统中(这个过程称为refresh)。因为一次写入的成本相对比较大,所以用攒一波批量提交的方式,写入性能会更好。不管这些数据都是在堆内存中还是在文件系统中(Filesystem Cache),如果发生断电,或者JVM的崩溃,则这部分数据一定会丢失。为了防止数据丢失,这部分数据会被写入到traslog中一份。当然这个写入translog的代价远小于作为一个提交点写入到分片中(lucene实例中)的代价小。commit 是一个开销比较大的操作,因此不可能每次写入或删除都调用 commit,为了保证数据的可靠性,ES 引入了 Translog。ES 每次调用 Lucene 的接口写入或删除数据后,都会将操作日志记录到 Translog 中防止意外断电或程序奔溃导致数据丢失。写入时机如下:

2. 设置

  • 同步间隔(index.translog.sync_interval)
    Translog 的日志每次都会写入到操作系统的缓存中,只有执行 fsync 刷盘后才是安全的。因此 ES 会每隔一段时间执行 fsync 刷盘。默认时间间隔是 5s,最低不能低于 500ms。注:改参数只针对异步落盘方式才生效。
  • 刷盘方式(index.translog.durability)
    Translog 的刷盘方式有两种:同步(request)和异步(async)
    ES 默认使用的是 request,即每次写入、更新、删除操作后立刻执行 fsync 落盘。
    如果使用异步的方式,则根据同步间隔周期性的刷盘。
    两种方式各有千秋,同步刷盘具备更强数据可靠性保障,但同时带来更高的 IO 开销,性能更低。异步刷盘牺牲了一定的可靠性保障,但是降低了 IO 的开销,性能更佳,因此需要根据不同的场景需求选择合适的方式。
  • 大小阈值 (index.translog.flush_threshold_size)
    我们不可能让 translog 的大小无限增长。translog 的大小过大会带来如下问题:占用磁盘空间;节点恢复需要同步 translog 回放日志,如果太大会导致恢复时间过长。因此,需要设定一个阈值,当日志量达到该阈值时,触发 flush,生成一个新的提交点,提交点之前的日志便可以删除了(具体能否删除还需结合日志的保留时长和保留大小而定)。
  • 日志保留大小(index.translog.retention.size)
    该设置项控制 translog 保留的大小。translog 保留的目的是为了在副本故障恢复时,提高恢复速度(主保留 translog,从恢复时,只需将 global checkpoint 后的日志发送给从就 ok 了)
  • 日志保留时长(index.translog.retention.age)
    同上,满足任一条件即可
  • 日志 generation 阈值大小(index.translog.generation_threshold_size)
    为了避免 translog 越来越大,增加恢复的时间。在 translog 达到阈值时,会执行 flush,触发 lucene commit,并滚动 translog 生成新的文件,当前 generation 前的操作数据都会提交到 lucene 持久化,恢复时,只需恢复当前 translog 中的操作即可。

FST/FOR/RBM算法解析

我们初步了解的倒排索引的结构组成部分: term index ,term dictionary , postings list;

es 底层针对每个组成部分都对应的一些算法操作来保证性能;

 term dictionar

       ES 为了能快速查找到 term,将所有的 term 排了一个序,二分法查找。类似 MySQL 的索引方式的,直接用 B+树建立索引词典指向被索引的数据。

term index

   Term Dictionary 是分词以后得到的词条,数据量是很大的,不可能无节制的保存到内存中,容易内存溢出;而磁盘 io 那么慢。ES 默认可是会对全部 text 字段进行索引,必然会消耗巨大的内存,为此 ES 针对索引进行了深度的优化。在保证执行效率的同时,尽量缩减内存空间的占用。于是用到 term index;

    Term index 从数据结构上分类算是一个字典树。这是一种专门处理字符串匹配的数据结构,用来解决在一组字符串集合中快速查找某个字符串的问题。

这棵树不会包含所有的 term,它包含的是 term 的一些前缀(这也是字典树的使用场景,公共前缀)。通过 term index 可以快速地定位到 term dictionary 的某个 offset,然后从这个位置再往后顺序查找。就想上图所表示的。

lucene 在这里还做了两点优化,一是 term dictionary 在磁盘上面是分 block 保存的,一个 block 内部利用公共前缀压缩,比如都是 Ab 开头的单词就可以把 Ab 省去。二是 term index 在内存中是以 FST-有效状态机(finite state transducers)的数据结构保存的。

FST

但是它是k:v结构的,能够根据索引快速查询,查询速度不会超过O(索引长度);

算法明细:

  依次保存 :    "cat":5,  "deep":10,  "do":15,  "dog":2,  "dogs":8 

  • 录入步骤及解释如下:
    1.从cat开始录入,查询开头是否有重合前缀,发现没有,则第一条边c的权重设置为cat对应value,然后继续插入a和t,因为cat整体value为5,所以a和t边权重为0,最后t指向一个末尾结点,该节点会被标记为末尾(因为前缀树的话会有很多重合,需要标记哪里有结尾)然后该节点会包含当前结束的索引项(cat)在所有路径权重和和初始权重的差值(这里为5-(5-0-0)=0)


    2.开始录入deep,查询开头是否有重合前缀,发现没有,则依照步骤1的方法直接录入,从起点到第一个节点的路径权重为depp的value->10,然后同样,最后的末尾结点包含两个东西,一个末尾结点标记,一个余下的权重,前者为True,后者为0,图示如下



3.开始录入do,查询开头是否有重合前缀,发现有,但是权重10小于当前词(do)的权重,所以不做处理,但是把temp权重(用于计算余下的权重)设置为5,因为有5没有分配,继续往下走,查询是否有前缀重合,发现没有,则新建结点,然后将该条路径的权重设置为5,然后末尾结点同样包含两个东西-->一个标记一个权重余量,此处为0,图示如下:


  • 4.开始录入dog,查询开头是否有重合前缀,发现有,然后比对权重,发现当前权重2<10,按照之前的分配方式不行,所以重新设置第一个权重为2,这样会导致之前的权重分配方案失败,怎么办呢,计算改变的量,此处为8(10-2),则需要下一个的出路径权重全部加上8(当然,如果下一个节点就有被标记为末尾结点,则末尾结点的余量也要加上响应的值),这时deep中的第一个e的权重从0变成8(符合条件,所以不需要继续传播),然后do中的o权重本来为5,现在变为5+8=13,然后此时分配到了dog的o,dog中o的权重余量为0,0小于当前权重13,所以还需要继续重新赋值,所以o被重置权重为0,又因为下一个节点被标记为结尾节点,所以此节点的末尾权重余量从0变为13-->(0+13),然后继续传播,查询是否有前缀,发现没有(g),然后新建结点(因为到末尾,所以是末尾结点)设置中间路径权重为0(因为dog的余量就为0),且末尾结点的权重余量亦为0。至此dog加入完毕,目前状态图如下


  • 5.开始录入dogs,查询是否有前缀,发现有,2<8,此时不需要重新赋值权重,但是dogs余量变为6,继续传播-->查询是否有前缀?发现有,o,当前权重0<6,不需要重新分配,继续传播-->查询是否有前缀,发现有,g当前权重0<6,不需要重新分配,继续传播-->查询是否有前缀,发现没有,新建结点s,设置路径权重为6,并新建末尾结点,结点包含两个东西,一个末尾标记,一个权重余量,前者为true,后者为0,最终状态如图所示:

  • 它最终的数据结构图示如下图所示

FST 有两个优点:

  • 空间占用小。通过对词典中单词前缀和后缀的重复利用,压缩了存储空间。
  • 查询速度快。O(len(str)) 的查询时间复杂度。

 postings list

    在 lucene 中,要求 postings lists 都要是有序的整形数组。但是数组也会非常大,占用很大的磁盘空间;需要对数组中的内容压缩;以及压缩以后仍然需要支持联合查询;

汇总在实际使用中,postings list 的痛点:

  • postings list 如果不进行压缩,会非常占用磁盘空间,
  • 联合查询下,如何快速求交并集(intersections and unions)

对于如何压缩,有两种算法:

FOR(Frame of Reference):

     算法会把所有的文档分成很多个 block,每个 block 正好包含 256 个文档,然后单独对每个文档进行增量编码,计算出存储这个 block 里面所有文档最多需要多少位来保存每个 id,并且把这个位数作为头信息(header)放在每个 block 的前面。这个技术叫 Frame of Reference

 postings lists 是有序的整形数组,这样就带来了一个很好的好处,可以通过 增量编码(delta-encode)这种方式进行压缩。

比如现在有 id 列表 [73, 300, 302, 332, 343, 372],转化成每一个 id 相对于前一个 id 的增量值(第一个 id 的前一个 id 默认是 0,增量就是它自己)列表是[73, 227, 2, 30, 11, 29]在这个新的列表里面,所有的 id 都是小于 255 的,所以每个 id 只需要一个字节存储

上图也是来自于 ES 官方博客中的一个示例(假设每个 block 只有 3 个文件而不是 256)。

FOR 的步骤可以总结为:

    进过最后的位压缩之后,整型数组的类型从固定大小 (8,16,32,64 位)4 种类型,扩展到了[1-64] 位共 64 种类型。

通过以上的方式可以极大的节省 posting list 的空间消耗,提高查询性能。不过 ES 为了提高 filter 过滤器查询的性能,还做了更多的工作,那就是缓存

RBM(Roaring Bitmaps)-(for filter cache)

    使用过ES以后,肯定知道filters ;可以使用 filters 来优化查询,filter 查询只处理文档是否匹配与否,不涉及文档评分操作,查询的结果可以被缓存。

对于 filter 查询,es 提供了 filter cache 这种特殊的缓存,filter cache 用来存储 filters 得到的结果集。缓存 filters 不需要太多的内存,它只保留一种信息,即哪些文档与 filter 相匹配。同时它可以由其它的查询复用,极大地提升了查询的性能。

我们上面提到的 Frame Of Reference 压缩算法对于 postings list 来说效果很好,但对于需要存储在内存中的 filter cache 等不太合适。

filter cache 会存储那些经常使用的数据,针对 filter 的缓存就是为了加速处理效率,对压缩算法要求更高。

对于这类 postings list,ES 采用不一样的压缩方式:

首先 postings list 是 Integer 数组,具有压缩空间。

假设有这么一个数组,我们第一个压缩的思路是什么?用位的方式来表示,每个文档对应其中的一位,也就是我们常说的位图,bitmap。

它经常被作为索引用在数据库、查询引擎和搜索引擎中,并且位操作(如 and 求交集、or 求并集)之间可以并行,效率更好。

     具体逻辑:将 doc id 拆成高 16 位,低 16 位。对高位进行聚合 (以高位做 key,value 为有相同高位的所有低位数组),根据低位的数据量 (不同高位聚合出的低位数组长度不相同),使用不同的 container(数据结构) 存储。

  • len<4096 ArrayContainer 直接存值
  • len>=4096 BitmapContainer 使用 bitmap 存储

分界线的来源:value 的最大总数是为2^16=65536. 假设以 bitmap 方式存储需要 65536bit=8kb,而直接存值的方式,一个值 2 byte,4K 个总共需要2byte*4K=8kb。所以当 value 总量 <4k 时,使用直接存值的方式更节省空间。

空间压缩主要体现在:

  • 高位聚合 (假设数据中有 100w 个高位相同的值,原先需要 100w*2byte,现在只要 1*2byte)
  • 低位压缩

缺点就在于位操作的速度相对于原生的 bitmap 会有影响。

联合查询

  • 如果查询有 filter cache,那就是直接拿 filter cache 来做计算,也就是说位图来做 AND 或者 OR 的计算。
  • 如果查询的 filter 没有缓存,那么就用 skip list 的方式去遍历磁盘上的 postings list。

    因为这个 FOR 的编码是有解压缩成本的。利用 skip list,除了跳过了遍历的成本,也跳过了解压缩这些压缩过的 block 的过程,从而节省了 cpu。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/664334.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

工业级以太网RJ45温湿度监控系统解决方案之关键POE供电温湿度传感器

目 录 一、关键词…………………………………………………………………………3 二、 产品概述………………………………………………………………………3 三、 应用范围………………………………………………………………………3 四、 产品特点………………………………

Linux0.11内核源码解析-file_dev.c

目录 功能描述 int file_read(struct m_inode * inode, struct file * filp, char * buf, int count) int file_write(struct m_inode * inode, struct file * filp, char * buf, int count) 功能描述 该文件主要是由两个函数file_read()和file_write()组成&#xff0c;提供…

Nginx网站服务——服务基础

文章目录 一.Nginx服务基础1.关于Nginx的特点2.简述Nginx和Apache的差异3.Nginx 相对于 Apache 的优点4.Apache 相对于 Nginx 的优点5.阻塞与非阻塞6.同步与异步7.nginx的应用场景 二.编译安装nginx服务1.在线安装nginx1.1 yum部署Nginx1.2 扩展源安装完后直接安装Nginx 2.ngin…

MySQL数据库---存储引擎(MyISAM与InnoDB)

目录 前言一、存储引擎概念介绍二、MyISAM三、InnoDB四、配置合适的存储引擎总结 前言 数据库存储引擎是数据库底层软件组织&#xff0c;数据库管理系统&#xff08;DBMS&#xff09;使用数据引擎进行创建、查询、更新和删除数据。不同的存储引擎提供不同的存储机制、索引技巧…

Vue中如何进行图像识别与人脸对比

Vue中如何进行图像识别与人脸对比 随着人工智能的发展&#xff0c;图像识别和人脸识别技术已经被广泛应用于各种应用程序中。Vue作为一种流行的前端框架&#xff0c;提供了许多实用工具和库&#xff0c;可以帮助我们在应用程序中进行图像识别和人脸识别。在本文中&#xff0c;…

docker换源(docker镜像源)pull超时(pull镜像超时)/etc/docker/daemon.json

文章目录 pull了n次都超时&#xff0c;也是醉了更换镜像源步骤1. 打开终端并以管理员身份登录到Docker主机。2. 编辑Docker配置文件daemon.json。该文件用于配置Docker守护进程的参数。3. 在daemon.json文件中添加以下内容&#xff0c;将<镜像源地址>替换为您选择的镜像源…

基于matlab仿真具有不同传感器模式的锥形阵列(附源码)

一、前言 此示例说明如何在不同的阵列配置上应用锥形和模型细化。它还演示了如何创建具有不同元素模式的数组。 二、ULA 逐渐变细 本节介绍如何在均匀线性阵列 &#xff08;ULA&#xff09; 的元素上应用泰勒窗口以降低旁瓣电平。 比较锥形阵列和非锥形阵列的响应。请注意锥形U…

外部局域网直接访问WSL2

1. 开启hyper-v 1、首先&#xff0c;进入控制面板—程序—启用或关闭windows功能&#xff0c;勾选hyper-v&#xff0c;确认后重启电脑。2、打开 Windows PowerShell&#xff0c;输入 systeminfo 命令 能够看到出现了很多处理器的信息&#xff0c;最末尾有个 Hyper-V 要求&…

Redis 2023面试5题(一)

一、Redis是单线程还是多线程 在面试中&#xff0c;当被问到Redis是单线程还是多线程这个问题时&#xff0c;可以按照以下思路进行回答&#xff1a; 首先&#xff0c;Redis的核心业务部分是单线程的&#xff0c;即命令处理部分是单线程的。然而&#xff0c;Redis也支持多路复…

Java---第四章(数组基础,冒泡排序,二分查找,多维数组)

Java---第四章 一 数组基本知识数组操作 二 数组实操数组排序二分查找二维数组 一 数组 基本知识 概念&#xff1a; 数组是编程语言中的一种常见的数据结构&#xff0c;能够存储一组相同类型的数据 作用&#xff1a; 存储一组相同类型的数据&#xff0c;方便进行数理统计&am…

springboot3生命周期监听的使用和源码解析

定义SpringApplicationRunListener来监听springApplication的启动 1.通过实现springApplicationRunListener来实现监听。 2.在 META-INF/spring.factories 中配置 org.springframework.boot.SpringApplicationRunListener自己的Listener。 在默认的springboot配置中就有给我…

视觉SLAM十四讲——ch12实践(建图)

视觉SLAM十四讲——ch12的实践操作及避坑 0.实践前小知识介绍1. 实践操作前的准备工作2. 实践过程2.1 单目稠密重建2.2 RGB-D稠密建图2.3 点云地图2.4 从点云重建网格2.5 八叉树地图 3. 遇到的问题及解决办法3.1 cmake ..时&#xff0c;出现opencv版本问题3.2 make -j8时&#…

使用腾讯云服务器从零搭建个人网站

前期准备工作 1.服务器重装系统 选择ubuntu18的系统镜像 2.开放端口 需要开放80&#xff0c;27017&#xff0c;3000&#xff0c;22端口 80端口用于配置nginx服务27017端口用于连接mongondb数据库3000端口是启动项目的端口22端口用于ssh远程连接服务器&#xff0c;一般默认会…

SpringBoot - @Transactional注解详解

简介 Spring中的Transactional注解&#xff0c;基于动态代理的机制&#xff0c;提供了一种透明的事务管理机制&#xff0c;方便快捷的解决在开发中碰到的问题&#xff0c;Transactional 的事务开启 &#xff0c;或者是基于接口的或者是基于类的代理被创建。Spring为了更好的支…

数据库SQL查询(二)之连接查询

本文介绍SQL查询&#xff0c;如何在海量数据中筛选想要数据&#xff1b; 数据库管理系统选择&#xff1a;关系型数据库mysql 数据库管理工具选择&#xff1a;navicat 本文中查询语句和查询案例参考自&#xff1a;https://edu.csdn.net/course/detail/27673?ops_request_mis…

python django vue httprunner 实现接口自动化平台(最终版)

一、项目介绍&#xff1a; 1.1 项目地址 前端地址&#xff1a; GitHub - 18713341733/test_platform_service: django vue 实现接口自动化平台 后端地址&#xff1a; GitHub - 18713341733/test_platform_front: Django vue实现接口自动化平台 1.2 项目介绍 1.2.1 环境…

在 K8S 中部署一个应用 上

本身在 K8S 中部署一个应用是需要写 yaml 文件的&#xff0c;我们这次简单部署&#xff0c;通过拉取网络上的镜像来部署应用&#xff0c;会用图解的方式来分享一下&#xff0c;过程中都发生了什么 简单部署一个程序 我们可以通过 kubectl run 的方式来简单部署一个应用&#…

Python深度学习027:什么是梯度、梯度消失、梯度爆炸以及如何解决

文章目录 1. 梯度的概念2. 梯度更新中存在的问题2.1 梯度消失2.2 梯度爆炸3. 解决办法3.1 梯度消失3.2 梯度爆炸1. 梯度的概念 在机器学习中,梯度是指一个多元函数在某一点处的变化率以及变化的方向。 对于一个参数化的函数,梯度可以告诉我们在一个特定的点处函数值增加最快…

分布式系统概念和设计——Mach实例研究

分布式系统概念和设计 Mach实例研究 Mach主要抽象概述 任务 一个Mach任务是一个执行环境主要包括一个被保护的地址空间和一个内存管理的权能集合这些权能主要用于访问端口 线程 任务可以包含多个线程在共享内存的多处理器中&#xff0c;属于同一个任务的线程可以在不同的处理…

【案例实战】SpringBoot整合Redis实现缓存分页数据查询

正式观看本文之前&#xff0c;设想一个问题&#xff0c;高并发情况下&#xff0c;首页列表数据怎么做&#xff1f; 类似淘宝首页&#xff0c;这些商品是从数据库中查出来的吗&#xff1f;答案肯定不是&#xff0c;在高并发的情况下&#xff0c;数据库是扛不住的&#xff0c;那么…