布隆过滤器用于检测某个值是否已经存在,应用场景很广泛,比如在Hbase中可以在ROW(行级)或ROWCOL(行+列)两个级别配置是否开启布隆过滤器。其作用是反向检测某个数据是否存在于某个数据块,检测结果确定为不存在或不确定。只有对不存在的判断是确切的,因为BloomFilter对存在的判断具有一定的误判率。BloomFilter将待处理的数据经过N个hash函数映射到一个Bit数组的N个值,hash值则为Bit数组的索引项。经过处理,如果一个值已经存在,那么必定满足Bit[Hi] == true 其中i为1到N,Hi为使用第i个hash函数得到的hash值,Bit为位数组。
在实现一般的网络爬虫的时候也可以考虑添加BloomFilter功能来过滤已爬取的网页。下面的代码为使用Scala util包下的MurmurHash3实现的BloomFilter。
import java.util.BitSet
import scala.util.hashing.MurmurHash3
/**
* 实现简单的bloomfilter过滤器,用来判断某个url是否已经被爬取
*/
object BloomFilter {
/** 1 << 24位长度的位图数组,存放hash值*/
val bitSetSize = 1 << 32
/**位数组*/
val bitSet = new BitSet(bitSetSize)
/**传入murmurhash中的seed的范围*/
val seedNums = 6
/**
* 根据MurmurHash3计算哈希值,设置BitSet的值
* @param str
*/
def hashValue(str: String): Unit = {
if(str != null && !str.isEmpty)
for(i <- 1 to seedNums) bitSet.set(Math.abs(MurmurHash3.stringHash(str, i)) % bitSetSize, true)
else
println("传入的字符串位空")
}
/**
* 判断一个字符串是否存在于bloomFilter
* @param str
* @return
*/
def exists(str: String): Boolean = {
def existsRecur(str: String, seed: Int): Boolean = {
if(str == null || str.isEmpty) false
else if(seed > seedNums) true
else if(!bitSet.get(Math.abs(MurmurHash3.stringHash(str, seed)) % bitSetSize)) false
else existsRecur(str, seed + 1)
}
if(str == null || str.isEmpty)
false
else
existsRecur(str, 1)
}
def main(args: Array[String]) = {
val s1 = "www.baidu.com"
val s2 = "www.jd.com"
val s3 = "www.taobao.com"
val s4 = "http://kafka.apache.org"
BloomFilter.hashValue(s1)
BloomFilter.hashValue(s2)
BloomFilter.hashValue(s3)
BloomFilter.hashValue(s4)
println(BloomFilter.exists(s1))
println(BloomFilter.exists(s2))
println(BloomFilter.exists(s3))
println(BloomFilter.exists(s4))
}
}