算法系列-大数据系列-Bloom Filter

这几天一直看到bloom filter这个算法。网上的资料很不错了,先摘录下,最后自己给出一个具体的应用。

 

bloom filter的wiki

 

几个应用

问题 写道
A和B中各存放着一亿条不重复的URL,URL存放时无序的,且URL是没有特征的,A和B可以试任意数据结构,也可以是存在数据库中。

如何找出A中有而B中没有的URL。
问题 写道
给你A,B两个文件,各存放50亿条URL,每条URL占用64字节,内存限制是4G,让你找出A,B文件共同的URL。如果是三个乃至n个文件呢?

 

 

关于bloom filter

 写道
Bloom Filter是一种空间效率很高的随机数据结构,它利用位数组很简洁地表示一个集合,并能判断一个元素是否属于这个集合。Bloom Filter的这种高效是有一定代价的:在判断一个元素是否属于某个集合时,有可能会把不属于这个集合的元素误认为属于这个集合(false positive)。因此,Bloom Filter不适合那些“零错误”的应用场合。而在能容忍低错误率的应用场合下,Bloom Filter通过极少的错误换取了存储空间的极大节省。
 写道
Bloom Filter。它是一种基于随机数(或Hash)的数据结构,它支持对成员使用较少空间来存储,却能得到较高效率的查询。换句话说:在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匹配成功。

 

适用范围

可以用来实现数据字典,进行数据的判重,或者集合求交集 

扩展

Bloom filter将集合中的元素映射到位数组中,用k(k为哈希函数个数)个映射位是否全1表示元素在不在这个集合中。Counting bloom filter(CBF)将位数组中的每一位扩展为一个counter,从而支持了元素的删除操作。Spectral Bloom Filter(SBF)将其与集合元素的出现次数关联。SBF采用counter中的最小值来近似表示元素的出现频率。 


关于错误率

 

其中: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

你可能感兴趣的:(jvm,数据结构,算法,.net,J#)