1.什么是布隆过滤器

本质上布隆过滤器是一种数据结构,比较巧妙的概率型数据结构(probabilistic data structure),特点是高效地插入和查询,可以用来告诉你 “某样东西一定不存在或者可能存在”。

相比于传统的 List、Set、Map 等数据结构,它更高效、占用空间更少,但是缺点是其返回的结果是概率性的,而不是确切的。

2.实现原理

HashMap 的问题

讲述布隆过滤器的原理之前,我们先思考一下,通常你判断某个元素是否存在用的是什么?应该蛮多人回答 HashMap 吧,确实可以将值映射到 HashMap 的 Key,然后可以在 O(1) 的时间复杂度内返回结果,效率奇高。但是 HashMap 的实现也有缺点,例如存储容量占比高,考虑到负载因子的存在,通常空间是不能被用满的,而一旦你的值很多例如上亿的时候,那 HashMap 占据的内存大小就变得很可观了。

还比如说你的数据集存储在远程服务器上,本地服务接受输入,而数据集非常大不可能一次性读进内存构建 HashMap 的时候,也会存在问题。

3.布隆过滤器数据结构

布隆过滤器是一个 bit 向量或者说 bit 数组,长这样:

image

如果我们要映射一个值到布隆过滤器中,我们需要使用多个不同的哈希函数生成多个哈希值,并对每个生成的哈希值指向的 bit 位置 1,例如针对值 “baidu” 和三个不同的哈希函数分别生成了哈希值 1、4、7,则上图转变为:

image

Ok,我们现在再存一个值 “tencent”,如果哈希函数返回 3、4、8 的话,图继续变为:

image

值得注意的是,4 这个 bit 位由于两个值的哈希函数都返回了这个 bit 位,因此它被覆盖了。现在我们如果想查询 “dianping” 这个值是否存在,哈希函数返回了 1、5、8三个值,结果我们发现 5 这个 bit 位上的值为 0,说明没有任何一个值映射到这个 bit 位上,因此我们可以很确定地说 “dianping” 这个值不存在。而当我们需要查询 “baidu” 这个值是否存在的话,那么哈希函数必然会返回 1、4、7,然后我们检查发现这三个 bit 位上的值均为 1,那么我们可以说 “baidu” 存在了么?答案是不可以,只能是 “baidu” 这个值可能存在。

这是为什么呢?答案跟简单,因为随着增加的值越来越多,被置为 1 的 bit 位也会越来越多,这样某个值 “taobao” 即使没有被存储过,但是万一哈希函数返回的三个 bit 位都被其他值置位了 1 ,那么程序还是会判断 “taobao” 这个值存在。

4.支持删除么

传统的布隆过滤器并不支持删除操作。但是名为 Counting Bloom filter 的变种可以用来测试元素计数个数是否绝对小于某个阈值,它支持元素删除。可以参考文章 Counting Bloom Filter 的原理和实现

5.如何选择哈希函数个数和布隆过滤器长度

很显然,过小的布隆过滤器很快所有的 bit 位均为 1,那么查询任何值都会返回“可能存在”,起不到过滤的目的了。布隆过滤器的长度会直接影响误报率,布隆过滤器越长其误报率越小。

另外,哈希函数的个数也需要权衡,个数越多则布隆过滤器 bit 位置位 1 的速度越快,且布隆过滤器的效率越低;但是如果太少的话,那我们的误报率会变高。

image

如何选择适合业务的 k 和 m 值呢,这里直接贴一个公式:

image.png

k 为哈希函数个数,m 为布隆过滤器长度,n 为插入的元素个数,p 为误报率。
至于如何推导这个公式,我在知乎发布的文章有涉及,感兴趣可以看看,不感兴趣的话记住上面这个公式就行了。

最佳实践

常见的适用常见有,利用布隆过滤器减少磁盘 IO 或者网络请求,因为一旦一个值必定不存在的话,我们可以不用进行后续昂贵的查询请求。

