• EWAH 意思是 Enhanced Word-Aligned Hybrid,在WAH基础上优化而来。
  • EWAH 算法论文:《Sorting improves word-aligned bitmap indexes》
  • javaewah项目(Java版)GitHub地址:https://github.com/lemire/javaewah
  • EWAHBoolArray项目(C++版) GitHub地址:https://github.com/lemire/EWAHBoolArray

本文基于Java版项目javaewah。

首先

首先要知道,EWAHCompressedBitmap是完全基于行程压缩算法压缩的。

结构就是这样,看起来很简单。

在构造EWAHCompressedBitmap时,内部会初始化一个RunningLengthWord,来存储EWAH压缩算法必需的两个数据结构:

    /*** The array of words.*/final Buffer buffer;/*** The position in array.*/int position;

其中Buffer根据实现的不同可能是

  • LongArray,内部为long[],使用默认构造方法构造Bitmap时就会构造LongArray
  • LongBufferWrapper, 内部为java.nio.LongBuffer,这样可以直接使用NIO的特性。在使用java.nio.ByteBuffer构造Bitmap时会构造LongBufferWrapper

不管什么实现,我们把Buffer直接理解为存储了一堆long的数组即可。

RunningLengthWord

RunningLengthWord存储了EWAHCompressedBitmap的全部数据,是整个项目中的核心。

其原理为:

将整个(未经过任何压缩的)bitmap每64位拆分为一个最小单元(long),只可能出现两种情况:

  1. 64位全都是相同的比特,要么全都是1,要么全都是0,这样的数据可以被run-length压缩。尤其是当这种情况发生在连续的多个long上的时候,压缩效果更为明显。
  2. 64位范围内既有0又有1,这样的数据不进行压缩,而是直接存储字面量,这样的数据在论文中叫做Dirty Word,生动形象。其实如果整个bitmap中大量出现Dirty Word的话,压缩效果会大打折扣。

根据上面的原理,RunningLengthWord使用了这样的实现:

如果所示,在初始化时,Buffer中下标为0的位置一定是一个run-length,其64位被拆分成了三部分:

  • 最低位(Running Bit):表示当前的run-length压缩的是0还是1。
  • 中间32位(Running Length): 表示当前的run-length压缩了几个64位(long)的连续相同bit。如果这个部分值为0,那么最低位的取值没有实际意义。
  • 高31位(Number of Literal Words ):表示当前run-length后面紧接着未压缩的字面量(Dirty Words)的数量。

如果Buffer中下标为N的位置为run-length,且其高位31位表示的Number of Literal Words为2,则Buffer中下标为N+1N+2的两个位置一定是字面量。

另外有一个性能相关的措施,就是设置一个position,始终指向整个Buffer中最后一个run-length,避免始终从头开始寻址。

举个栗子

先插入9

因为要插入9,导致[0, 63]范围变成了Dirty Word,需要存储为字面量,因此会发生下面这些步骤:

  1. 将Buffer中第0个run-length的高位Number of Literal Words部分改为1,表示后面的一个long为字面量;
  2. 在Buffer中下标为1的位置插入一个表示字面量的long,表示[0, 63]范围的值。因为插入了9,所以第9位的位置需要设为1(最低位为第0位)。

再插入666

再插入666的话,如果不压缩,那么将会形成这样的数组:

[640, 703]:Dirty Word,包含值666
[576, 639]:全0
[512, 575]:全0
[448, 511]:全0
[384, 447]:全0
[320, 383]:全0
[256, 319]:全0
[192, 255]:全0
[128, 191]:全0
[ 64, 127]:全0
[  0,  63]:Dirty Word,包含值9

可以看到,除了[0, 63][640, 703]两个Dirty Word,中间的9个long全都是0,是可以进行run-length压缩的。步骤如下:

  1. 在Buffer中下标为2的位置插入一个run-length,其中Running Bit为0(压缩的是0),Running Length为9(压缩了9×64位),Number of Literal Words为1(后面有一个Dirty Word);
  2. position指向2,保持始终指向最后一个run-length;
  3. 在Buffer中下标为3的位置插入一个字面量,表示[640, 703],其中第26位为1,表示插入了值666。
  4. 目前Buffer已满,将数组大小由4扩展为8,以备后用。

run-length和字面量的转换

对于一个字面量

字面量代表的64位范围内既有0又有1,如果经过某些操作后,恰好所有0都变成了1,或者所有的1都变成了0,那么这个字面量就会被转换为run-length。

需要进行以下操作:

  • 因为自己不再是字面量了,所以需要减少前一个run-length的Number of Literal Words的值。
  • 检查前后相邻的long是不是run-length,如果是的话能不能与自己合并。如果合并的话,合并后当前位置将会变成空位,需要将后面的数据整体前移。
  • 如果转换后自己变成最后一个run-length,需要将position指向自己。

对于一个run-length

run-length代表了至少一个、多则成百上千个64位区间全都是相同的bit。如果某些操作导致其中出现一个异常值,将会切断当前run-length,插入至少一个字面量。

需要进行以下操作:

  • 如果异常值出现在run-length的前64位或末尾64位,则需要收缩run-length的大小,在前面或后面插入一个字面量。
  • 如果异常值出现在run-length的中间,则会将当前run-length切成两个较短的run-length,中间插入一个字面量。
  • 如果当前run-length只包含64位,则直接将当前run-length替换为一个字面量。
  • 上述操作完成后,更新发生变动的字面量前面的Number of Literal Words值。

