这几天一直看到bloom filter这个算法。网上的资料很不错了,先摘录下,最后自己给出一个具体的应用。
建立一个容量为500万的Bit Array结构(Bit Array的大小和keyword的数量决定了误判的几率),将集合中的每个keyword通过32个hash函数分别计算出32个数字,然后对这32个数字分别用500万取模,然后将Bit Array中对应的位置为1,我们将其称为特征值。简单的说就是将每个keyword对应到Bit Array中的32个位置上,见下图:
当需要快速查找某个keyword时,只要将其通过同样的32个hash函数运算,然后映射到Bit Array中的对应位,如果Bit Array中的对应位全部是1,那么说明该keyword匹配成功。
可以用来实现数据字典,进行数据的判重,或者集合求交集
其中:k标示hash函数的个数,m表示bit array的长度(位数),n表示实际数据的个数。
注意:如果要测试,比较长的数据,需要调节jvm参数
-server -Xms800m -Xmx800m -XX:MaxNewSize=256m
//待比较的数据长度---对应公式中的N private static final Integer dataLength = 400; //bloom filter的bitArray辅助对象长度,对应公式中M private static final Integer bitArrayLength = 5000; //辅助对象, //将 查找目标hash后的值用bitArrayLengrh取模后的结果 的位置 置为 true private boolean[] bitArray = new boolean[bitArrayLength]; //本地数据集,可以存储在内存中,文件,数据库中 //在系统初始化时,需要将每个值 进行bloom filter处理,初始化bitArray //这样,bitArray就相当于成为了一个带有“信息摘要”的密码本 private Integer[] data = new Integer[dataLength];
//hash函数库 private HashFunction hashFunction = new HashFunction(); /** * @param args */ public static void main(String[] args) { BloomFilter bloomFilter = new BloomFilter(); bloomFilter.init(); Scanner in = new Scanner(System.in); while(in.hasNext()) { int n = in.nextInt(); long old = System.currentTimeMillis(); boolean exsist = bloomFilter.check(n); long nl = System.currentTimeMillis(); if(exsist) { System.out.println("exsist " + (nl - old)); } else { System.out.println("not exsist " + (nl - old)); } } } private void init() { //初始化数据 //在这里只是简单的进行数字赋值,具体应用可以从数据源读取 for(int i =0,j=0; i<dataLength; i++,j+=2) { data[i] = j;//赋值 //bloom filter 核心算法 APHash(data[i]); RSHash(data[i]); JSHash(data[i]); PJWHash(data[i]); ELFHash(data[i]); BKDRHash(data[i]); SDBMHash(data[i]); DJBHash(data[i]); DEKHash(data[i]); BPHash(data[i]); } }
//1.得到data的hash值 //2.将hash值与bitArrayLength模运算 //3.将此为的bitArrayLength置为true private void APHash(Integer data) { int temp = (int)hashFunction.APHash(data.toString()); int l1 = (temp < 0 ? -temp : temp) % bitArrayLength; bitArray[l1] = true; }
private boolean check(Integer n) { if(n > (dataLength-1) * 2 || n < 0) return false; //进行验证,是否所有位均为true,如果有任何一位不是true则表明查找数据不存在 //注意,bloom filter是会存在误差,具体的误差请看wiki上的资料 if(APHashE(n) && RSHashE(n) && JSHashE(n) && PJWHashE(n) && ELFHashE(n) && BKDRHashE(n) && SDBMHashE(n) && DJBHashE(n) && DEKHashE(n) && BPHashE(n)) { return true; } return false; }
如果能够接受误差(具体的误差率可以通过N,M,K的值来计算),就可以用bloom filter来处理判断集合中是否存在某元素的问题,同时空间使用率很低
参考:
http://www.hellodba.net/2009/04/bloom_filter.html
http://blog.redfox66.com/post/mass-data-topic-2-bloom-filter.aspx