Bloom Filter --海量数据过滤的发动机

来源:互联网 发布:淘宝卖的红酒 编辑:程序博客网 时间:2024/05/02 21:40

Bloom Filter 布隆过滤器

部分内容参考这位大神的http://blog.csdn.net/hguisu/article/details/7866173


  在保证一定高效空间效率和一定的出错率的前提下判断元素是不是集合中的成员。而存在的错误只可能存在于元素位于集合中, 对于元素不存在集合中的情况是不会产生错误的情况的。由于存在一定的可能低错误,则不适用于“0错误”的场合。


介绍

  如果存在上百万量的数据的时候,如何判断集合R中是否已经存在元素x呢,一种在少量数据中很常见的做法就是将所有的数据存入在R中,然后遍历这个集合判断元素是否在集合中,这种做法当然可以,但是在大数据的情况下,这样的方法显然不适合,如此大的数据显然会占用很多的内存,于是想到将这些元素数据通过MD5计算得到较短的字符串,虽然短小,但是数据量大,内存还是很难受。
  可行的方法总是被人想到,那将元素通过hash函数,将元素映射到位数组上,如果该元素经过哈希等到的数组的某一位置1,表示该元素已经存在。
  **问题:**hash函数总存在冲突的问题,为减少函数冲突的问题,借鉴Universal Hash的方法,构造多个Hash函数,由此引出
  Bloom Filter的基本思想:如果通过其中的一个Hash值我们得出某元素不在集合中,那么该元素肯定不在集合中。只有在所有的Hash函数告诉我们该元素在集合中时,才能确定该元素存在于集合中。

原理

初始化

  • 使用M位位数组,初始条件下,每一位都为0;
  • 选择k个hash函数,每个hash都将元素x映射到{1—M}的范围内

添加元素

  • 对于每个元素,可以根据hash函数,计算出k个hash值,对于这些值(1—M),将这些值填写在位数组中,具体的操作是使那个位置的数置为1

判断元素是否在集合中

  • 对于这个元素,根据hash函数,计算出k个hash值,对于每个hash值,如果对应的位置都被置为1,则返回true,只要一个不为1,则直接返回false

过程如下图:
这里写图片描述

实现

两个主要的方法 add和membershipTest

add(Key key) 将元素hash并添加到位数组对应位置中

public void add(Key key){    if(key ==null){        throw new NullPointerException(".....");    }    int[] h= hash.hash(key);    hash.clear();    for(int i =0; i<nbHash ;i++){        bits.set(h[i]);    }}

membershipTest 判断元素是否在集合中

public boolean membershipTest(Key key){    if(key ==null){        throw new NullPointerException(".....");    }    int[] h= hash.hash(key);    hash.clear();    for(int i =0; i<nbHash ;i++){        if(!bits.get(h[i])){            return false;        }    }    return true;}

两个重要的问题

不能删除集合中的元素

  原因是如果删除了一个元素的置位,则对于其他元素的这一置位也会受到影响。
  一个简单的改进:使用引用计数,而不是单一的位置1,使用counting Bloom filter,就可以支持删除了。

m,k的选择

  如何根据输入个数(n),来选定位数组m的大小和hash函数的个数k。即hash函数会影响效率。当hash函数个数k=(ln2)*(m/n)时错误率最小。在错误率不大于E的情况 下,m至少要等于n*lg(1/E) 才能表示任意n个元素的集合。但m还应该更大些,因为还要保证bit数组里至少一半为0,则m应 该>=nlg(1/E)*lge ,大概就是nlg(1/E)1.44倍(lg表示以2为底的对数)。
  举个例子我们假设错误率为0.01,则此时m应大概是n的13倍。这样k大概是8个。
  具体可以查看http://blog.csdn.net/hguisu/article/details/7866173#t2 说得非常详细呢

MapReduce中的应用

  假设有2个表需要进行内连接,其中一个表非常大,另一个表非常小,这是为了加快处理速度,通常会基于小表创建连接列上的Bloom Filter,具体的做法就是先创建Bloom Filter对象,然后将小表连接列上的值都保存到Bloom Filter上,然后开始通过Mapreduce作业执行内连接。
  在Map阶段,读取小表的时候直接输出连接列值为Key,以数据为value的键值对,在读取大表的时候,则在输出前先判定连接列值是否在Bloom Filter中,如果存在则以同样的方式输出,如果不存在则不需要输出,这样就很大程度地提高了效率。
  在Reduce阶段,针对每个连接列值连接2个表的元组合并输出结果。

1 0
原创粉丝点击