[转]海量数据解决思路之BitMap

一、概述

本文将讲述Bit-Map算法的相关原理,Bit-Map算法的一些利用场景,例如BitMap解决海量数据寻找重复、判断个别元素是否在海量数据当中等问题.最后说说BitMap的特点已经在各个场景的使用性。

二、Bit-Map算法

先看看这样的一个场景:给一台普通PC,2G内存,要求处理一个包含40亿个不重复并且没有排过序的无符号的int整数,给出一个整数,问如果快速地判断这个整数是否在文件40亿个数据当中?

问题思考:

40亿个int占(40亿*4)/1024/1024/1024 大概为14.9G左右,很明显内存只有2G,放不下,因此不可能将这40亿数据放到内存中计算。要快速的解决这个问题最好的方案就是将数据搁内存了,所以现在的问题就在如何在2G内存空间以内存储着40亿整数。一个int整数在java中是占4个字节的即要32bit位,如果能够用一个bit位来标识一个int整数那么存储空间将大大减少,算一下40亿个int需要的内存空间为40亿/8/1024/1024大概为476.83 mb,这样的话我们完全可以将这40亿个int数放到内存中进行处理。

具体思路:

1个int占4字节即4*8=32位,那么我们只需要申请一个int数组长度为 int tmp[1+N/32]即可存储完这些数据,其中N代表要进行查找的总数,tmp中的每个元素在内存在占32位可以对应表示十进制数0~31,所以可得到BitMap表:

tmp[0]:可表示0~31

tmp[1]:可表示32~63

tmp[2]可表示64~95

.......

那么接下来就看看十进制数如何转换为对应的bit位:

假设这40亿int数据为:6,3,8,32,36,......,那么具体的BitMap表示为:

如何判断int数字在tmp数组的哪个下标,这个其实可以通过直接除以32取整数部分,例如:整数8除以32取整等于0,那么8就在tmp[0]上。另外,我们如何知道了8在tmp[0]中的32个位中的哪个位,这种情况直接mod上32就ok,又如整数8,在tmp[0]中的第8 mod上32等于8,那么整数8就在tmp[0]中的第八个bit位(从右边数起)。

三、Bit-Map算法原始实现

标注下,这部分来自blog:http://blog.csdn.net/hguisu/article/details/7880288的第五部分。好,来看看c语言的实现:


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

                                  

//set 设置所在的bit位为1

void set(int i) {      

    a[i>>SHIFT] |=  (1<<(i & MASK));

}

//clr 初始化所有的bit位为0

void clr(int i) {      

    a[i>>SHIFT] &= ~(1<<(i & MASK));

}

//test 测试所在的bit为是否为1

int  test(int i){

    return a[i>>SHIFT] &   (1<<(i & MASK));

}                                                                      

int main()

{   int i;

    for (i = 0; i < N; i++)

        clr(i);

    while (scanf("%d", &i) != EOF)

        set(i);

    for (i = 0; i < N; i++)

        if (test(i))

            printf("%d\n", i);

    return 0;

}

注明: 左移n位就是乘以2的n次方,右移n位就是除以2的n次方

解析本例中的void set(int i) {        a[i>>SHIFT] |=  (1<<(i & MASK)); }
1)  i>>SHIFT: 
其中SHIFT=5,即i右移5为,2^5=32,相当于i/32,即求出十进制i对应在数组a中的下标。比如i=20,通过i>>SHIFT=20>>5=0 可求得i=20的下标为0;

2)  i & MASK: 
其中MASK=0X1F,十六进制转化为十进制为31,二进制为0001 1111,i&(0001 1111)相当于保留i的后5位。

比如i=23,二进制为:0001 0111,那么 
                        0001 0111 
                  &    0001 1111 = 0001 0111 十进制为:23 
比如i=83,二进制为:0000 0000 0101 0011,那么 
                         0000 0000 0101 0011 
                    &   0000 0000 0001 0000 = 0000 0000 0001 0011 十进制为:19

i & MASK相当于i%32。

3) 1<<(i & MASK) 
相当于把1左移 (i & MASK)位。 
比如(i & MASK)=20,那么i<<20就相当于: 
        0000 0000 0000 0000 0000 0000 0000 0001 << 20 
      =0000 0000 0001 0000 0000 0000 0000 0000

