大数据处理算法二:Bloom Filter算法

来源:互联网 发布:网络广告位招商 编辑:程序博客网 时间:2024/05/16 15:27

百度面试题:给定a、b两个文件,各存放50亿个url,每个url各占64字节,内存限制是4G,让你找出a、b文件共同的url?

Bloom Filter是由Bloom1970年提出的一种多哈希函数映射的快速查找算法。通常应用在一些需要快速判断某个元素是否属于集合,但是并不严格要求100%正确的场合。

实例 

  为了说明Bloom Filter存在的重要意义,举一个实例:

   (实例一),假设要你写一个网络蜘蛛(web crawler)。由于网络间的链接错综复杂,蜘蛛在网络间爬行很可能会形成。为了避免形成,就需要知道蜘蛛已经访问过那些URL。给一个URL,怎样知道蜘蛛是否已经访问过呢?稍微想想,

         (实例二)给定ab两个文件,各存放50亿个url,每个url各占64字节,内存限制是4G,让你找出ab文件共同的url

就会有如下几种方案:

  1. 将访问过的URL保存到数据库。

  2. HashSet将访问过的URL保存起来。那只需接近O(1)的代价就可以查到一个URL是否被访问过了。

  3. URL经过MD5SHA-1等单向哈希后再保存到HashSet或数据库。

  4. Bit-Map方法。建立一个BitSet,将每个URL经过一个哈希函数映射到某一位。

  方法1~3都是将访问过的URL完整保存,方法4则只标记URL的一个映射位。

       以上方法在数据量较小的情况下都能完美解决问题,但是当数据量变得非常庞大时问题就来了。

  方法1的缺点:数据量变得非常庞大后关系型数据库查询的效率会变得很低。而且每来一个URL就启动一次数据库查询是不是太小题大做了?

  方法2的缺点:太消耗内存。随着URL的增多,占用的内存会越来越多。就算只有1亿个URL,每个URL只算50个字符,就需要5GB内存。

  方法3:由于字符串经过MD5处理后的信息摘要长度只有128BitSHA-1处理后也只有160Bit,因此方法3比方法2节省了好几倍的内存。

  方法4消耗内存是相对较少的,但缺点是单一哈希函数发生冲突的概率太高。还记得数据结构课上学过的Hash表冲突的各种解决方法么?若要降低冲突发生的概率到1%,就要将BitSet的长度设置为URL个数的100倍。

  实质上上面的算法都忽略了一个重要的隐含条件:允许小概率的出错,不一定要100%准确!也就是说少量url实际上没有没网络蜘蛛访问,而将它们错判为已访问的代价是很小的——大不了少抓几个网页呗。 

例如有 一组字符 arr:”哈哈“,”呵呵“........

字符串:“哈哈”

哈希算法1处理后:8

哈希算法2处理后:1

哈希算法1处理后:3

插入BitArray后


再处理字符串:“呵呵”

哈希算法1处理后:2

哈希算法2处理后:1

哈希算法1处理后:9

 

继续插入BitArray后,如果继续游字符串,继续以这种方式插入

 

判断”在这些字符串是否包含”嘻嘻“

哈希算法1处理后:0

哈希算法2处理后:1

哈希算法1处理后:7

只要判断 下标分别为 0,1,7位置的值是否都为1,如下图 因为位置0跟位置7的值不为1

所以”嘻嘻“不包含在arr中,反之如果都为1怎包含


java代码实现如下

