需求背景:不安全的网页黑名单包含100亿个黑名单网页,每个网页的URL最多占用64B,现在想要实现一种网页过滤系统,可以根据网页的URL判断该网页是否在黑名单上,请设计该系统。
一般可能会首先想到利用HashSet的不可重复性,但是URL上亿的话所占内存空间会非常大。另外一种,就是采用BitMap这种数据结构。具体做法就是获取每一个URL的HashCode,然后根据它来插入到Btimap的对应位置。如果值是1,说明存在这个URL。
使用Bitmap以后,每一个Url只占了1个Bit,一亿个Url占约12MB。假设整个Bitmap的空隙比较多,额外空间占90%,总空间也不过是120MB,相比HashSet来说大大节省了内存空间。String的Hashcode方法虽然尽可能做到均匀分布,但仍然免不了会有冲突的情况。HashCode的冲突意味着什么呢?意味着不是黑名单的URL被误判为黑名单上的。
此时,引出布隆算法,它是一种以BitMap集合为基础的排重算法,应用场景有Url的排重,垃圾邮箱过滤等等。
1.把第一个URL按照三种Hash算法,分别生成三个不同的Hash值。
2.把第二个URL也按照三种Hash算法,分别生成三个不同的Hash值。
3.依次比较每一个Hash结果,只有当全部结果都相等时,才判定两个URL相同。
假设标准 HashCode 的重复几率是 0.01%,那么3个Hash结果同时重复的几率就是 0.01%^3=0.00000..1%。布隆算法会把每一个Hash结果都映射到同一个Bitmap上面。
1.创建一个空的Bitmap集合。
2.把第一个URL按照三种Hash算法,分别生成三个不同的Hash值。
3.分别判断5,17, 9 在Bitmap的对应位置是否为1,只要不同时为1,就认为该Url没有重复,于是把5,17,9的对应位置设置为1。
4.把第二个URL按照三种Hash算法,分别生成三个不同的Hash值。
5.分别判断10,12, 9 在Bitmap的对应位置是否为1,只要不同时为1,就认为该Url没有重复,于是把10,12, 9 的对应位置设置为1。
6.把第三个URL按照三种Hash算法,分别生成三个不同的Hash值。
7.分别判断4,16, 11 在Bitmap的对应位置是否为1,只要不同时为1,就认为该Url没有重复,于是把4,16, 11 的对应位置设置为1。
8.把第四个URL按照三种Hash算法,分别生成三个不同的Hash值。
9.分别判断5,17, 9 在Bitmap的对应位置是否为1。判断的结果是 5,17, 9 在Bitmap对应位置的值都是1,所以判定该Url是一个重复的Url。
但是,布隆算法也有一定几率会造成误判,如下:
1.URL按照三个Hash算法得到三个结果。
2.分别判断10,12, 17 在Bitmap的对应位置是否为1。判断的结果是 10,12, 17 在Bitmap对应位置的值都是1,所以判定该Url是一个重复的Url。
这种情况就是误判,可以看出布隆算法虽然极力降低了Hash冲突的几率,但是仍然有一定的误判率,为了减小误判率,可以让Bitmap的空间更大一些,单个Url所做的Hash更多一些(一般是8次),总之是在空间和准确率上做出取舍。
既然使用同一个Bitmap会出现误判,为什么不让每一种Hash算法的结果对应一个独立的Bitmap?那样的话,占用的空间也会相应增加几倍,反而不如用HashSet