注意上面 “|=”.

在博文:位运算符及其应用 提到过这样位运算应用:

将int型变量a的第k位清0,即a=a&~(1<<k)
将int型变量a的第k位置1, 即a=a|(1<<k)

这里的将  a[i/32] |= (1<<M));第M位置1 .

4) void set(int i) {        a[i>>SHIFT]  |=  (1<<(i & MASK)); }等价于:

  1. void set(int i)
  2. {
  3. a[i/32] |= (1<<(i%32));
  4. }

即实现上面提到的三步:

1.求十进制0-N对应在数组a中的下标: n/32

2.求0-N对应0-31中的数:N%32=M

3.利用移位0-31使得对应32bit位为1: 1<<M,并置1;

四、BitMap算法一些其他应用场景扩展

(1)BitMap小小变种:2-BitMap。

看个小场景:在3亿个整数中找出不重复的整数,限制内存不足以容纳3亿个整数。

对于这种场景我可以采用2-BitMap来解决,即为每个整数分配2bit,用不同的0、1组合来标识特殊意思,如00表示此整数没有出现过,01表示出现一次,11表示出现过多次,就可以找出重复的整数了,其需要的内存空间是正常BitMap的2倍,为:3亿*2/8/1024/1024=71.5MB。

具体的过程如下:

扫描着3亿个整数,组BitMap,先查看BitMap中的对应位置,如果00则变成01,是01则变成11,是11则保持不变,当将3亿个整数扫描完之后也就是说整个BitMap已经组装完毕。最后查看BitMap将对应位为11的整数输出即可。

(2)对没有重复元素的整数进行排序。

对于非重复的整数排序BitMap有着天然的优势,它只需要将给出的无重复整数扫描完毕,组装成为BitMap之后,那么直接遍历一遍Bit区域就可以达到排序效果了。

举个例子:对整数4、3、1、7、6进行排序

BitMap如下:

直接按Bit位输出就可以得到排序结果了。

五、总结

本文主要讲述了BitMap算法的相关概念以及其一些相关的应用场景和实现方法。其实BitMap的应用场景远远不止点,比如还可以用于压缩、爬虫系统中url去重、解决全组合问题。可能有些人觉得BitMap算法实现起来有点麻烦,其实某些语言是对BitMap算法进行了封装的,比如java中对应BitMap的数据结构就有BitSet类。其使用方法相当简单,看看API就ok,还是给个例子吧:


1

2

3

4

5

6

7

8

9

10

11

12

13

14

import java.util.BitSet;

public class Test{

    public static void main(String[] args) {

        int [] array = new int [] {1,2,3,22,0,3};

        BitSet bitSet  = new BitSet(6);

        //将数组内容组bitmap

        for(int i=0;i<array.length;i++)

        {

            bitSet.set(array[i], true);

        }

       System.out.println(bitSet.size());

        System.out.println(bitSet.get(3));

    }

}

对应的bit位如果有对应整数那么通过bitSet.get(x)会返回true,反之false。其中x为BitMap位置下标。

好了,BitMap就说到这里。下次blog说说处理海量数据的“万金油”-Hash算法,以及它在MapReduce框架中的应用。

转自 http://zengzhaozheng.blog.51cto.com/8219051/1404108

时间: 2024-10-10 05:12:31

[转]海量数据解决思路之BitMap的相关文章

【转】海量数据解决思路之BitMap