[java] view plaincopy
  1. import java.util.ArrayList;  
  2. import java.util.BitSet;  
  3. import java.util.List;  
  4.   
  5. /** 
  6.  * BloomFilter算法 
  7.  *  
  8.  * @author JYC506 
  9.  *  
  10.  */  
  11. public class BloomFilter {  
  12.     /*哈希函数*/  
  13.     private List<IHashFunction> hashFuctionList;  
  14.     /*构造方法*/  
  15.     public BloomFilter() {  
  16.         this.hashFuctionList = new ArrayList<IHashFunction>();  
  17.     }  
  18.     /*添加哈希函数类*/  
  19.     public void addHashFunction(IHashFunction hashFunction) {  
  20.         this.hashFuctionList.add(hashFunction);  
  21.     }  
  22.     /*删除hash函数*/  
  23.     public void removeHashFunction(IHashFunction hashFunction) {  
  24.         this.hashFuctionList.remove(hashFunction);  
  25.     }  
  26.     /*判断是否被包含*/  
  27.     public boolean contain(BitSet bitSet, String str) {  
  28.         for (IHashFunction hash : hashFuctionList) {  
  29.             int hashCode = hash.toHashCode(str);  
  30.             if(hashCode<0){  
  31.                 hashCode=-hashCode;  
  32.             }  
  33.             if (bitSet.get(hashCode) == false) {  
  34.                 return false;  
  35.             }  
  36.         }  
  37.         return true;  
  38.     }  
  39.     /*添加到bitSet*/  
  40.     public void toBitSet(BitSet bitSet, String str) {  
  41.         for (IHashFunction hash : hashFuctionList) {  
  42.             int hashCode = hash.toHashCode(str);  
  43.             if(hashCode<0){  
  44.                 hashCode=-hashCode;  
  45.             }  
  46.             bitSet.set(hashCode, true);  
  47.         }  
  48.     }  
  49.       
  50.     public static void main(String[] args) {  
  51.         BloomFilter bloomFilter=new BloomFilter();  
  52.         /*添加3个哈希函数*/  
  53.         bloomFilter.addHashFunction(new JavaHash());  
  54.         bloomFilter.addHashFunction(new RSHash());  
  55.         bloomFilter.addHashFunction(new SDBMHash());  
  56.         /*长度为2的24次方*/  
  57.         BitSet bitSet=new BitSet(1<<25);  
  58.         /*判断test1很test2重复的字符串*/  
  59.         String[] test1=new String[]{"哈哈","我","大家","逗比","有钱人性","小米","Iphone","helloWorld"};  
  60.         for (String str1 : test1) {  
  61.             bloomFilter.toBitSet(bitSet, str1);  
  62.         }  
  63.         String[] test2=new String[]{"哈哈","我的","大家","逗比","有钱的人性","小米","Iphone6s","helloWorld"};  
  64.         for (String str2 : test2) {  
  65.             if(bloomFilter.contain(bitSet, str2)){  
  66.                 System.out.println("'"+str2+"'是重复的");  
  67.             }  
  68.         }  
  69.           
  70.     }  
  71. }  
  72. /*哈希函数接口*/  
  73. interface IHashFunction {  
  74.     int toHashCode(String str);  
  75. }  
  76.   
  77. class JavaHash implements IHashFunction {  
  78.   
  79.     @Override  
  80.     public int toHashCode(String str) {  
  81.         return str.hashCode();  
  82.     }  
  83.   
  84. }  
  85.   
  86. class RSHash implements IHashFunction {  
  87.   
  88.     @Override  
  89.     public int toHashCode(String str) {  
  90.         int b = 378551;  
  91.         int a = 63689;  
  92.         int hash = 0;  
  93.         for (int i = 0; i < str.length(); i++) {  
  94.             hash = hash * a + str.charAt(i);  
  95.             a = a * b;  
  96.         }  
  97.         return hash;  
  98.     }  
  99.   
  100. }  
  101.   
  102. class SDBMHash implements IHashFunction {  
  103.   
  104.     @Override  
  105.     public int toHashCode(String str) {  
  106.         int hash = 0;  
  107.         for (int i = 0; i < str.length(); i++)  
  108.             hash = str.charAt(i) + (hash << 6) + (hash << 16) - hash;  
  109.         return hash;  
  110.     }  
  111.   
  112. }  
0 0