另外,既然你使用布隆过滤器来加速查找和判断是否存在,那么性能很低的哈希函数不是个好选择,推荐 MurmurHash、Fnv 这些。

大Value拆分

Redis 因其支持 setbit 和 getbit 操作,且纯内存性能高等特点,因此天然就可以作为布隆过滤器来使用。但是布隆过滤器的不当使用极易产生大 Value,增加 Redis 阻塞风险,因此生成环境中建议对体积庞大的布隆过滤器进行拆分。

拆分的形式方法多种多样,但是本质是不要将 Hash(Key) 之后的请求分散在多个节点的多个小 bitmap 上,而是应该拆分成多个小 bitmap 之后,对一个 Key 的所有哈希函数都落在这一个小 bitmap 上。

6.使用场景

1.网页爬虫对URL的去重,避免爬去相同的URL地址。

2.垃圾邮件过滤,从数十亿个垃圾邮件列表中判断某邮箱是否是杀垃圾邮箱。

3.解决数据库缓存击穿,黑客攻击服务器时,会构建大量不存在于缓存中的key向服务器发起请求,在数据量足够大的时候,频繁的数据库查询会导致挂机。

4.秒杀系统,查看用户是否重复购买

7.实际场景:

背景:现在有个100亿个黑名单网页数据,每个网页的URL占用64字节。现在想要实现一种网页过滤系统,可以根据网页的URL判断该网站是否在黑名单上,请设计该系统。

需求:可以允许有0.01%以下的判断失误率,并且使用的总空间不要超过200G。

这里一共有4个常量:

100亿条黑名单数据,每条数据占64个字节,万分之一的失误率,总空间不要超过200G。

如果不考虑不拢过滤器,那么这里存储100亿条数据就需要 100亿 * 64字节 = 596G 显然超过300G

解题 在满足有 100亿条数据 并且允许 万分之一的失误率 的布隆过滤器需要多大的bit数组呢?

  • 设bit数组大小为m,样本数量为n,失误率为p。
  • 由题可知 n = 100亿,p = 0.01%

布隆过滤器的大小m公式

求得 m = 19.19n,向上取整为 20n。所以2000亿bit,约为186G。

算完m,我们顺便来算下m,n已知,这时满足最小误差的k是几个。

哈希函数的个数k公式

求得 k = 14,即需要14个哈希函数。

通过通过 m = 20n, k = 14我们再来算下真实的失误率。

布隆过滤器真实失误率p公式

求得 p = 0.006%,即布隆过滤器的真实失误率为0.006%。

通过布隆过滤器公式也可以看出:

单个数据的大小不影响布隆过滤器大小,因为样本会通过哈希函数得到输出值。

就好比上面的 每个网页的URL占用64字节 这个数据大小 跟布隆过滤器大小没啥关系。

本文到这里也就结束了,喜欢的记得点一波关注。

参考链接:

https://www.jianshu.com/p/2104d11ee0a2

https://www.cnblogs.com/qdhxhz/p/11237246.html

