delphi报列表索引越界怎么处理_图解Elasticsearch索引机制,此篇带你领悟新世界...

前言

随着Elastic的上市,ELK不仅在互联网大公司得到长足的发展,而且在各个中小公司都得到非常广泛的应用,甚至连"婚庆网站"都开始使用Elasticsearch了。随之而来的是 Elasticsearch 相关部署、框架、性能优化的文章早已铺天盖地。

因为ES家族团队已在设计阶段做了大量的设计,所以整个ELK家族的组件使用起来非常容易上手,对于初学者甚至会进入幻觉—:"一键部署、导入数据、检索&聚合、动态扩展",这些都是如此简单。

但,实际上呢?仅就 Elasticsearch 索引设计,请回答如下几个问题:

倒排索引是什么?

有限状态转换的机制是什么?

对于亿级数据,ES是如何做到毫秒级甚至秒级回复,它有哪些独特的原理?

    相比于大多数人熟悉的MySQL数据库的索引,Elasticsearch的索引机制是完全不同于MySQL的B+Tree结构。索引会被压缩放入内存用于加速搜索过程,这一点在效率上是完爆MySQL数据库的。但是Elasticsearch会对全部text字段进行索引,必然会消耗巨大的内存,为此Elasticsearch针对索引进行了深度的优化。在保证执行效率的同时,尽量缩减内存空间的占用。

为了方便,以下统一用ES来代替Elasticsearch。

简介

Elasticsearch是一个基于Lucene库的开源搜索引擎,它提供分布式的实时文件存储和搜索,可扩展性好,并且支持通过HTTP网络接口交互,数据以JSON格式展示。

ES的索引处理机制是将所有数据存放于内存中,从而提高搜索效率。这一点对于我们熟悉的MySQL的B+树索引结构,在设计上有了显著提升和优化。因为B+树需要将索引放入磁盘,每次读取需要先从磁盘读取索引然后寻找对应的数据节点。另外一方面:Mysql并不支持聚合操作,ES可以完成复杂的操作,每个字段都是有索引的。再各种场景中可以互相组合。

    ES能够直接在内存中就找到目标文档对应的大致位置,最大化提高效率。并且在进行组合查询的时候MySQL的劣势更加明显,它不支持复杂的组合查询比如聚合操作,即使要组合查询也要事先建好索引,但是ES就可以完成这种复杂的操作,默认每个字段都是有索引的,在查询的时候可以各种互相组合。

索引

前面已经说过ES的索引和MySQL的概念不太一样,首先我们查看ES和Mysql中的关键概念:如图:

787292e70f9fb5424be1368c9a712b5d.png

通过图可知,ES的索引跟Mysql中的库相对应。但是,再ES中不需要像MySQL那样需要手动建立相关内容。

为了可以在大数据量中快速定位查找到内容,ES建立索引的时候采用了一种叫做倒排索引的机制。

倒排索引

现在有三句话:

Winter is coming

Ours is fury

Ths choice is yours

按照一般常规的查询策略,想要去找到其中的choice,需要数据库查询整个表单内容,然后通过每一条过滤才能找到对应内容所对应的id。显然,这样效率非常低,如果数据量非常的情况下,很难得到结果。提高效率的方法就是建立索引,我们给所有输入的数据都建立索引,并且把这样的索引和对应的文档建立一个关联关系,相当于一个词典。当我们在寻找choice的时候就可以直接像查字典一样,直接找到所有包含这个数据的文档的id,然后找到数据。

8a561894eda6f2e4a5f9b3dcb273c967.png

Lucene在对文档建立索引的时候,会给词典的所有的元素排好序,如上图所示,每一个元素都会统计出出现的频率和所在的文档,在搜索的时候直接根据二分查找的方法进行筛选就能够快速找到数据,这样会使效率大为提高。根据词频树进行二分查找,这点可能会有些眼熟,其实这就是MySQL的索引方式的,直接用B+树建立索引词典指向被索引的文档的原理是一样的。

相比较Lucene做法,ES又进一步做了更深次的处理:ES希望把这个词典“搬进”内存,显然直接从内存读取数据要比从磁盘读数据要快很多。但,另一个问题必须解决:对于海量的数据,内存空间消耗必然十分巨大。如果是直接将数据放到内存肯定是不合适的。ES做了进一步的处理,建立词典索引(term index)。通过词典索引可以直接找到搜索词在词典中的大致位置,然后从磁盘中取出词典数据再进行查找。所以大致的结构图就变成了这样:

a8196521b6efe2099919328c4a361549.png

ES通过有限状态转化器,把词典(term dictionary)变成了词典索引(term index),放进了内存,所以这个词典索引究竟是怎么样的?

我们见介绍另一个概念:有限状态转换

