Interview preparation--elasticSearch倒排索引原理

搜索引擎应该具备哪些要求
  • 查询速度快
    • 优秀的索引结构设计
    • 高效率的压缩算法
    • 快速的编码和解码速度
  • 结果准确
    • ElasiticSearch 中7.0 版本之后默认使用BM25 评分算法
    • ElasticSearch 中 7.0 版本之前使用 TP-IDF算法
倒排索引原理
  • 当我们有如下列表数据信息,并且系统数据量达到10亿,100亿级别的时候,我们系统该如何去解决查询速度的问题。
  • 数据库选择—mysql, sybase,oracle,mongodb,唯一加速查询的方法是添加索引
索引
  • 无论哪一种存储引擎的索引都是如下几个特点
    • 帮助快速检索
    • 以数据结构为载体
    • 以文件的形式落地
  • 如下图中mysql的文件形式,其中的idb文件就是使用innodb存储引擎来实现数据存储生成的文件,其他后缀的文件是其他存储引擎生成的,因此无论什么引擎,索引方式,数据结构最终都是要落文件的

在这里插入图片描述

  • 传统数据库的基本结构如下:

在这里插入图片描述

  • MySql包括Server层和存储引擎层:Server层包括,连接器,查询缓存,分析器,优化器,执行器
  • 连接器:负责和客户端建立连接
  • 查询缓存:MySql获取到查询请求后,会先查询缓存,如果之前已经执行过一样的语句结果会以Key-value的形式存储到内存中,key是查询语句,value是查询结果。缓存明中的话可以很快完成查询,但是大多是情况不能明中,不建议用缓存,因为缓存失效非常频繁,任何对表的更新都会让缓存晴空,所以对一个进程更改的表而言,查询缓存基本不可用,除非是一张配置表。可以通过配置来决定释放开启查询缓存,并且MySql8.0 之间删除了查询缓存功能
  • 分析器:词法分析,识别语句中表名,列名,语法分析,判断Sql是否满足MySql语法
  • 优化器:在有多个索引的情况下,决定使用哪个索引,或者多表联合查询的时候,表的连接顺序这么执行等
  • 执行器:执行器先判断权限,有权限才会去调用存储引擎对应的查询接口,默认InnoDB
数据载体 mongodb & mysql
  • 以为mongodb为案例,索引数据存储的结构如下

在这里插入图片描述

  • Mongodb索引使用的是B树:B树是多叉平衡查找树,包括以下几个结构特性

    • 左子树数据小于跟数据,右子树数据大于根节点数据
    • 左右子树高度差不大于1
    • 每个节点可以有N个字节的,N>2
  • B树的每个节点都存放 索引 & 数据,数据遍布整个树结构,搜索可能在非叶子结点结束,最好情况是O(1)

  • B树存在的问题:

    • 紫色部分存储数据的主键信息,蓝色存储的是指针指向下一个节点,黄色部分是存储的主键对应的数据Data。因此Data是在节点中占比最大的一部分数据,他可能有1M或者更大的一个数据体
    • 假设我们一个节点的大小是固定的M,在Mysql中最小的数据逻辑单元是数据页,一个数据页是16KB,如果Data越大,M所能容纳的Data个数就越小,如果需要存储更多的数据则需要更多的节点,B树为了承载更多的节点的同时满足结构特性就需要更多的分叉,因此就导致树的深度更大,每一个层级都意味着一次IO操作导致IO次数更多
  • 以为Mysql为案例分析:

在这里插入图片描述

  • Mysql中innoDB 使用的索引结构是B+树,
  • B+ 树是B树的变种,区别在于:
    • 叶子结点保存了完整的索引 & 数据,非叶子结点只保存索引值,因此他的查询时间固定为logn
    • 叶子结点中有指向下一个叶子结点的指针,叶子结点类似一个双向链表
    • 因为叶子结点有完整数据,并且有双链表结构,因此我们在范围查询的时候能有效提升查询效率。
  • 数据都在子节点上,因此非叶子节点就能容纳更多的索引信息,这样就增加了同一个节点的出度,减少了数据Data信息,同一个节点就能容纳更多的其他类型数据信息,因此能用更少的节点来承载索引数据,节点的减少导致树的深度更低,查询的IO次数就变少了。
倒排索引数据结构
  • 对如上两个索引结构的分析,我们能看到MySql 无法解决大数据索引问题:
    • 第一点:索引往往字段很长,如果使用B+trees,树可能很深,IO很可怕
    • 第二点:索引可能会失效
    • 第三点:查询准确度差,
  • 有如下案例,有1亿条数据的商品信息,我们需要对其中的product字段进行查询,而且是文本信息查询,例如“小米”这个字段查询,那么有如下查询语句:
