Java集合框架分析(八)——从哈希到布隆过滤器

        今天说一个新的数据结构,布隆过滤器。

一.哈希的优缺点:

       首先我们要从哈希说起,对于数据的存储,查询,插入,哈希表肯定是最好的选择,他的时间复杂度接近于O(1)。但是为了减少哈希冲突,也就是为了时间复杂度尽量小,就要空间利用率相对低。这就是用空间换时间。所以说哈希表的优点是速度快,准确,缺点是空间浪费。现在我们从一个经典问题来看,比如gmail需要过滤垃圾邮件,怎么做呢?就是把这些垃圾邮件全部保存起来,全球的垃圾邮件地址就算是1亿个,这么大的集合要是用哈希表存的话,是直接存入内存中的,这样哈希表的存储效率的缺点就体现出来了,为了解决空间存储效率的问题,就要用到布隆过滤器这个数据结构。他可以只用哈希表1/8到1/4的空间,并且时间复杂度也是一个可以接受的常数。

二.信息指纹:

       分析布隆过滤器之前,要先提到一个信息指纹的概念,比如抓犯人的时候,把每个人都看成一个对象,要想判断这个人是不是凶手,难道要讲犯人的每个属性都比较过去吗?显然是不用的,看过侦探片的都知道很多时候只要找到指纹这个关键的证据,案件也就差不多了。这样判断一个人是不是犯人就只要判断每个人的指纹就行了。把这个概念抽象出来,想判断一个集合中是否有元素A,只要判断A的信息指纹就行了,那么就是说数据存入的时候只要将元素的信息指纹存进去就行了。如何实现呢?就是把所有元素都映射成一个128bit(就是16字节)的信息指纹。我们假设要存储一批网址(一般用于网络爬虫),每个网址的URL长度不同,设他们平均100字节,那么存储大小就从100字节到了16字节,就是原来的1/6!!这就是一个关键原理。

三.位图法算法(bitmap):

         有了信息指纹的概念我们很容易就想到把对象存储变成对象的信息 指纹映射。而每个信息指纹都是128bit,这里怎么理解呢,假设有这样一组数据{5,1,7,15,0,4,6,10},总共8个整型数据,其中最大数是15,

那么我们就建立一个长度为15+1=16的数组,并且每个位置初始化为0.



 接着,每个数据的值就是他在数组中的索引位置,存在的就变为1.


 

这样就得到了一个信息指纹。我们把这样的一个算法或者说数据结构叫做位图法(bitmap)

       具体到实际问题中来,我们要查找一个集合是否含有元素A,只要通过一个hash算法得到元素A的8个值当做输入值,通过,只要有一个位置不同,那么元素就不相同。好了说到这里差不多把布隆过滤器的核心算法给引出来了。

 四.布隆过滤器(简单实现):

       我们以一个实际例子为例来说明布隆过滤器过程。假定我们要存储1亿个网址的URL。

1.就要先建立一个16亿二进制(因为每个元素最终都要映射成一个128bit,1字节=8bit,1 int=2字节,所以2*8*8=128)并且都设置成0.

2.将每个网址的URL作为key值,通过8个随机函数生成8个value值。

3.我们再来一个哈希函数,分别以这8个value值为键,会得到8个数值(范围为1到十六亿的某个数字)。

4.以现在这8个数值为下标索引,将8个索引位置上的二进制变成1。

       搞定!这样一个URL就映射成了一个128bit的二进制信息指纹。查询的时候还是通过相同的哈希函数来得到信息指纹,对比,只要有一个不为1就不相等。

      总的来说:1.布隆过滤器就是将元素映射成位编码来储存。

                        2.布隆过滤器存在一种误判性,就是说若是有的URL正好经过计算之后得到相同的value,当然这种情况的概率很低。而且出错概率P和我们定义的bit有关,我们定义的bit为128,就是生成8个value,则此时的误差率在万分之一以下。

      布隆过滤器的简单过程就是这样,当然他可没那么简单,下一篇我会对布隆过滤器的内部实现机制的数学原理进行详细分析。

        

猜你喜欢

转载自linhaoxiang.iteye.com/blog/2062320