有限状态转换

有限状态转换器(Finite State Transducers)相当于是一个Trie前缀树,可以直接根据前缀就找到对应的term在词典中的位置。

比如我们现在有已经排序好的单词mop、moth、pop、star、stop和top以及他们的顺序编号0..5,可以生成一个下面的状态转换图:

cb227440cd205e9016b62dc4414ca401.png

当遍历上面的每一条边的时候,都会加上这条边的输出,比如当输入是stop的时候会经过s/3和o/1,相加得到的排序的顺序是4;而对于mop,得到的排序的结果是0。

需要特别注意的是,上面这个树它其实并没有包含所有的term,而是包含了term的前缀,它是通过这些前缀而快读定位到磁盘上的区域,然后,根据区域再去找文档列表。ES为了进一步压缩词典空间,实际上每个区块只是报错block的不同部分:例如:start,stop在同一个以st开头的block中,那么对应词典里面只会报错art和op,正式通过这样的设计,是ES的空间利用率提高了一倍。

帧引用(Frame of Reference)

在进行查询的时候经常会进行组合查询,比如查询同时包含choice和the的文档,那么就需要分别查出包含这两个单词的文档的id,然后取这两个id列表的交集;如果是查包含choice或者the的文档,那么就需要分别查出posting list然后取并集。为了能够高效的进行交集和并集的操作,posting list里面的id都是有序的。同时为了减小存储空间,所有的id都会进行delta编码(delta-encoding,我觉得可以翻译成增量编码)

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

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

比如对上面的数据进行压缩(假设每个block只有3个文件而不是256),压缩过程如下:

a1fc0b5c73fd7b3180de83c55dcf0a4e.png

在返回结果的时候,其实也并不需要把所有的数据直接解压然后一股脑全部返回,可以直接返回一个迭代器iterator,直接通过迭代器的next方法逐一取出压缩的id,这样也可以极大的节省计算和内存开销。

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

总结

ES为了提高搜索效率、优化存储空间做了很多工作。

为了能够快速定位到目标文档,ES使用倒排索引技术来优化搜索速度,虽然空间消耗比较大,但是搜索性能提高十分显著。

由于索引数量巨大,ES无法直接把全部索引放入内存,转而建立词典索引,构建有限状态转换器(FST)放入内存,进一步提高搜索效率。

数据文档的id在词典内的空间消耗也是巨大的,ES使用了索引帧(Frame of Reference)技术压缩posting list,带来的压缩效果十分明显。

ES的filter语句采用了Roaring Bitmap技术来缓存搜索结果,保证高频filter查询速度的同时降低存储空间消耗。

以上为全部内容。

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

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

相关文章

为什么C语言函数不能返回数组,却可以返回结构体