select * from product where brand like "%小米 NFC 手机%"
  • 第一点说明:以上查询语句,我们需要在product上建索引, MySql上使用的B+树,因为文本的信息量特别的大,导致所需要的节点就更多N个16KB(MySql索引中如果一个数据行的大小超过了页的大小16KB,MySQL 会将该行的部分数据存储在行溢出页中。这意味着数据行会被分割,一部分存储在索引页中,而溢出的部分存储在单独的溢出页中),节点数的增加,导致树深度增大查询IO次数增加
    在这里插入图片描述

  • 第二点说明:“%小米 NFC 手机%” 查询中用了左匹配的方式去查询,会导致索引失效,这样导致全表扫描。

  • 第三点说明:“小米 NFC 手机%” 去掉左匹配,走索引的方式,则会只查询"小米 NFC 手机"开头的,这样就会导致结果不准确

ElascitSearch索引解决方案
  • 对product字段进行分词拆分,得到如下一个词项 与id的匹配关系如下

在这里插入图片描述

Posting List (倒排表)
  • 索引系统通过扫描文章中的每一个词,对其创建索引,指明在文章中出现的次数和位置,当用户查询时,索引系统过就会根据事先建立的索引进行查找,并将查找的结果反馈给用户的检索方式,利用如上表可以快速完成全文检索
  • 在为属性(product)构建倒排索引后,此时,本类别中包含了所有文档中所有字段的一个 分词(term) 文档id对应关系的字典信息,通过倒排索引我们可以迅速找到符合条件的文档,例如“手机” 在文档 1,2,3 中。
Term Dictionary(前缀树)
  • 当我们进行Elasticsearch查询,为了能快速找到某个term在倒排表中的位置,ElasticSearch 将类型中所有的term进行排序,然后通过二分法查找term,时间复杂度能达到 logN的查找效率,就像通过字典查找一样,这就是Term Dictionary,整个是二级辅助索引
Term Index(前缀索引)
  • 同时参照 B-Tree通过减少磁盘寻道次数来提高查询性能,Elasticsearch也是采用同样的思路,直接通过内存查找term,将term Dictionary这个构建的Mapping存放在内存中。但是如果term太多,term dictionary也会很大,放内存不现实,于是有了Term Index,因此整个ElasticSearch的数据结构如下图

在这里插入图片描述

压缩算法
  • 倒排表生成后,可能存在如表中,小米关键字匹配到的文档id有 100W个 int类型的有序数组,如果直接存储这个数据的那么需要4Byte * 100w =4MB 的存储空间,因此存储的时候需要用到一定的压缩算法来进行数据压缩
FOR (Frame Of Reference)压缩算法:
  • 假设我们获取到的压缩表数组id是[1,2,3,4,5,…100W] 每一个数据占用的存储空间是 4Byte, 总共是100W * 4Byte = 100W * 4 * 8 bit
  • 通过计算相邻数据差值 得到数组2 [1,1,1,1,1,1, ,1],总共有100W个1, 这样我们可以将每一个数据用一个bit 来存储,这样就只需要 100W * 1bit 相比于原来 数据 缩小了 32 倍
  • 如下图:

在这里插入图片描述

  • 当然以上是一个特殊的案例,我们用一个相对正常一点的数组来重新计算

  • 原数组:[73,300,302,332,343,372] 总共 6*4Byte = 24Byte

  • 差值数组:[73,227,2,30,11,29]。我们得到如下结论。 64 < 73 < 128, 128 < 227 < 256, 1<2<4, 16 < 30<32, 8<11<16, 16 < 29 <32,

  • 以上数据我们就依然用bit位的存储方式,我们用以上数组中最大的数字所需要的bit位来计算,也就是227 ,用256 来存储 2 8 , 也就是8个bit位每个数字,得到如下

  • [73,227,2,30,11,29]。需要的存储。6 * 8bit = 48bit

  • 但是我们发现还是可以有优化空间,比如 2 其实只需要一个bit位即可,因此我们将大数,小数再次做一次分组 [73, 227] 最大28 es中会做一个记录,记录此处数组占用的是8bit。, [2, 30,11,29] 最大25 同样es中做记录此处占用5bit,进一步缩小存储空间。

  • 计算整个的存储空间:

    • [73, 227] 部分。 8bit - 给es记录存储空间大小是8bit。数字占用 8bit * 2 总共。 8bit * 3 = 3Byte
    • [2, 30,11,29] 部分。 8bit - 给es记录存储空间大小是5bit, 数字占用 5bit * 4 总共。8 bit + 20bit = 4Byte
    • 因此总共也就7 Byte的空间占用
  • 如下图:

