布隆过滤器

178 阅读3分钟

1.定义

BloomFilter 是由一个固定大小的二进制向量或者位图(bitmap)和一系列映射函数组成的。用来解决一个元素是否存在一个集合里面(一般是很大的集合里),是一种算法。

2.场景

  1. 用户名是否注册过
  2. 缓存穿透:缓存和数据库中都没有的数据,导致每次都要重新查询,而用户恶意不断发起请求,导致一直查询数据库导致资源浪费。
  3. 网页爬虫判断是否爬过URL的判断
  4. 反垃圾邮件,从数十亿个垃圾邮件列表中判断某邮箱是否垃圾邮箱;

2.1传统的解决方案:

  • 1.使用数据库存储用户数据,没有都查询用户是否在数据库里。如果超过1亿条,速度会超慢。
  • 3.4. 如果使用Set对象存储对应的查询数据如 url或邮件地址,当数据量超过几个G,内存就会被溢出。

2.2使用布隆过滤器的方案:

每次写入用户数据都更新一下 这个长长的二进制的位图,当有请求的时候,先在这个二进制位图查询。如果有才进行数据库查询。

3.原理

一个集合C里面的有n元素,把n个元素通过k个哈希函数,分别转化映射到二进制向量里面。这些位置都标识为1,当要校验某个x元素是否在集合里,只需要把x元素进行同样的哈希函数转化,查看标识1的位置 与二进制向量表是否匹配,如果相同位置同时也是1 则存在。

4.例子🌰

假设有集合{'a','f','h'},需要检查'h' 是否在集合中

  1. 刚开始二进制向量 所有位置都是0 image.png

  2. 'a'经过hash1哈希之后,在第二个位置标识为1 image.png

  3. 'f'经过hash1哈希之后,在第4个位置标识为1 image.png

  4. 'h'经过hash1哈希之后,在第6个位置标识为1 image.png

这时候{'a','f','h'}映射的二进制向量已经映射好,校验'h'是否存在,只需要执行hash1('h'), 然后检查对应的位置是否已经标识为1即可。是1则存在,是0则不存在。

image.png

5.总结

2.2.1优点

通过一个很长的二进制向量就能描述各种复杂的数据关系,空间复杂度极低。查询时间也比较快。

2.2.2特点

有则有可能有误差,有哈希碰撞的可能,但是没有就肯定没有。哈希函数可以有效均匀的分布在整个位图里,减少哈希碰撞。

2.2.2缺点

由于有可能有误差,有哈希碰撞的可能,导致结果不精确。删除也不方便。

优化方案:可以增加hash哈希函数的数量与位图的长度。

6.推荐第三方库

Google的Guava类,Twitter的 Algebird 类库,Redis自带的Bitmaps二次开发。