聊聊Bloom Filter

聊聊Bloom Filter

bit数组
首先,比如我们有一个长度=2的byte数组,2个字节一共有16位,可以表示0-15的数字是否存在。比如我们要验证11是否出现过,那么我们先检查第11个位置是否为1,
如果为0,说明11没出现过,然后我们把第11位置为1,表示11已经出现过了。所以,BitSet基本只有两个操作,set(int value) 和 isHas(int value)
1.set(int value)
1.因为一个byte占8位,所以对于一个给定的value,我们先求出该value应该位于哪个Byte上,这很简单,int byteIndex = value / 8;
2.找到value在byte数组中的位置后,再就是在该字节中寻找表示value的bit位,我们知道,一个byte其实就是一个长为8的bit数组,那么value在该bit
数组中的位置也就很好算了,int bitIndex = value % 8;
3.最后我们把该bit位设置为1就可以了:byte[byteIndex] =
byte[byteIndex] | 1 << ( 7 - bitIndex)

				public void set(int value){
				  int byteIndex = value / 8;
				  int bitIndex = value % 8;
				  byte[byteIndex] = byte[byteIndex] | 1 << (7 - bitIndex)
				}

				public boolean isHash(int value){
				  int byteIndex = value / 8;
				  int bitIndex = value % 8;
				  return byte[byteIndex] & 1 << (7 - bitIndex) > 0
				}			
  1. BitSet的局限性
    1.当样本分布极度不均匀的时候,BitSet会造成很大空间上的浪费。 举个例子,比如你有10个数,分别是1、2、3、4、5、6、7、8、99999999999;那么你不得不用99999999999个bit位去实现你的BitSet,而这个BitSet的中间绝大
    多数位置都是0,并且永远不会用到,这显然是极度不划算的。
    2.当元素不是整型的时候,BitSet就不适用了。 想想看,你拿到的是一堆url,然后如果你想用BitSet做去重的话,先得把url转换成int型,在转换的过程中难免某些url会计算出相同的int值,于是BitSet的准
    确性就会降低。 解决方案
    1.第一种分布不均匀的情况可以通过hash函数,将元素都映射到一个区间范围内,减少大段区间闲置造成的浪费,这很简单,取模就好了,难的是取模之后的值保
    证不相同,即不发生hash冲突。
    2.第二种情况,把字符串映射成整数是必要的,那么唯一要做的就是保证我们的hash函数尽可能的减少hash冲突,一次不行我就多hash几次,hash还是容易碰撞,
    那我就扩大数组的范围,使hash值尽可能的均匀分布,减少hash冲突的概率。 布隆过滤器的原理 当一个元素被加入集合时,通过K个散列函数将这个元素映射成一个位数组中的K个点,把它们置为1。检索时,我们只要看看这些点是不是都是1就(大约)知道集合中有没
    有它了:如果这些点有任何一个0,则被检元素一定不在;如果都是1,则被检元素很可能在。这就是布隆过滤器的基本思想。 Bloom
    Filter跟单哈希函数Bit-Map不同之处在于:Bloom
    Filter使用了k个哈希函数,每个字符串跟k个bit对应。从而降低了冲突的概率。

     例子
     	比如你有10个Url,你完全可以创建一长度是100bit的数组,然后对url分别用5个不同的hash函数进行hash,得到5个hash后的值,这5个值尽可能的保证均匀分布
     	在100个bit的范围内。然后把5个hash值对应的bit位都置为1,判断一个url是否已经存在时,一次看5个bit位是否为1就可以了,如果有任何一个不为1,那么说明
     	这个url不存在。这里需要注意的是,如果对应的bit位值都为1,那么也不能肯定这个url一定存在 			例如针对值 “baidu”
    

    和三个不同的哈希函数分别生成了哈希值 1、4、7 我们现在再存一个值 “tencent”,如果哈希函数返回 3、4、8
    值得注意的是,4 这个 bit 位由于两个值的哈希函数都返回了这个 bit 位,因此它被覆盖了 而当我们需要查询
    “baidu” 这个值是否存在的话,那么哈希函数必然会返回 1、4、7,然后我们检查发现这三个 bit 位上的值均为 1,那么我们可以说
    “baidu” 存在了么?答案是不可以,只能是 “baidu” 这个值可能存在。 BloomFilter的核心思想有两点:
    1.多个hash,增大随机性,减少hash碰撞的概率
    2.扩大数组范围,使hash值均匀分布,进一步减少hash碰撞的概率。

    Bloom Filter的缺点 bloom filter之所以能做到在时间和空间上的效率比较高,是因为牺牲了判断的准确率、删除的便利性
    存在误判,可能要查到的元素并没有在容器中,但是hash之后得到的k个位置上值都是1。如果bloom
    filter中存储的是黑名单,那么可以通过建立一个白名单来存储可能会 误判的元素。
    删除困难。一个放入容器的元素映射到bit数组的k个位置上是1,删除的时候不能简单的直接置为0,可能会影响其他元素的判断。可以采用Counting
    Bloom Filter

    Bloom Filter 实现 在使用bloom filter时,绕不过的两点是预估数据量n以及期望的误判率fpp,
    在实现bloom filter时,绕不过的两点就是hash函数的选取以及bit数组的大小。
    对于一个确定的场景,我们预估要存的数据量为n,期望的误判率为fpp,然后需要计算我们需要的Bit数组的大小m,以及hash函数的个数k,并选择hash函数
    1.Bit数组大小选择 根据预估数据量n以及误判率fpp,bit数组大小的m的计算方式:m= - n In(fpp)/ (In2)^2
    2.哈希函数选择 由预估数据量n以及bit数组长度m,可以得到一个hash函数的个数k:k=n/m * In2 哈希函数的选择对性能的影响应该是很大的,一个好的哈希函数要能近似等概率的将字符串映射到各个Bit。选择k个不同的哈希函数比较麻烦,一种简单的方法
    是选择一个哈希函数,然后送入k个不同的参数。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值