在这里插入图片描述

RBM压缩(Roaring bitmaps)
  • 有了FOR算法,而且针对于同一种数据结构为什么还需要RBM算法,因为以上数据中案例数组都是比较稠密的数组,也就是他们的差值都是比较小的值,如果有如下数组

  • [1000W, 2000W, 3000W, 4000W, 5000W] 每个数都上千万,差值也是千万级别,这样用FOR算法就没有任何意义了。

  • RBM 案例讲解,有如下案例[1000, 62101, 131385, 132052, 191173, 196658]

  • 第一步,我们将数字用二进制表示 ,例如。196658 转二进制是 0000 0000 0000 0011 0000 0000 0011 0010

  • 第二步,将二进制分为高16 位: 0000 0000 0000 0011 转十进制是 2,底16位 0000 0000 0011 0010 转十进制是50

  • 通过以上步骤我们得到196658 的表示方式(2, 50)

  • 也可以通过计算方式得到这两个数字 196658 / 216 得到的值是2, 余数是 50 ,这种计算方式得到我们的推测结果,并且得到的所有数字都小于 2 16= 65536

  • 我们将以上数组表示为 [(0,1000), (0,62101), (2,313), (2,980), (2,60101), (2,50)]

  • 第三步:用一个container的数据结构来存储以上得到的数据表,

在这里插入图片描述

short[] 数组存储 第一个数字Array,bitmap,run 存储第二个数字的组合
01000. 62101
2313,980, 60101,50
。。。。。。。。
  • 我们将数字以第一个数字为基准做group by 聚合,得到一个表
  • RBM的存储方式有三种 ArrayContainer,BitMapContainer,RunContainer 三种
    • ArrayContainer存储short 类型的数组,short类型,最大是216 正好可以存储下所有数据的极限,而第一个位置中的数字,最大也就是65535,因为我们通过X/65535 X最大也就是232 因此,最多也就是。65535个行,同样一个Array最多也是存储65536个id,计算总存储占用
    • short 2Byte = 16bit, 总共有65536个。65536* 2Byte / 1024 = 128KB,因此一个行的数据最多存储128KB
  • BitMapContainer存储位图,存储的数据必须是不一样的数据,因为避免冲突,bitmap每一位不为0 的位都代表当前位的数据存在,比如第10位 1,表示数组中存在1 ,因此如果有数组[1,2,3,4,5,6,7], bitMap对应的就是7个bit位
    • 如果65536 个数字都是不一样的,那么用一个 65536 个bit位置的bitMap存储即可,总共 65536 bit / 8 / 1024 = 8KB
    • 缺点是必须每个数字不一样
  • RunContainer存储:按照如上思路如果存在如下特殊的数组[1,2,3,4,5,…100W] ,那么可以表示为(1, 100W)压缩到极致,比例取决于连续数字的多少
  • 安以上三种算法,有如下图表示

es 三种压缩算法

Term Dictionary & Term Index
  • 构建好倒排表之后,就又能力快速找到某个term对于的文档id,然后通过id查找磁盘上的segment,新的问题产生了,加入又1亿数据,那么term可能又上百万,挨个便利就炸了
  • ElasticSearch为了快速找到对应term,讲term按数组排序,排序后二分查找,以logN的查询时间复杂度完成查询,这样就构建了一个类似如下的term Dictionary
[aaa, aba, abb,abc, allen, .... ,sara,sarb,sarc,....selena.....]
  • 即使是logN的时间复杂的,在存在磁盘操作的情况 + 大数据量情况也是非常慢的,如果讲term dictionary加载到内存,十万级别的数据量可能就把内存沾满了,因此需要另外一个更晓的数据来对term dictionary进行替代到内存中进行查询,他就是 term index
  • 构建term index 过程: 便利所有 term dictionary 中的数据,按字符拆分,构建成b-tree,例如aaa 构建成 a-a-a,其他分支依然按字符拆分,如下图

在这里插入图片描述

  • 以上前缀表中不会包含所有的term信息,它包含的是term的前缀信息,例如 aaa,aab,aac 都存在aa前缀,通过term index可以快速地定位到term dictionary的某个offset,再结合FST(Finite State Transducers)的压缩技术,可以使term index缓存到内存中。从term index查到对应的term dictionary的block位置之后,再去磁盘上找term,大大减少了磁盘随机读的次数。如下图:

在这里插入图片描述