总结

  • 存储结构简单,只有一个大大的long[],在bitmap较大时对GC不太友好。
  • 除了有一个position指向最后一个run-length,其他再没有能帮助随机访问的措施了,这就意味着,基本上所有的对bitmap的随机访问全都要从头开始过一遍,时间是线性的。不过,人家是完全的行程压缩,说随机访问有点欺负人,这种bitmap本身就不适合随机访问,大家也不要这样用。
  • 总觉得压缩差那么点意思。。在极端情况下,压缩率甚至是负的。比如,你每隔64插入一个值试试。。

其实我不应该先研究RoaringBitmap再来研究EWAH的,现在看起来怎么都不如RoaringBitmap了。。

后面我会专门写一篇来比较RoaringBitmap和EWAHCompressedBitmap的性能指标,用数据来说话。

EWAHCompressedBitmap数据结构及原理相关推荐

  1. Caché 实操《Caché 算法与数据结构-数组原理》学习笔记

    参考书  第二章 Caché 算法与数据结构 数组原理_yaoxin521123的博客-CSDN博客 本人Cache'小白,欢迎指教和交流.本文为学习原作者的代码进行代码重现后的总结精炼.使用数据库: ...

  2. 【Go语言学习】——go 数据结构底层原理

    go 数据结构底层原理 array底层原理 go中的数组是由固定长度的特定类型元素组成的序列,数组的长度是数据类型的组成方式,所以不同长度和不同类型的元素组成的数组是不同的数组类型.数组属于值类型,因 ...

  3. GitHub上分享的常用算法和数据结构实现原理可视化系统

    一门编程语言入门之后,要想进阶,必须学习算法和数据结构,但是对于初学者来讲算法和数据结构和数据结构的实现原理和机制过于枯涩.抽象难懂. 这里为小伙伴们分享一个名为Algorithm Visualize ...

  4. mysql是如何管理数据结构_MySQL索引背后的数据结构和原理

    这是我看到的一篇博客,讲得非常详细,分享给大家:http://blog.codinglabs.org/articles/theory-of-mysql-index.html Abstract: 本文以 ...

  5. mysql匹配数据结构_MySQL索引背后的数据结构及原理

    前两天经历了武汉一行腾讯面试,数据库索引是一个面试热点,在此搜集相关资料,以备学习之用. 下面是一位牛人写得关于数据库索引的精品之作,因为很好,不敢修饰,转载至此与博友共享. 本文以MySQL数据库为 ...

  6. python常用代码_Python常用算法学习(4) 数据结构(原理+代码)-最全总结

    数据结构简介 1,数据结构 数据结构是指相互之间存在着一种或多种关系的数据元素的集合和该集合中数据元素之间的关系组成.简单来说,数据结构就是设计数据以何种方式组织并存贮在计算机中.比如:列表,集合与字 ...

  7. long 转为string_面试必问 Redis数据结构底层原理String、List篇

    点击关注上方"Java大厂面试官",第一时间送达技术干货. 阅读文本大概需要 8 分钟. 前言 今天来整理学习下Redis有哪些常用数据结构,都是怎么使用的呢?首先看下全局存储结构 ...

  8. mysql的底层数据结构_MySQL索引底层数据结构实现原理

    MySQL索引背后的数据结构及算法原理 一.定义 索引定义:索引(Index)是帮助MySQL高效获取数据的数据结构. 本质:索引是数据结构. 二.B-Tree m阶B-Tree满足以下条件: 1.每 ...

  9. 【Java基础】HashMap底层数据结构及其原理

    1.简单了解一下HashMap HashMap 就是以 Key-Value 键值对的方式进行数据存储的一种数据结构,它在 JDK 1.7 和 JDK 1.8 中底层数据结构是有些不一样的.简单来说,J ...

最新文章

  1. 第十天2017/04/21(1、函数指针、❤动态库回调❤)
  2. 《系统集成项目管理工程师》必背100个知识点-95我国信息化基本原则
  3. wps出现安装installer_判断本机是否安装Microsoft Office或者wps
  4. 任务管理平台_jytask一个任务调度统一管理平台
  5. javascript event
  6. vue 对象继承_Vue2.0中组件的继承与扩展是什么
  7. 使用deeplearning4j训练Doc2Vec(文档向量)
  8. python classmethod函数_在python中使用与instance和classmethod相同的函数
  9. 微服务实战(八):落地微服务架构到直销系统(服务高可用性)
  10. 计算机应用技术在医院的应用,计算机管理技术在医院的应用
  11. FileZilla Server详细配置
  12. Gateway网关- 微服务(十四)
  13. 云服务器发现安全漏洞怎么解决?
  14. clk_get、clk_enable和clk_get_rate函数
  15. 麦迪关键球失误的背后
  16. html 6是什么格式,ac6是什么格式
  17. Vue SSR 性能优化实践
  18. 图像处理之Lanczos采样放缩算法
  19. 计算机学院混合式局域网 组网方案设计
  20. 使用01字典树解决最大异或问题

热门文章

  1. 程序员的思维修炼读书笔记(二)
  2. Vue开发之基础路由
  3. android返回首页
  4. 无线服务器网速加快,无线路由器网速慢怎么办?
  5. 支付宝芝麻分701,花呗借呗额度提升明显,网友:三年没涨一分
  6. labview:一个采集数据的小程序
  7. 张飞实战电子第一部——门控开关设计笔记
  8. 期货模拟盘有效果吗?
  9. 1425:【例题4】加工生产调度
  10. 网络编程培训之一 编程实现IP/TCP/UDP报文