Elasticsearch 查询命令执行时,如何通过词项索引、词项字典、倒排表定位文档逻辑介绍

这里不涉及到源码,只是根据网上的一些文章总结一下,目前不需要细究,只需要知道大概就好,除非你的工作是二次开发ES

  • 一、​Term Index(词项索引)
    • 1、FSM(Finite State Machine)有限状态机
    • 2、FSA(Finite State Acceptor)确定无环有限状态接收机
    • 3、FST(Deterministic acyclic finite state transducer)确定无环状态转换器
  • 二、Term Dictionary(词项字典)
  • 三、Posting List(倒排表)
    • 1、FOR(Frame Of Reference)压缩算法(差值存储)
    • 2、RBM(RoaringBitmap)压缩算法(32位int拆成两个16位的short存储)
      • (1)ArrayContainer
      • (2)BitmapContainer
      • (3)RunContainer

在这里插入图片描述
这张图你可以认为粗糙的描述倒排索引对应关系,下面的文章也是主要讲解这张图各个部分含义

一、​Term Index(词项索引)

看这个​Term Index是不是特别想树的数据结构?比如二叉树或者多叉树?其实是FST,下面看一下它是怎么出来的

1、FSM(Finite State Machine)有限状态机

表示有限个状态(State)集合以及这些状态之间转移和动作的数学模型。其中一个状态被标记为开始状态,0个或更多的状态被标记为final状态。来自[转]ElasticSearch 查询的秘密

在这里插入图片描述
这种模型使用原型的节点标示某个“状态”,状态之间可以互相转换,但是转换过程是无向的。
比如睡觉醒了可以去工作,工作累了可以去玩手机;或者工作中想去上厕所等等。
在这个模型中,标示状态的节点是有限多个的,但状态的转换的情况是无限多的,同一时刻只能处于某一个状态,并且状态的转换是无序切循环的。
显然这种模型并不适用于描述Term Dictionary这样的数据结构,所以再看一下演变的FSA

2、FSA(Finite State Acceptor)确定无环有限状态接收机

相较于FSMFSA增加了EntryFinal的概念,这样就增加了如下3个特性
1、确定:意味着指定任何一个状态,只可能最多有一个转移可以访问到。
2、无环: 不可能重复遍历同一个状态
3、接收机:有限状态机只“接受”特定的输入序列,并终止于final状态。
来自:关于Lucene的词典FST深入剖析

我们如何来表示只有一个key:jul 的集合。FSA是这样的:
在这里插入图片描述
当查询这个FSA是否包含“jul”的时候,按字符依序输入。

输入j,FSA从0->1
输入u, FSA从1->2
输入l,FSA从2->3
这个时候,FSA处于final状态3,所以jul是在这个集合的。

增加一个key:mar 就如下表
在这里插入图片描述
再增加一个key:jun
在这里插入图片描述
遍历算法是这样的:

初始状态0, key=””
->1, key=”j”
->2, key=”ju”
->3, key=”jul”, 找到jul
2<-, key=”ju”
->3, key=”jun”, 找到jun
2<-, key=”ju”
1<-, key=”j”
0<-, key=””
->4, key=”m”
->5, key=”ma”,
->3, key=”mar”,找到mar
这个算法时间复杂度O(n),n是集合里所有的key的大小, 空间复杂度O(k),k是结合内最长的key字段length。

再看一下更复杂的,由“october”,“november”,”december”构成的FSA
在这里插入图片描述
所以FSA不光共用前缀,后缀也一样可以共用

即使FSA已经满足了对Term Dictionary数据高效存储的基本要求,但是仍然不满足的一个问题就是,FSA无法存储key-value的数据类型,

3、FST(Deterministic acyclic finite state transducer)确定无环状态转换器

FSTFSA基础上为每一个出度添加了一个output属性,用来表示每个termvalue值,
来自:倒排索引:ES倒排索引底层原理及FST算法的实现过程

下面拿key:msb输出 要输出一个value:10 和再新增一个key:msbtech输出一个value:5的FST是如何构建的