FST 压缩算法
  • 假设我们要将mop, moth, pop, star, stop and top(term index里的term前缀)映射到序号:0,1,2,3,4,5(term dictionary的block位置)。最简单的做法就是定义个Map<string, integer=“”>,大家找到自己的位置对应入座就好了,但从内存占用少的角度看可以用FST来进行压缩后在存储到内存。如下图

在这里插入图片描述

  • O表示一种状态
  • –>表示状态的变化过程,上面的字母/数字表示状态变化和权重
  • 将单词分成单个字母通过⭕️和–>表示出来,0权重不显示。如果⭕️后面出现分支,就标记权重,最后整条路径上的权重加起来就是这个单词对应的序号。
  • FST以字节的方式存储所有的term,这种压缩方式可以有效的缩减存储空间,使得term index足以放进内存,但这种方式也会导致查找时需要更多的CPU资源。

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

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

相关文章

【字符串】【双指针】1、仅仅反转字母+2、回文子串+ 3、最长回文子串+4、验证回文串+5、反转字符串中的单词

今天依旧是字符串&#xff01;2道简单&#xff0b;3道中等 1、仅仅反转字母&#xff08;难度&#xff1a;简单&#xff09; 该题对应力扣网址 错误做法 一开始是“原始”思路&#xff0c;交了之后果然不对&#xff0c;错误的思路我也就不解释了。 class Solution { public:…

高考未上本科线,大专不是唯一归宿

高考&#xff0c;作为人生中的一次重要考试&#xff0c;其结果往往牵动着无数家庭的心。然而&#xff0c;当高考成绩未能达到本科线时&#xff0c;是否就意味着大专是唯一的选择呢&#xff1f;其实不然&#xff0c;现代教育体系的多样化为我们提供了更多的可能性&#xff0c;其…

openinstall拥抱鸿蒙生态,SDK全面适配HarmonyOS NEXT

作为国内领先的App渠道统计与深度链接服务商&#xff0c;openinstall持续推动鸿蒙生态建设&#xff0c;近日正式发布openinstall HarmonyOS SDK&#xff0c;并成功入驻鸿蒙生态伙伴SDK专区&#xff0c;成为华为鸿蒙生态的合作伙伴&#xff0c;为鸿蒙应用开发者带来安全合规、高…

ONLYOFFICE 桌面编辑器 8.1华丽登场

简介&#xff1a;全新ONLYOFFICE 桌面编辑器 8.1解锁全新PDF编辑、幻灯片优化与本地化体验&#xff0c;立即下载&#xff01; 前言&#xff1a;在数字化时代&#xff0c;高效的办公协作工具是企业和个人不可或缺的利器。ONLYOFFICE&#xff0c;作为一款功能强大的云端和桌面办公…

数据结构-图的存储结构-邻接矩阵

图的结构十分复杂&#xff0c;不仅各个结点的度不同&#xff0c;各个顶点之间的路径也不尽相同。但是图的主要组成部分比较清晰&#xff0c;分为顶点信息和边或者弧的信息。 邻接矩阵 邻接矩阵就是用一维数组存储图中顶点的信息&#xff0c;用一个二维数组表示图中各个顶点之间…

uni-app与原生插件混合开发调试1-环境准备

uni-app与原生插件混合开发调试系列文章分为3篇&#xff0c;分别详细讲了《环境准备》、《搭建uni-app本地开发调试环境》和《安卓原生插件开发调试和打包》&#xff0c;3篇文章完整详细地介绍了“从环境安装配置到本地开发调试到原生插件打包”整个流程。 相关名词和概念解释…

FuTalk设计周刊-Vol.026

&#x1f525;&#x1f525;AI漫谈 热点捕手&#x1f525;&#x1f525; 1、Hotshot-XL AI文本转GIF Hotshot-XL 是一种 AI 文本转 GIF 模型&#xff0c;经过训练可与Stable Diffusion XL一起使用。能够使用任何现有或新微调的 SDXL 模型制作 GIF。 网页体验 网页http://htt…

智能体实战:开发一个集成国内AI平台的GPTs,自媒体高效智能助手

文章目录 一&#xff0c;什么是GPTs二&#xff0c;开发GPTs1&#xff0c;目标2&#xff0c;开发2.1 打开 GPTS&#xff1a;https://chat.openai.com/gpts2.2 点击 Create 创建一个自己的智能体 2.3 配置GPTs2.4 配置外挂工具2.4.1 配置Authentication-授权2.4.1.1 生成语聚AI的…

用FFmpeg合并音频和视频