面试官问到布隆过滤器,还好我阅读过这篇博客相关推荐

  1. 漫画:以后有面试官问你快速排序,你就干脆把我这篇熬夜写的文章扔给他!

    这篇文章,以对话的方式,详细着讲解了快速排序以及排序排序的一些优化. 一禅:归并排序是一种基于分治思想的排序,处理的时候可以采取递归的方式来处理子问题.我弄个例子吧,好理解点.例如对于这个数组arr[ ...

  2. redis怎么修改_面试官问我Redis事务,还问我有哪些实现方式

    ❝ 「第12期」 距离大叔的80期小目标还有68期,今天大叔要跟大家分享的内容是 -- Reids中的事务.同样,这也是redis中重要指数为四颗星的必备基础知识点.下面一起来了解一下吧. ❞ 相信大 ...

  3. 面试官问你斐波那契数列的时候不要高兴得太早 搞懂C语言函数指针 搜索引擎还可以这么玩? 那些相见恨晚的搜索技巧...

    面试官问你斐波那契数列的时候不要高兴得太早 前言 假如面试官让你编写求斐波那契数列的代码时,是不是心中暗喜?不就是递归么,早就会了.如果真这么想,那就危险了. 递归求斐波那契数列 递归,在数学与计算机 ...

  4. 面试官问你想找什么工作_找工作时如何面试面试官

    面试官问你想找什么工作 在技​​术面试中要问的十二个问题 (Twelve questions to ask at tech interviews) I've just come off six wee ...

  5. 面试官问:select......for update会锁表还是锁行?

    欢迎关注方志朋的博客,回复"666"获面试宝典 select查询语句是不会加锁的,但是select .......for update除了有查询的作用外,还会加锁呢,而且它是悲观锁 ...

  6. 面试官问:数据库 delete 表数据,磁盘空间还是被一直占用,为什么?

    以下文章来源方志朋的博客,回复"666"获面试宝典 最近有个上位机获取下位机上报数据的项目,由于上报频率比较频繁且数据量大,导致数据增长过快,磁盘占用多. 为了节约成本,定期进行数 ...

  7. 面试官问:Kafka 会不会丢消息?怎么处理的?

    点击上方蓝色"方志朋",选择"设为星标" 回复"666"获取独家整理的学习资料! Kafka存在丢消息的问题,消息丢失会发生在Broker, ...

  8. 面试官问我:一个 TCP 连接可以发多少个 HTTP 请求?我竟然回答不上来...

    点击上方"方志朋",选择"设为星标" 做积极的人,而不是积极废人 作者 | 松若章 来源 | https://zhuanlan.zhihu.com/p/6142 ...

  9. 后处理程序文件大小的变量_【每日一题】(17题)面试官问:JS中事件流,事件处理程序,事件对象的理解?...

    关注「松宝写代码」,精选好文,每日一题 作者:saucxs | songEagle 2020,实「鼠」不易 2021,「牛」转乾坤 风劲潮涌当扬帆,任重道远须奋蹄! 一.前言 2020.12.23 立 ...

最新文章

  1. Kali Linux安装谷歌输入法
  2. Citus数据分片分布研究(二 副本与故障)
  3. 洛谷 P3119 [USACO15JAN]草鉴定Grass Cownoisseur (SCC缩点,SPFA最长路,枚举反边)
  4. java生产者消费者问题代码分析
  5. 数据结构与算法——贪心算法
  6. 辐射避难所服务器维护,《辐射:避难所Online》6月2日停服维护更新公告
  7. Redhat Enterprise Linux 5系统引导故障解决方法
  8. c语言图书信息管理系实验心得,C语言图书信息管理系统实验报告.doc
  9. stay here forever中文歌词
  10. 最小和最大优先循环队列(C++)
  11. SQL server 中的dbo、guest
  12. CF 285D 285E
  13. 电脑如何录屏?分享4个屏幕录制的好方法,建议收藏
  14. HTML5之Worker用法
  15. java根据内容生成二维码
  16. keras-文本图片文字识别
  17. js实现简单打地鼠小游戏
  18. Hadoop安装(二) --- Hadoop安装
  19. 三星android智能手图片机,掌中投影智能机 三星GALAXY Beam2图赏
  20. 让五个数都不相等的程序c语言,C语言程序设计课件第05讲.ppt

热门文章

  1. 数据开发工程师,你需要哪些技能?
  2. 好用的配音软件有什么?推荐几款实用配音软件
  3. yolov5 onnx 前后处理+运行推理(暂记)
  4. 学计算机装机,学习电脑装机全过程 组装台式机图解教程(4)
  5. 从菜鸟到Android资深工程师的进阶之路
  6. 在b/s架构下实现与读卡器(射频读写机)通讯
  7. SpringBoot单元测试:MockMvc的自动配置
  8. 算法设计与分析----二分搜索(递归)
  9. 【 js基础 Day2】js的流程控制:分支语句,循环.顺序结构
  10. Delphi MSComm 控件方法