在这里插入图片描述
当第一个term:msb被写入FST中,其输出值被保存在了其第一个节点的出度上,在数据从FST中读取的时候, 计算其每个节点对应的出度的输出值以及终止节点的final output值的累加和,从而得出输出值,此时msb的输出值就是10+0+0+0=10,但是这里我用0来标识没有输出值,但实际情况没有输出值就是空而不是0,这里写0只是为了方便你去理解,这一点是需要注意的。

当第二个term:msbteach被写入的时候,其输出值5与msb的输出值10发生了冲突,这时,通用最小化算法法则发挥了功效。数字虽然不能像字符那样以前缀作为复用手段,但是数字是可以累加的,10可以拆成两个数字5,这样10和5就产生了公共部分,即5,所以这个时候m的输出值就需要改成5,那另一个5就需要找一个合适的位置,然而把它存放在任何一个节点的出度上似乎都会影响msbtech的计算结果,为了避免这个问题,可以把这个多出来的属于msb的输出值存入msb的final节点的final output中,节点的final output只会在当前出度是输入值的最后一个字符并且出度的target指向的是final节点的时候,才会参与计算。因此此时的msbmsbtech就各自把输出值存入了合适的位置互不影响而且做到了“通用最小化”原则。

所以大体上就知道了​Term Index 中的FST是怎样的数据结构了

二、Term Dictionary(词项字典)

这个就比较直白,就是各个分词后的字段列表
来自:倒排索引:ES倒排索引底层原理及FST算法的实现过程

下面拿右边的做一个例子,这样Term Dictionary会把右边的表中product字段的内容分词,分成左边的表格中的样例

在这里插入图片描述
但是既然都已经知道上面的term index了,那看存储词项索引的文件.tip数据结构和输出如何映射到词项字典文件.tim

词项字典包含了index field的所有经过normalization token filters处理之后的词项数据,最终存储在.tim文件中。
所谓normalization其实是一个如去重、时态统一、大小写统一、近义词处理等类似的相关操作;词项索引就是为了加速词项字典检索的一种数据结构,落地文件为.tip

在这里插入图片描述
所以,词项字典也是存储了很多东西的,一个block代表像小米手机这样的分词块

三、Posting List(倒排表)

倒排表这里主要说一下两种压缩算法,因为都知道倒排表存储的是词项字典对应的文档的id,那如何存储的呢?因为要考虑到量的问题,虽然不是文档本身,但是id这个字段存储几十亿的量还是挺大的

1、FOR(Frame Of Reference)压缩算法(差值存储)

即不存储原本的数值,而是存储每个数值与前一个数字的差值,这个适用于id之间差值都很小,或者只有几个id之间差值大的场景,这种数组也叫稠密数组
下面以某个id的集合是[1,2,3…100万]和[73,300,302,332,343,372]举例

在这里插入图片描述
如果是[1,2,3…100万],用差值存储你可能就知道为什么这么做了,节省的空间存储很多,压缩了32倍。

下面又用了一个特殊的例子[73,300,302,332,343,372]来演示特殊的情况,就是某两个id之间差值之间太大的情况,数组经过拆分,分为了两个数组,第一个数组每个数字占用1个Byte,共两个数字,总占用为2Bytes,记录数组单位大小的Record Space大小为1Byte,第二个数组每个数字占用5个bit,一共四个数字,共计20bit,但是计算空间的最小单位是Byte,所以实际占用的大小为3Bytes,第二个数组的Record Space大小也是1Byte,因此压缩后的数据总大小为1B+2x1B+3B+1B=7Bytes,相比压缩之前,大小不到原先的三分之一

但是可能还有更特殊的,每一个id之间相差都很大,就有了下面这种压缩算法RBM

2、RBM(RoaringBitmap)压缩算法(32位int拆成两个16位的short存储)

针对id数据大部分id之间差值都很大,用差值存储压缩不了多少的情况,这里称这种数组为稀疏数组,Lucene对于这种稀疏数组采用了另一种压缩算法
下面用 [1000,62101,131385,132052,191173,196658] 这种典型稀疏数组为例

