漫画:什么是Bitmap算法?









两个月以前——java













为知足用户标签的统计需求,小灰利用Mysql设计了以下的表结构,每个维度的标签都对应着Mysql表的一列:程序员



要想统计全部90后的程序员该怎么作呢?算法


用一条求交集的SQL语句便可:
sql


Select count(distinct Name) as 用户数 from table whare age = '90后' and Occupation = '程序员' ;
数据库



要想统计全部使用苹果手机或者00后的用户总合该怎么作?bash


用一条求并集的SQL语句便可:
maven


Select count(distinct Name) as 用户数 from table whare Phone = '苹果' or age = '00后' ;学习





两个月以后——优化












———————————————ui













1. 给定长度是10的bitmap,每个bit位分别对应着从0到9的10个整型数。此时bitmap的全部位都是0。


2. 把整型数4存入bitmap,对应存储的位置就是下标为4的位置,将此bit置为1。



3. 把整型数2存入bitmap,对应存储的位置就是下标为2的位置,将此bit置为1。



4. 把整型数1存入bitmap,对应存储的位置就是下标为1的位置,将此bit置为1。



5. 把整型数3存入bitmap,对应存储的位置就是下标为3的位置,将此bit置为1。




要问此时bitmap里存储了哪些元素?显然是4,3,2,1,一目了然。


Bitmap不只方便查询,还能够去除掉重复的整型数。















1. 创建用户名和用户ID的映射:




2. 让每个标签存储包含此标签的全部用户ID,每个标签都是一个独立的Bitmap。




3. 这样,实现用户的去重和查询统计,就变得一目了然:












1. 如何查找使用苹果手机的程序员用户?




2. 如何查找全部男性或者00后的用户?




















一周以后......











咱们以上一期的用户数据为例,用户基本信息以下。按照年龄标签,能够划分红90后、00后两个Bitmap:





用更加形象的表示,90后用户的Bitmap以下:




这时候能够直接求得90后的用户吗?直接进行非运算?




显然,非90后用户实际上只有1个,而不是图中获得的8个结果,因此不能直接进行非运算。







一样是刚才的例子,咱们给定90后用户的Bitmap,再给定一个全量用户的Bitmap。最终要求出的是存在于全量用户,但又不存在于90后用户的部分。





如何求出呢?咱们可使用异或操做,即相同位为0,不一样位为1。







































































25769803776L = 11000000000000000000000000000000000B

8589947086L = 1000000000000000000011000011001110B















1.解析Word0,得知当前RLW横跨的空Word数量为0,后面有连续3个普通Word。


2.计算出当前RLW后方连续普通Word的最大ID是 64 X (0 + 3) -1 = 191。


3. 因为 191 < 400003,因此新ID必然在下一个RLW(Word4)以后。


4.解析Word4,得知当前RLW横跨的空Word数量为6247,后面有连续1个普通Word。


5.计算出当前RLW(Word4)后方连续普通Word的最大ID是191 + (6247 + 1)X64 = 400063。


6.因为400003 < 400063,所以新ID 400003的正确位置就在当前RLW(Word4)的后方普通Word,也就是Word5当中。


最终插入结果以下:













官方说明以下:


* Though you can set the bits in any order (e.g., set(100), set(10), set(1),
* you will typically get better performance if you set the bits in increasing order (e.g., set(1), set(10), set(100)).
* 
* Setting a bit that is larger than any of the current set bit
* is a constant time operation. Setting a bit that is smaller than an 
* already set bit can require time proportional to the compressed
* size of the bitmap, as the bitmap may need to be rewritten.


复制代码



几点说明:


1. 该项目最初的技术选型并不是Mysql,而是内存数据库hana。本文为了便于理解,把最初的存储方案写成了Mysq数据库。


1.文中介绍的Bitmap优化方法在必定程度上作了简化,源码中的逻辑要复杂得多。好比对于插入数据400003的定位,和实际步骤是有出入的。


2.若是同窗们有兴趣,能够亲自去阅读源码,甚至是尝试实现本身的Bitmap算法。虽然要花很多时间,但这确实是一种很好的学习方法。

EWAHCompressedBitmap对应的maven依赖以下:

复制代码

<dependency>
  <groupId>com.googlecode.javaewah</groupId>
  <artifactId>JavaEWAH</artifactId>
  <version>1.1.0</version>
</dependency>复制代码



—————END—————



喜欢本文的朋友们,欢迎长按下图关注订阅号程序员小灰,收看更多精彩内容

相关文章
相关标签/搜索
本站公众号
   欢迎关注本站公众号,获取更多信息