网页爬虫之布隆滤波原理及java实现

前续:网页上已经有很多布隆过滤器很全的资料了,由于博主最近在做网页爬虫,遇到url防重问题,所以认真分析了布隆滤波器原理,也参考了相关博文。旨在给出不同人对其不同的理解,好给大家更全面的参考。

1、布隆过滤器原理

布隆过滤器=位图+哈希。一个空的布隆过滤器是一个m位的位图,所以位值开始均为0,定义k个不同的符合均匀随机分布的哈希函数,每个函数把集合元素映射到位图m位中的某一位。插入时,先把这个元素作为k个哈希函数的输入,拿到k组数组位置,然后把这所有的位置设置为1,。查询时,把这个元素作为k个哈希函数的输入,得到k组数组位置。这些位置只要有任意一个是0,元素肯定不会在这个集合里面。如果元素在集合里面,那么这些位置在元素插入时都被设置为1了。如果这些位置都是1,那么要么元素在集合里面,要么所有这些位置在其他元素插入时都被设置为1了,发生了“虚报”。
该过程这样理解:首先插入 “A”  “B”  “C”三个元素,可以通过散列表拿到A B C所对应的哈希码。如果 A元素对应的哈希码为 000101,位图开始是m位的全零的bits,那我把位图的最低位和从最低位开始第三位设置为1。B也是同样的道理,如果B对应的哈希码为0010,那么现在的位图为000111,如果c对应为10000,此时位图为010111,如果再来一个c,发现位图的最低位开始第五位为1,那么证明该位图中含有c元素,所以不对c元素进行存储。这里存在另一种情况,如果a对应的是001111,b对应的是000001,先进来a,然后进来b的时候发现最低位置一了,就会判断b已经存在(其实b还没存在集合中),所以就会产生漏判。但是不会出现误判现象,即a已经存在集合中,但是判断的时候说没存在集合中,这种情况不会产生。所以该布隆过滤器会存在一个漏判率。
优缺点:
优点:1、存储空间和插入/查询时间都是常数,远远超过一般的算法;
            2、Hash函数相互之间没有关系,生成hash码时可以并行处理;
            3、不需要存储本身值,对保密性要求高的场合有很强的实用性;
            4、耗费空间减少到散列表的1/8到1/4;
缺点:1、有一定的漏判概率;
            2、删除元素有困难,这个也好理解A对应的码是001111,B如果对应的码是000001,那么删除A时无法保证不误删掉和A共用最低位B对应的码。所以删除很不方便,如果要保证正确删除的话,需要做辅助变量和相应逻辑。

 布隆滤波器的误报率介绍:  给定一个布隆过滤器,m是该位数组的大小,K是hash函数的个数,n是要插入的元素个数,则误报的概率近似为:,可以看出:随着位数m的增加,假正例(false positives)的概率会下降,同时随着插入元素的个数n的增加,假正例的概率会增加,所以误报率最小的k约等于0.7*m/n。

2、java代码实现

package edu.bit.ys.spider.method;

import java.util.ArrayList;
import java.util.BitSet;
import java.util.List;

public class BloomFilterNew {
	
	public static final int BLOOMSIZE=2<<24;						//规定bloom的长度24bits
	public static final int[] seeds={3,5,7,11,13,31,37,61,131};			        //8个hashset函数
	private BitSet bits=new BitSet(BLOOMSIZE);						//定义一个24位长的bit 所有位初始值都是false
	
	//把字符串加到布隆滤波器中,简而言之就是把该字符串的相应hashcode映射到bits上
	public boolean add(String s){
		if(s.equals("")||(s==null)){
			return false;
		}
		for(int i=0;i<seeds.length;i++){
			HashCodeGen hcg=new HashCodeGen(seeds[i]);
			int codeGen=hcg.hashCodeGen(s);
			bits.set(codeGen,true);
		}
		return true;		
	}
	//判断该字符串是否存在
	public boolean contain(String s) throws Exception{
		if(s.equals("")||(s==null)){	//输入的字符串需要控制
			throw new Exception("非法输入字符串");
		}
		boolean ret=true;
		for(int i=0;i<seeds.length;i++){
			HashCodeGen hcg=new HashCodeGen(seeds[i]);//生成seeds长度的对象
			ret=ret && bits.get(hcg.hashCodeGen(s));
			if(ret==false)break;
		}		
		return ret;
	}
	
	public static void main(String[] args) {
		BloomFilterNew bfn=new BloomFilterNew();

		bfn.add("www.baidu.com");
		try {
			System.out.println(bfn.contain("www.baidu.com.cn"));
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

}

class HashCodeGen{
	private int seed=0;
	public HashCodeGen(int seed){
		this.seed=seed;
	}
	//生成hash码
	public int hashCodeGen(String s){
		int hash=0;
		for(int i=0;i<s.length();i++){
			hash=hash*seed+s.charAt(i);
		}
		return (hash & 0x7ffffff);
	}
}
搞明白其原理,代码就相对好编写了。这里就hashCodeGen说明一下其来源:该哈希码的生成用的是BKDRhash,BKDRhash的c/c++代码如下:
unsigned int BKDRhash(char *s)
{
     unsigned int seed=131;//31 131 13131 131313 etc...
      unsigned int hash=0;
      while(*s)
       {
            hash=hash*seed+(*str++);   
        }
       return (hash & 0x7FFFFFFF);
}
         该哈希码生成算法用的相对很广泛,然后返回的是hash&(2^24-1)。这就是为什么在很多程序里面代码:c=2<<24; return hash & (c-1);了。这些代码是有其具体的原型。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值