在这里插入图片描述
RBM算法本身的设计思路是将原数字的的32个bit分为了高16位低16位。以原数组中的196658这个id为例,将其转化为二进制结果为 110000000000110010,我们看到其实结果是不足32bits的,但因为每个int型都是有32个bit组成的,不足32bit会在其前面补0,实际其占用的空间大小仍然为32bits,如果这一点不理解,打个比方,公交车有32个座位,无论是否坐满,都是使用了32个座位。最终196658转换成二进制就是0000 0000 0000 0011 0000 0000 0011 0010,前16位就是高16位,转换成十进制就是3,后16位也就是低16位,转换成十进制就是50

到这一步其实你有疑问?拆开空间也没有变小啊,还是32bits啊?那可以继续往下看

对数组中每个数字进行相同的操作,会得到以下结果:(0,1000)(0,62101)(2,313)(2,980)(2,60101)(3,50),其含义就是每个数字都由一个很大的数字变为了两个很小的数字,并且这两个数字都不超过65536,更重要的是,当前结果是非常适合压缩的,因为不难看出,出现了很多重复的数字,

比如前两个数字的得数都是0,以及第2、3、4个数字的得数都是2。RBM使用了非常适合存储当前结果的数据结构。这种数据结构是一种类似于哈希的结构,只不过Key值是一个short有序不重复数组,用于保存每个商值,value是一个容器保存了当前Key值对应的所有模,这些模式不重复的,因为同一个商值的余数是不会重复的。

这里的容器官方称之为Container,RBM中包含三种Container,分别是ArrayContainer、BitmapContainer和RunContainer,

(1)ArrayContainer

ArrayContainer,顾名思义,Container中实际就是一个short类型的数组,其空间占用的曲线如图3-4中的红色线段,注意这里是线段,因为docs的数量最大不会超过65536,其函数为 y(空间占用)=x(docs 长度) x 2Bytes,当长度达到65536极限值的时候,其占用的大小就是16bit * 65536 / 8 /1024 = 128KB,乘以65536是总bit数,除以8是换算成Byte,除以1024是换算成KB。

在这里插入图片描述

(2)BitmapContainer

第二种是BitmapContainer,理解BitmapContainer之前首先要了解什么是bitmap。以往最常见的数据存储方式都是二进制进位存储,比如我们使用8个bit存储数字,如果存十进制0,那二进制就是 0 0 0 0 0 0 0 0,如果存十进制1,那就是 0 0 0 0 0 0 0 1,如果存十进制2,那就是 0 0 0 0 0 0 1 1,用到了第二个bit。这种做法在当前场景下存储效率显然不高,如果我们现在不用bit来存储数据,而是用来作为“标记”,即标记当前bit位置商是否存储了数字,出的数字值就是bit的下标,如下图所示,就表示存储了2、3、5、7四个数字,第一行数字的bit仅代表当前index位置上是否存储了数字,如果存储了就记作1,否则记为0,存储的数字值就是其index,并且存储这四个数字只使用了一个字节。
在这里插入图片描述

不过这种存储方式的问题就是,存储的数字不能包含重复数字,并且Bitmap的大小是固定的,不管是否存储了数值,不管存储了几个值,占用的空间都是恒定的,只和bit的长度有关系。
但是我们刚才已经说过,同一个Container中的数字是不会重复的,因此这种数据类型正好适合用这种数据结构作为载体,而因为我们Container的最大容量是65536,因此Bitmap的长度固定为65536,也就是65536个bit,换算成千字节就是8KB,如图的蓝色线段所示,即Lucene的RBM中BitmapContainer固定占用8KB大小的空间,
通过对比可以发现,当doc的数量小于4096的时候,使用ArrayContainer更加节省空间,当doc数量大于4096的时候,使用BitmapContainer更加节省空间

(3)RunContainer

第三种Container叫RunContainer,这种类型是Lucene 5之后新增的类型,主要应用在连续数字的存储商,比如倒排表中存储的数组为 [1,2,3…100W] 这样的连续数组,如果使用RunContainer,只需存储开头和结尾两个数字:1和100W,即占用8个字节。这种存储方式的优缺点都很明显,它严重收到数字连续性的影响连续的数字越多,它存储的效率就越高。

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