C语言函数为什么不能返回数组?在C语言程序开发中,我们不可以编写下面这样的代码:char f(void[8]{ char ret;// ...fill... return ret; }int main(int argc, char ** argv) {char obj_a[10];obj_a f(); }不可以编写这样的代码这其实就是不能…

oracle迁移mysql_从自建Oracle迁移至RDS MySQL

#本示例以名称为dtstest的数据库账号为例介绍授权命令,需要对PDB和CDB同时授权#PDB授权示例:create user dtstest IDENTIFIED BY rdsdt_dtsacct;grant create session to dtstest;grant connect to dtstest;grant resource to dtstest;grant select on a…

2015年传智播客java_2015年Java 8强势开始

2015年传智播客javaJDK 8从2015年开始,其博客文章和文章的受欢迎程度将激增。 这与本月将 Java 自动升级到JDK 8恰好吻合。 在这篇文章中,我列出并简要描述了2015年已经发布的许多有关JDK 8的文章和帖子。 JDK 8 Streams在最近的帖子中理所当然地受欢迎…

python文件运行哪一个_如何使一个python文件运行另一个?

本问题已经有最佳答案,请猛点这里访问。 如何创建一个python文件来运行另一个? 例如,我有两个.py文件。我想运行一个文件,然后让它运行另一个.py文件。 docs.python.org / / modules.html教程 所以我execfile()模块通常是更好的。…

C语言printf()函数具体解释和安全隐患

程序员都知道,也都会使用printf函数,但你知道它也有“安全隐患”吗?下面就来举例我说说:嵌入式专栏1问题描述打印输出的数据并不是理论值,如下图(右边):嵌入式专栏2进一步描述问题请…

brew search mysql_brew mysql

1、homebrew安装/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"2、命令使用安装软件:brew install 软件名,例:brew install wget搜索软件:brew search 软件名&a…

spring 请求转码_Spring请求级备忘录

spring 请求转码介绍 备注化是一种方法级别的缓存技术,用于加快连续调用的速度。 这篇文章将演示如何仅使用Spring AOP实现任何数据源的请求级可重复读取。 Spring缓存 Spring提供了非常有用的缓存抽象 ,允许您将应用程序逻辑与缓存实现细节分离。 Sp…

java map 如何根据key获得对象_ThreadLocal:Java中的影分身

关于ThreadLocal,你有哪些疑问?ThreadLocal是用来解决什么问题的?如何使用ThreadLocal?ThreadLocal的实现原理是什么?可否举几个实际项目中使用ThreadLocal的案例?基础知识ThreadLocal是线程局部变量&#…

【C语言】你可能对 sizeof() 有点误解。。。

各位,今天还是按照惯例给大家分享一个C语言容易出现的小错误,这也是跟sizeof有关的,问题虽小,却可管中窥豹,话不多说,代码先行:#include int main() { int i; i 8; printf("%d\…

mysql cluster 设置单向复制_mysql单向主从配置

1.环境要求操作系统:centOS6.5或以上Mysql版本:mysql5.5主机配置:4核CPU、4G内存2.主从复制的方式mysql5.6开始主从复制有两种方式:基于日志(binlog)、基于GTID(全局十事务标示符),下面主要介绍基于日志(binlog)的复制…

java处理注释_如何处理Java注释

java处理注释Java 8的一项很酷的新功能是对lambda表达式的支持。 Lambda表达式在很大程度上依赖于FunctionalInterface 注释 。 在本文中,我们将介绍注释以及如何处理它们,以便您可以实现自己的出色功能。 注解 Java 5中添加了注释 。Java语言附带了一…

nginx tcp转发_Nginx学习(九):负载均衡服务

介绍对于请求而言,负载均衡能很好的均摊请求,提高服务端吞吐率和整体性能,多个服务节点部署的方式,也提高了容灾和服务高可用。一、负载均衡分类负载均衡分为:GSLB和SLB。1. GDLB全局负载均衡,往往按照国家…

控制台发送get命令_.NET Core使用命令行参数库构建控制台应用程序

前言在我们开发中可能需要设计一次性应用程序,这些实用程序可以利用接近原始源代码的优势,但可以在与主Web应用程序完全独立的安全性上下文中启动。具体在 [管理过程](https://12factor.net/admin-processes)中也已经列出了原因。创建控制台应用打开命令…

C语言函数为什么不能返回数组?

C语言函数为什么不能返回数组?在C语言程序开发中,我们不可以编写下面这样的代码:char f(void)[8] {char ret; // ...fill... return ret; }int main(int argc, char ** argv) {char obj_a[10]; obj_a f(); }不可以编写这样的代码这其实就是不…

mockito_书评:Mockito Essentials

mockitoSujoy Acharya的Mockito Essentials副标题( Packt出版 ,2014年10月)是:“实用指南,可帮助您使用Mockito进行单元测试并开始运行。” Mockito Essentials中的前言和七章涵盖大约190个实质性页面。 前言 在序言中…

python3 byte 字面值_bytearray() Python 内置函数

转载须注明出处:简书Orca_J35 | GitHuborca-j35 class bytearray([source[, encoding[, errors]]]) 该内置函数本质上是 bytearray 类的构造函数,用于创建一个 bytearray 实例。bytearray 实例是一个由字节(8-bits 无符号)构成的可变序列,并拥…

python如何调用c函数实现真正意义的多线程_python如何使用多线程执行多个函数?...

之前小编给大家介绍了用python去返回了一个值,立马就有小伙伴跟小编留言说道“能都执行多个内容?”于是,小编就给大家整理最细致,也是最简单的实现方法,方便大家理解学习,一起来看下吧~直接上代码&#xff…

Java EE 8怎么了? (第2部分)

Java EE 8的工作仍处于初期阶段,并有望在来年跟上发展步伐,届时我们将看到专家组的完成,围绕用例/功能的更多讨论,大量JIRA和各种规范的草案版本(本会很有趣!)。 在第1部分中 ,我们…

C语言中quot;##quot;的独特用法

市面上有很多比较火的编程语言,比如Python、 JAVA、 Go等,你可能觉得C语言很古老、很落后。如果你有这种想法,那可能你只是一个初学的菜鸟。可能绝大部分 C 程序员都不知道"##"隐藏用法,下面就来给大家讲讲。一、##的“…

html a标签去掉下划线_如何用HTML基本元素制作表格

第2天【HTML基本元素】主要内容标题标签段落标签强制换行水平线图片超链接文本格式化标签列表表格学习目标一、标题标题&#xff08;Heading&#xff09;是通过 <h1> - <h6> 标签进行定义的。<h1> 定义最大的标题。 <h6> 定义最小的标题。标题很重要请…