漫画:Bitmap算法 整合版

简介: 为满足用户标签的统计需求,小灰利用Mysql设计了如下的表结构,每一个维度的标签都对应着Mysql表的一列。

640.jpg

640.jpg

640.jpg

640.jpg


两个月之前——

640.jpg

640.jpg640.jpg

640.jpg

image.gif

640.jpg


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

640.jpgimage.gif

要想统计所有90后的程序员该怎么做呢?


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

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

要想统计所有使用苹果手机或者00后的用户总合该怎么做?

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

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

                               640.jpg


两个月之后——

                       640.jpg


image.gif640.jpg

640.jpg

640.jpg

image.gif640.jpg

640.jpg

640.jpg


640.jpg


image.gif640.jpg



image.gif

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

640.png 

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

640.png

image.gif

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

640.png


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

640.png


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

image.gif640.png


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

Bitmap不仅方便查询,还可以去除掉重复的整型数。

640.jpg

640.jpg

640.jpg

image.gif640.jpg

640.jpg


image.gif640.jpg


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

640.png


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


640.png


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

image.gif640.png

640.jpg

image.gif

640.jpg

640.jpg

image.gif


640.jpg

image.gif

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

image.gif

640.png


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

640.png

image.gif

640.jpg

640.jpgimage.gif

640.jpg


640.jpg

image.gif

640.jpg


image.gif

640.jpg

640.jpg

image.gif

640.jpg

image.gif


一周之后......



640.jpgimage.gif

640.jpg

640.jpg

image.gif



image.gif

640.jpg



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

640.png


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

640.png

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

640.png

image.gif



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

640.jpg

640.jpgimage.gif


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


640.png



如何求出呢?我们可以使用异或操作,即相同位为0,不同位为1。

640.png

640.jpg

image.gif

640.jpg


640.jpgimage.gif


640.jpg

640.jpg640.pngimage.gif

640.jpg


640.jpg

image.gif

640.png

640.jpg

640.jpgimage.gif

640.png


image.gif

640.jpg


640.jpgimage.gif



image.gif640.jpg


640.png

image.gif

640.jpg


640.pngimage.gif


640.jpg

image.gif

640.png


640.jpgimage.gif


640.png

image.gif

640.jpg


640.jpgimage.gif



640.jpgimage.gif


640.jpg

image.gif

640.jpg


image.gif

640.png


image.gif640.jpg


640.jpg

image.gif640.jpg


640.jpg

image.gif

640.png


25769803776L  =  11000000000000000000000000000000000B

8589947086L = 1000000000000000000011000011001110Bimage.gif


640.jpg

image.gif

640.jpg


image.gif

640.jpg


image.gif


640.jpg

image.gif

640.jpg640.jpg


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当中。

最终插入结果如下:


640.jpg

image.gif640.jpg

640.jpg

 

640.pngimage.gif


640.jpg

image.gif



官方说明如下:


* 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.


640.jpgimage.gif



几点说明:


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>




相关文章
|
1天前
|
算法
时间复杂度与空间复杂度(自漫画算法)
时间复杂度与空间复杂度(自漫画算法)
16 0
|
存储 算法 程序员
bitmap算法的PHP实现,快速去重排序,数据压缩储存
因为电路的逻辑只有0和1两个状态,这里的0和1并不是数字的0和1,0和1是表示两种不同的状态,0表示低电平,1表示高电平。因为计算机是由无数个逻辑电路组成的,只能根据0和1的无限位数和组合来表达信息。 电脑只认识0和1这两个数字,所有的数据在电脑中都是以0和1组成的编码存储的,这样的编码叫做二进制。一个0或一个1就叫做一个位 最初的计算机性能和存储容量都比较差,所以普遍采用4位BCD编码(这个编码出现比计算机还早,最早是用在打孔卡上的)。
322 0
|
算法
【漫画算法学习笔记】第二章——2.1数组
本篇博客总结了《漫画算法》第二章的知识点,并将数组的扩容封装成了工具类
79 0
【漫画算法学习笔记】第二章——2.1数组
|
算法
漫画算法题:两数之和与三数之和
我们来举个例子,给定下面这样一个整型数组(假定数组不存在重复元素):我们随意选择一个特定值,比如13,要求找出两数之和等于13的全部组合。 由于12+1 = 13,6+7 = 13,所以最终的输出结果(输出的是下标)如下:
170 0
漫画算法题:两数之和与三数之和
|
算法 Java
漫画:什么是KMP算法?
KMP算法和BF算法的“开局”是一样的,同样是把主串和模式串的首位对齐,从左到右对逐个字符进行比较。
120 0
|
算法 Java
漫画:如何优化 “字符串匹配算法”?
BF算法是如何工作的? 正如同它的全称BruteForce一样,BF算法使用简单粗暴的方式,对主串和模式串进行逐个字符的比较。
150 0
漫画:如何优化 “字符串匹配算法”?
|
算法
漫画:什么是字符串匹配算法?
比较哈希值是什么意思呢? 用过哈希表的朋友们都知道,每一个字符串都可以通过某种哈希算法,转换成一个整型数,这个整型数就是hashcode: hashcode = hash(string) 显然,相对于逐个字符比较两个字符串,仅比较两个字符串的hashcode要容易得多。
122 0
漫画:什么是字符串匹配算法?
|
存储 算法
漫画:Dijkstra 算法的优化
如何求得最短路径的详细节点,而不仅仅是距离?
130 0
漫画:Dijkstra 算法的优化
|
存储 缓存 算法
漫画:什么是LRU算法?
用户信息当然是存在数据库里。但是由于我们对用户系统的性能要求比较高,显然不能每一次请求都去查询数据库。 所以,小灰在内存中创建了一个哈希表作为缓存,每次查找一个用户的时候先在哈希表中查询,以此提高访问性能。
142 0
漫画:什么是LRU算法?
|
算法
漫画:如何实现抢红包算法?
发出一个固定金额的红包,由若干个人来抢,需要满足哪些规则?所有人抢到金额之和等于红包金额,不能超过,也不能少于。每个人至少抢到一分钱。要保证所有人抢到金额的几率相等。
164 0
漫画:如何实现抢红包算法?

热门文章

最新文章