海云安亮相2023北京国际金融安全论坛,助力金融企业数字化转型降本增效

近日&#xff0c;2023北京国际金融安全论坛暨金融科技标准认证生态大会在北京金融安全产业园成功举办。深圳海云安网络安全技术有限公司&#xff08;以下简称“海云安”&#xff09;受邀参展亮相此次大会。海云安作为国内领先的金融科技服务商&#xff0c;展示了开发安全系列产…

【北亚服务器数据恢复】san环境下LUN Mapping出错导致文件系统一致性出错的数据恢复案例

服务器数据恢复环境&#xff1a; san环境下的存储上一组由6块硬盘组建的RAID6&#xff0c;划分为若干LUN&#xff0c;MAP到跑不同业务的服务器上&#xff0c;服务器上层是SOLARIS操作系统UFS文件系统。 服务器故障&#xff1a; 业务需求需要增加一台服务器跑新增的应用&#xf…

Spring Boot:Spring Boot 入门、yaml 配置文件给属性赋值、自动装配原理详解

文章目录 Spring Boot - 01一、概述二、第一个 Spring Boot 程序补充知识 三、配置文件1. yaml 配置文件2. 使用 yaml 配置文件给属性赋值3. 松散绑定以及数据校验4. 配置文件的位置以及多环境配置 四、Spring Boot 分析1. pom.xml2. 启动器3. 主程序4. 自动装配原理5. 主启动类…

Kafka:本地设置

这是设置 Kafka 将数据从 Elasticsearch 发布到 Kafka 主题的三部分系列的第一部分;该主题将被 Neo4j 使用。第一部分帮助您在本地设置 Kafka。第二部分将讨论如何设置Elasticsearch将数据发布到Kafka主题。最后 将详细介绍如何使用连接器订阅主题并使用数据。 Kafka Kafka 是…

【Unity】【FBX】如何将FBX模型导入Unity

【背景】 网上能够找到不少不错的FBX模型资源&#xff0c;大大加速游戏开发时间。如何将这些FBX导入Unity呢&#xff1f; 【步骤】 打开Unity项目文件&#xff0c;进入场景。 点击Projects面板&#xff0c;右键选择Import New Assets 选中FBX文件后导入。Assets文件夹中就会…

【软件测试】为bug而生

为什么定位问题如此重要&#xff1f; 可以明确一个问题是不是真的“bug” 很多时候&#xff0c;我们找到了问题的原因&#xff0c;结果发现这根本不是bug。原因明确&#xff0c;误报就会降低多个系统交互&#xff0c;可以明确指出是哪个系统的缺陷&#xff0c;防止“踢皮球”&…

Apache Flink连载(二十一):Flink On Yarn运行原理-Yarn Application模式

🏡 个人主页:IT贫道_大数据OLAP体系技术栈,Apache Doris,Clickhouse 技术-CSDN博客 🚩 私聊博主:加入大数据技术讨论群聊,获取更多大数据资料。 🔔 博主个人B栈地址:豹哥教你大数据的个人空间-豹哥教你大数据个人主页-哔哩哔哩视频 目录 1. 任务提交命令

Android 理解Context

文章目录 Android 理解ContextContext是什么Activity能直接new吗&#xff1f; Context结构和源码一个程序有几个ContextContext的作用Context作用域获取ContextgetApplication()和getApplicationContext()区别Context引起的内存泄露错误的单例模式View持有Activity应用正确使用…

3d导入模型怎样显示原本材质---模大狮模型网

要在导入3D模型时保留原本的材质&#xff0c;您可以尝试以下方法&#xff1a; 导入前检查文件格式&#xff1a;确保您所使用的3D软件支持导入模型的文件格式。不同的软件对文件格式的支持有所差异&#xff0c;选择正确的文件格式可以更好地保留原始材质。 使用正确的材质库&am…

3D 渲染如何帮助电商促进销售?

在线工具推荐&#xff1a; 3D数字孪生场景编辑器 - GLTF/GLB材质纹理编辑器 - 3D模型在线转换 - Three.js AI自动纹理开发包 - YOLO 虚幻合成数据生成器 - 三维模型预览图生成器 - 3D模型语义搜索引擎 3D 渲染图像因其高转化率而成为亚马逊卖家的最新趋势。它是电子商务平…

