首先Bitmap算法并不是一种数学公式,而是一种方法!
下面通过一个列子来使你明白何为Bitmap算法!以下数据库以mysql为列!
给出一个表结构,每一行都表示一条记录!
1、要想统计所有70后的演员怎么做?
Select count(distinct Name) as 用户数 from table where Age='70后' and Job='演员';
2、要想统计所有Apple手机使用者或者80后的用户总和怎么做?
Select count(distinct Name) as 用户数 from table where Phone='Apple' or Age='80后';
是不是很简单,几个月后你的数据库越来越长,后面的标签越来越多,导致你sql语句拼接出来是如此的长,而且多个用户求并集的时候用distinct,性能慢的会让人崩溃!
这个时候Bitmap思想就出来了,如果我们可以把一个数据映射到内存的一个bit上,这样对于通过位操作就可以快速的实现大型数据的去重和查询。
举个列子,给出一长度为10bit的内存空间,想要插入整型数据4,3,2,1。
第一步:10bit的所有位数据均为0。
第二步:把数据4存入bitmap,映射到内存存储的位置就是下标为4的位置,将此位置为1。
第三步:把数据3存入bitmap,映射到内存存储的位置就是下标为3的位置,将此位置为1。
第四步:把数据2存入bitmap,映射到内存存储的位置就是下标为2的位置,将此位置为1。
第五步:把数据1存入bitmap,映射到内存存储的位置就是下标为1的位置,将此位置为1。
现在问此时bitmap里存了什么哪些数据?显然4,3,2,1。
那到底跟我上面数据库查询有什么关系?我们来想想,我们的用户标签能不能用Bitmap的形式来存储?
出现上面mysql的查询复杂是因为我们一个用户对应多个标签,如果我们让一个标签对应多个用户呢?这个时候我们就要建立用户名和用户ID的映射,然后让每一个标签存储包含此标签的的用户ID!
比如:
1、建立用户名和用户的ID的映射
2、让每个标签存储包含此标签的所有用户ID,每个标签都是独立的bitmap。
3、这样,实现用户的去重和查询统计,就变的简单了!
好了这就是bitmap的应用!
有人或许不明白HashSet和HashMap也能同样实现去重和统计,我们要用Bitmap,其实他们的每一个ID都存储成int型,占内存多啊,bit只占1,32倍的空间节省!而且bitmap在用户做交集和并集运算很方便,就是平时我们常用的位运算。
1、如何查找使用Apple手机的演员用户?
使用Apple手机的演员用户(0000001010B & 0000000010B =0000000010B)
2、如何查找所有男性或者80后的用户?
男性或者80后的用户(0000001100B | 0000000110B =0000001110B)
当然bitmap也会有缺点,那就是在不知道总用户的情况下,无法用非运算!
最后给个开源的bitmap,谷歌开发的EWAHCompressedBitmap!这个我下篇文章会分析它的存储结构!