转载(http://zengzhaozheng.blog.51cto.com/8219051/1404108) 一.概述 本文将讲述Bit-Map算法的相关原理,Bit-Map算法的一些利用场景,例如BitMap解决海量数据寻找重复.判断个别元素是否在海量数据当中等问题.最后说说BitMap的特点已经在各个场景的使用性. 二.Bit-Map算法 先看看这样的一个场景:给一台普通PC,2G内存,要求处理一个包含40亿个不重复并且没有排过序的无符号的int整数,给出一个整数,问如果快速地判断这个整数

海量数据解决思路之Hash算法

海量数据解决思路之Hash算法   一.概述 本文将粗略讲述一下Hash算法的概念特性,里边会结合 分布式系统负载均衡 实例对Hash的一致性做深入探讨.另外,探讨一下Hash算法在海量数据处理方案中的通用性.最后,从源代码出发,具体分析一下Hash算法在MapReduce框架的中的应用. 二.Hash算法 Hash可以通过散列函数将任意长度的输入变成固定长度的输出,也可以将不同的输入映射成为相同的相同的输出,而且这些输出范围也是可控制的,所以起到了很好的压缩映射和等价映射功能.这些特 性被应用

[转]海量数据解决思路之Hash算法

一.概述 本文将粗略讲述一下Hash算法的概念特性,里边会结合分布式系统负载均衡实例对Hash的一致性做深入探讨.另外,探讨一下Hash算法在海量数据处理方案中的通用性.最后,从源代码出发,具体分析一下Hash算法在MapReduce框架的中的应用. 二.Hash算法 Hash可以通过散列函数将任意长度的输入变成固定长度的输出,也可以将不同的输入映射成为相同的相同的输出,而且这些输出范围也是可控制的,所以起到了很好的压缩映射和等价映射功能.这些特性被应用到了信息安全领域中加密算法,其中等价映射这

Can&#39;t connect to local MySQL server through socket ‘/var/run/mysqld/mysqld.sock‘ (2)解决思路

首先说明一下mysql.sock文件的作用: 连接mysql有两种方式,第一种是TCP/IP,第二种就是直接使用unix domain socket,它比TCP/IP块. mysql.sock是在mysql-server和client在同一服务器上时,发起本地连接时可用,而无需定义-h参数指定具体的IP.mysql.sock是随每次mysql server启动时生成,通常配置参数是将mysql.sock生成在/tmp/目录下.即在/etc/my.cnf文件中指定socket=/tmp/mysql

防止多图OOM的核心解决思路就是使用LruCache技术

防止多图OOM的核心解决思路就是使用LruCache技术.但LruCache只是管理了内存中图片的存储与释放,如果图片从内存中被移除的话,那么又需要从网络上重新加载一次图片,这显然非常耗时.对此,Google又提供了一套硬盘缓存的解决方案:DiskLruCache(非Google官方编写,但获得官方认证).只可惜,Android Doc中并没有对DiskLruCache的用法给出详细的说明,而网上关于DiskLruCache的资料也少之又少,因此今天我准备专门写一篇博客来详细讲解DiskLruC

一个Android多平台问题兼容解决思路

问题:使用AS打出来的签名包,在调试一直用的5.0的小米手机上可以正常运行,4.4的联想手机上闪退,5.1的模拟器上闪退. 抛出:java.lang.UnsatisfiedLinkError,ClassLoader找不到相关的so库. 解决思路: 猜想跟CPU架构有关系,查询如下(cat /proc/cpuinfo): 模拟器:                     电脑使用的是Intel的cpu                         x86_64架构 联想:Processor  

Jquery UI - DatePicker 在Dialog中无法自动隐藏的解决思路

通过Jquery UI Dialog模态展示如下的一个员工编辑页面,但是遇到一个奇怪的问题:点击Start Date的input元素后,其无法失去焦点.从而导致DatePicker控件在选择日期后无法自动隐藏. 解决思路:给DatePicker加上onSelect事件,在该事件中让Start Date的input元素的父元素获取焦点,这样DatePicker控件在选择日期后就自动隐藏.

Qt新建项目No valid kits found解决思路

Qt新建项目No valid kits found解决思路 第一次用Qt Creator创建Project时,进入Kit Selection窗口后,会提示No Valid kits found. Please add a kit in the options or via the maintenance tool of the SDK.错误. 解决思路如下: 需要设置Qt SDK,Device type等的路径给Qt Creator.假设已装Qt SDK,安装方法在(这里).解决方法:点击蓝色o

系统优化(一)Maven打包同一个jar有不同的:版本+时间戳(解决思路)

解决:maven仓库的ear里面有很多个相同的jar(只是包含不同的:版本+时间戳) 问题描述: 发现ear里面有很多个相同的jar,只是包含不同的:版本+时间戳,如下图所示: (例如:itoo-basic-api有很多相同的jar,只是包含不同的:版本+时间戳) 解决思路 用权限的itoo-authority-usergroup-ear模块进行测试 1.怀疑是:maven的坐标,时间戳的问题 关键字: maven snapshot maven war中同一个jar有很多不同版本 maven 本