GPT-5、开源、更强的ChatGPT!OpenAI公布2024年计划

年终岁尾&#xff0c;正值圣诞节热闹气氛的OpenAI写下了2024年的发展清单。 OpenAI联合创始人兼首席执行官Sam Altman在社交平台公布&#xff0c;AGI&#xff08;稍晚一些&#xff09;、GPT-5、更好的语音模型、更高的费率限制&#xff1b; 更好的GPTs&#xff1b;更好的推理…

python可视化界面自动生成,python如何做可视化界面

大家好&#xff0c;小编来为大家解答以下问题&#xff0c;python gui可视化操作界面制作&#xff0c;python做出的炫酷的可视化&#xff0c;现在让我们一起来看看吧&#xff01; 目录 前言 一.环境配置 插件&#xff1a; 1.python 2.Chinese 3.Open In Default Browser 安装pyt…

【K8S 基本概念】Kurbernetes的架构和核心概念

目录 一、Kurbernetes 1.1 简介 1.2、K8S的特性&#xff1a; 1.3、docker和K8S&#xff1a; 1.4、K8S的作用&#xff1a; 1.5、K8S的特性&#xff1a; 二、K8S集群架构与组件&#xff1a; 三、K8S的核心组件&#xff1a; 一、master组件&#xff1a; 1、kube-apiserve…

Zookeeper之手写一个分布式锁

前言 我之前写了一篇快速上手ZK的文章&#xff1a;https://blog.csdn.net/qq_38974073/article/details/135293106 本篇最要是进一步加深学习ZK&#xff0c;算是一次简单的实践&#xff0c;巩固学习成果。 设计一个分布式锁 对锁的基本要求 可重入&#xff1a;允许同一个应…

【软件工程】漫谈增量过程模型:软件开发的逐步之道

&#x1f34e;个人博客&#xff1a;个人主页 &#x1f3c6;个人专栏&#xff1a; 软件工程 ⛳️ 功不唐捐&#xff0c;玉汝于成 目录 前言&#xff1a; 正文 增量过程模型&#xff08;Incremental Process Model&#xff09; 主要特点和阶段&#xff1a; 优点&#xff1…

【滑动窗口】C++算法:K 个不同整数的子数组

作者推荐 动态规划 多源路径 字典树 LeetCode2977:转换字符串的最小成本 本题涉及知识点 滑动窗口 LeetCoe992 K 个不同整数的子数组 给定一个正整数数组 nums和一个整数 k&#xff0c;返回 nums 中 「好子数组」 的数目。 如果 nums 的某个子数组中不同整数的个数恰好为 …

右键添加 idea 打开功能

1.开始运行regedit 2.找到: HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Directory\shell _3.开始设置 一、右键shell目录新建项Idea二、右键Idea新建command三、选择Idea 右侧空白出新建字符串 名字为Icon 值填入idea的运行程序地址 四、选择command 默认项填入idea的运行程序地址…

Vue3-29-路由-编程式导航的基本使用

补充一个知识点 路由配置中的 name 属性 &#xff1a; 可以给你的 路由 指定 name属性&#xff0c;称之为 命名路由。 这个 name 属性 在 编程式导航 传参时有重要的作用。 命名路由的写法如下 &#xff1a; 像指定 path 一样&#xff0c;直接指定一个 name 属性即可。{path:/d…

python+django网上购物商城系统o9m4k

语言&#xff1a;Python 框架&#xff1a;django/flask可以定制 软件版本&#xff1a;python3.7.7 数据库&#xff1a;mysql 数据库工具&#xff1a;Navicat 开发工具pycharm/vscode都可以 前端框架:vue.js 系统使用过程主要涉及到管理员和用户两种角色&#xff0c;主要包含个…

智能优化算法应用:基于减法平均算法3D无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用&#xff1a;基于减法平均算法3D无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于减法平均算法3D无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.减法平均算法4.实验参数设定5.算法结果6.…