使用FFmpeg合并音频和视频是一个相对直接的过程。可以通过以下一些基本的步骤和命令示例完成这个任务&#xff1a; 安装FFmpeg&#xff1a;首先&#xff0c;确保你的系统中已经安装了FFmpeg。你可以从[FFmpeg官网](Download FFmpeg)下载并安装它。 准备素材&#xff1a;确保你…

服务器重装系统后,远程ssh需要修改的内容

前提 首先实验室服务器内部是搭了内网的&#xff0c;所以有固定的IP,IP是和网卡的MAC地址有关的&#xff0c;所以和系统没有关系&#xff0c;所以更换了系统不会影响IP的。 修改内容 1、首先需要安装 SSH sudo apt install openssh-server2、之后需要修改ssh的配置参数 打…

itsdangerous,一个强大的 Python 库!

更多资料获取 &#x1f4da; 个人网站&#xff1a;ipengtao.com 大家好&#xff0c;今天为大家分享一个强大的 Python 库 - itsdangerous。 Github地址&#xff1a;https://github.com/pallets/itsdangerous 在Web应用开发中&#xff0c;数据的安全传输和存储是非常重要的。P…

服务器部署—虚拟机安装nginx并部署web网页

该篇博客用于讲解Linux的Centos7发行版中如何通过Linux安装Nginx&#xff0c;然后将静态页面部署到Nginx中&#xff0c;通过浏览器访问。 非常适用于新手小白学习项目部署相关的知识。建议收藏&#xff01;&#xff01;&#xff01; 需要大家提前准备好虚拟机和CentOS7操作系统…

python API自动化(基于Flask搭建MockServer)

接口Mock的理念与实战场景: 什么是Mock: 在接口中&#xff0c;"mock"通常是指创建一个模拟对象来代替实际的依赖项&#xff0c;以便进行单元测试。当一个类或方法依赖于其他类或组件时&#xff0c;为了测试这个类或方法的功能&#xff0c;我们可以使用模拟对象来替代…

M4V文件损坏无法播放?一招轻松修复损坏视频文件!

M4V是一个标准视频文件格式&#xff0c;此种格式常在iPod 、 iPhone 和 PlayStation Portable等设备上使用&#xff0c;同时此格式基于MPEG-4编码第二版&#xff0c;是MP4格式的一种特殊类型&#xff0c;有时可能会因为各种原因而损坏&#xff0c;导致无法正常播放。M4V文件出现…

前端vue3 根据某些Id 筛选数据

现在有一些不等的数据 我需要通过前端 吧这个数据筛选一下 比如我使用一些 我需要的ID 下的数据 比如以上的数据 的 cinemaLineId 来筛选 const cinemaLineId ref(["1246429254713147392", "1182608813770321920", "1182608917403185152"])…

爬取必应关键字搜索结果url

上代码 import aiohttp import asyncio from lxml import etree import aiofiles import time import random aiohttp 和 asyncio 用于异步HTTP请求和事件循环。 lxml 用于解析HTML。 aiofiles 用于异步文件操作。 time 和 random 用于控制爬取速度。 headers {User-Agent: M…

frida的安装使用以及解决抓包app时遇到的证书校验

frida的安装和使用 这里使用夜神模拟器来演示frida的使用&#xff0c;因为真机开启frida-server服务时需要root权限,模拟器自带root 下载夜神模拟器并启动 夜神官网 打开power shell&#xff0c; adb连接模拟器&#xff0c;查看模拟器的系统型号 adb connect 127.0.0.1:6200…

阿里云centos7.9 挂载数据盘 并更改宝塔站点根目录

一、让系统显示中文 参考&#xff1a;centos7 怎么让命令行显示中文&#xff08;英文-&#xff1e;中文&#xff09;_如何在命令行中显示中文-CSDN博客 1、输入命令&#xff1a;locale -a |grep "zh_CN" 可以看到已经存在了中文包 2、输入命令&#xff1a;sudo vi…

SecureCRT使用SSH登录服务器报错:Key exchange failed

SecureCRT使用SSH登录Ubuntu服务器报错&#xff1a;Key exchange failed 原因&#xff1a; ssh客户端与服务器的公钥协商失败&#xff0c;SecureCRT客户端所指定的秘钥交换算法&#xff08;KexAlgorithms &#xff09;&#xff0c;不在服务端支持范围内。可能是服务端的sshd版…

学习笔记(linux高级编程)7

2._exit 系统调用 void _exit(int status); 功能: 让进程退出,不刷新缓存区 参数: status:进程退出状态 返回值: 缺省 回调函数 3.atexit int atexit(void (*function)(void)); 功能: 注册进程退出前执行的函数 参数: function:函数指针 指向void返回值void参数的函数指针 返…