题目描述

一个网站有 100 亿 url 存在一个黑名单中,每条 url 平均 64 字节。这个黑名单要怎么存?若此时随便输入一个 url,你如何快速判断该 url 是否在这个黑名单中?

题目解析

这是一道经常在面试中出现的算法题。凭借着题目极其容易描述,不考虑细节的话,此题就是一个简单的查找问题。对于查找问题而言,使用散列表来处理往往是一种效率比较高的方案。但是,如果你在面试中回答使用散列表,接下来面试官肯定会问你:然后呢?如果你不能回答个所以然,面试官就会面无表情的通知你:今天的面试到此结束,我们会在一周内给你答复。

为什么不能用散列表?
       100 亿是一个很大的数量级,这里每条 url 平均 64 字节,全部存储的话需要 640G 的内存空间。又因为使用了散列表这种数据结构,而散列表是会出现散列冲突的。为了让散列表维持较小的装载因子,避免出现过多的散列冲突,需要使用链表法来处理,这里就要存储链表指针。因此最后的内存空间可能超过 1000G 了。
只是存储个 url 就需要 1000G 的空间,老板肯定不能忍!

位图(BitMap)
       这个时候就需要拓展一下思路。首先,先来考虑一个类似但更简单的问题:现在有一个非常庞大的数据,比如有 1 千万个整数,并且整数的范围在 1 到 1 亿之间。那么如何快速查找某个整数是否在这 1 千万个整数中呢?
需要判断该数是否存在,也就是说这个数存在两种状态:存在( True )或者不存在(False)。

因此这里可以使用一个存储了状态的数组来处理。这个数组特点是大小为 1 亿,并且数据类型为布尔类型( True 或者 False )。然后将这 1 千万个整数作为数组下标,将对应的数组值设置成 True,比如,整数 233 对应下标为 233 的数组值设置为 True,也就是 array[ 233 ] = True。

这种操作就是位图法:就是用每一位来存放某种状态,适用于大规模数据,但数据状态又不是很多的情况。
另外,位图法有一个优势就是空间不随集合内元素个数的增加而增加。它的存储空间计算方式是找到所有元素里面最大的元素(假设为 N ),因此所占空间为:

       因此,当 N 为 1 亿的时候需要 12MB 的存储空间。当 N 为 10 亿的时候需要 120MB 的存储空间了。当 N 的数量大到一定量级的时候,比如 N 为 2^64 这个海量级别的时候,需要消耗 2048PB 的存储空间,这个量级的BitMap,目前硬件上是支持不了的。
也就是说:位图法的所占空间随集合内最大元素的增大而增大。这就会带来一个问题,如果查找的元素数量少但其中某个元素的值很大,比如数字范围是 1 到 1000 亿,那消耗的空间不容乐观。

这个就是位图的一个不容忽视的缺点:空间复杂度随集合内最大元素增大而线性增大。对于开头的题目而言,使用位图进行处理,实际上内存消耗也是不少的。
       因此,出于性能和内存占用的考虑,在这里使用布隆过滤器才是最好的解决方案:布隆过滤器是对位图的一种改进。

布隆过滤器

布隆过滤器(英语:Bloom Filter)是 1970 年由 Burton Bloom 提出的。它实际上是一个很长的二进制矢量和一系列随机映射函数它可以用来判断一个元素是否在一个集合中。它的优势是只需要占用很小的内存空间以及有着高效的查询效率。对于布隆过滤器而言,它的本质是一个位数组:位数组就是数组的每个元素都只占用 1 bit ,并且每个元素只能是 0 或者 1。

一开始,布隆过滤器的位数组所有位都初始化为 0。比如,数组长度为 m ,那么将长度为 m 个位数组的所有的位都初始化为 0。

      在数组中的每一位都是二进制位。
      布隆过滤器除了一个位数组,还有 K 个哈希函数。当一个元素加入布隆过滤器中的时候,会进行如下操作:
            •使用 K 个哈希函数对元素值进行 K 次计算,得到 K 个哈希值。
            •根据得到的哈希值,在位数组中把对应下标的值置为 1。

      举个例子,假设布隆过滤器有 3 个哈希函数:f1, f2, f3 和一个位数组 arr。现在要把 2333 插入布隆过滤器中:
            •对值进行三次哈希计算,得到三个值 n1, n2, n3。
            •把位数组中三个元素 arr[n1], arr[n2], arr[3] 都置为 1。

当要判断一个值是否在布隆过滤器中,对元素进行三次哈希计算,得到值之后判断位数组中的每个元素是否都为 1,如果值都为 1,那么说明这个值在布隆过滤器中,如果存在一个值不为 1,说明该元素不在布隆过滤器中。

      很明显,数组的容量即使再大,也是有限的。那么随着元素的增加,插入的元素就会越多,位数组中被置为 1 的位置因此也越多,这就会造成一种情况:当一个不在布隆过滤器中的元素,经过同样规则的哈希计算之后,得到的值在位数组中查询,有可能这些位置因为之前其它元素的操作先被置为 1 了。

如图 1 所示,假设某个元素通过映射对应下标为4,5,6这3个点。虽然这 3 个点都为 1 ,但是很明显这 3 个点是不同元素经过哈希得到的位置,因此这种情况说明这个元素虽然不在集合中,也可能对应的都是 1,这是误判率存在的原因。
      所以,有可能一个不存在布隆过滤器中的会被误判成在布隆过滤器中。
      这就是布隆过滤器的一个缺陷:存在误判。

但是,如果布隆过滤器判断某个元素不在布隆过滤器中,那么这个值就一定不在布隆过滤器中。总结就是:
            •布隆过滤器说某个元素在,可能会被误判
            •布隆过滤器说某个元素不在,那么一定不在
            用英文说就是:False is always false. True is maybe true。

误判率
      布隆过滤器可以插入元素,但不可以删除已有元素。其中的元素越多,false positive rate(误报率)越大,但是false negative (漏报)是不可能的。

补救方法
布隆过滤器存在一定的误识别率。常见的补救办法是在建立白名单,存储那些可能被误判的元素。 比如你苦等的offer 可能被系统丢在邮件垃圾箱(白名单)了。

使用场景
      布隆过滤器的最大的用处就是,能够迅速判断一个元素是否在一个集合中。因此它有如下三个使用场景:
            •网页爬虫对 URL 的去重,避免爬取相同的 URL 地址
            •进行垃圾邮件过滤:反垃圾邮件,从数十亿个垃圾邮件列表中判断某邮箱是否垃圾邮箱(同理,垃圾短信)
            •有的黑客为了让服务宕机,他们会构建大量不存在于缓存中的 key 向服务器发起请求,在数据量足够大的情况下,频繁的数据库查询可能导致 DB 挂掉。布隆过滤器很好的解决了缓存击穿的问题。

回到问题
      回到一开始的问题,如果面试官问你如何在海量数据中快速判断该 url 是否在黑名单中时,你应该回答使用布隆过滤器进行处理,然后说明一下为什么不使用 hash 和 bitmap,以及布隆过滤器的基本原理,最后你再谈谈它的使用场景那就更好了。

常见面试题之布隆过滤器的使用案例(海量数据)相关推荐

  1. Redis常见面试题总结

    Redis常见面试题 持久化方式有哪些?有什么区别? redis持久化方案分为RDB和AOF两种. RDB RDB持久化可以手动执行也可以根据配置定期执行,它的作用是将某个时间点上的数据库状态保存到R ...

  2. 算法面试必备-----数据分析常见面试题

    算法面试必备-----数据分析常见面试题 算法面试必备-----数据分析常见面试题 1.统计学问题 问题:贝叶斯公式复述并解释应用场景 问题:朴素贝叶斯的理解 问题:参数估计 问题:极大似然估计 问题 ...

  3. 「java工程师」常见面试题及其答案(持续更新)

    「高级java工程师」常见面试题及其答案: 「高级java工程师」常见面试题及其答案(持续更新)_好人老李的博客-CSDN博客 目录 java基础 面向对象与面向过程的区别? JRE.JDK.JVM的 ...

  4. 面试1:Java、微服务、架构常见面试题(持续更新中)

    Java.微服务.架构常见面试题(持续更新中) 文章目录 Java.微服务.架构常见面试题(持续更新中) ==**Java**== 1.Java概述 (1)JVM.JRE和JDK (2)Java特点 ...

  5. 300+ Java常见面试题总结【JavaPub版】

    点赞再看,养成习惯 答案解析见文末 我是JavaPub,专注于面试.副业,技术人的成长记录. 这份[Java常见面试题总结]我想准备很久了,前面做面试官,后来自己也面了很多一线二线互联网公司,希望通过 ...

  6. Redis常见面试题(缓存击穿、穿透、雪崩)

    Redis常见面试题(缓存击穿.穿透.雪崩) 击穿 场景: 一般由于redis中的数据到期,同时并发用户特别多,此时大量请求压到数据库上. 解决思路: 根据redis是单进程单实例的特性,当高流量进入 ...

  7. 面经 | Redis常见面试题

    Redis 常见面试题 目录结构: 文章目录 Redis 常见面试题 数据结构 String 哈希 List Set Zset 有序集合 持久化机制 RDB快照 AOF 混合使用 Redis为什么要线 ...

  8. Java常见面试题 Java面试必看 (二)

    Java常见面试题 Java面试必看 (一) 十一.Spring Boot/Spring Cloud 104.什么是 spring boot? Spring Boot 是由 Pivotal 团队提供的 ...

  9. vue 离开页面事件_【必看】58 道 Vue 常见面试题集锦,涵盖入门到精通,自测 Vue 掌握程度...

    △ 是新朋友吗?记得先点web前端学习圈关注我哦- 1.vue优点? 答: 轻量级框架:只关注视图层,是一个构建数据的视图集合,大小只有几十 kb : 简单易学:国人开发,中文文档,不存在语言障碍 , ...

最新文章

  1. R语言cut函数实现数据分箱及因子化实战
  2. 直播预告|灵动MM32 MCU助力全国大学生智能汽车竞赛——基础培训第二讲
  3. 一步步打造漂亮的新闻列表(无刷新分页、内容预览)(4)
  4. Oracle 触发器使用实例
  5. win10系统 ubuntu子系统 进行ndk编译笔记
  6. mysql -s 参数_mysqldump 的常用参数。
  7. 敏捷大观园 - 视频分享第6弹!
  8. java学习(112):simpledateformat进行格式化
  9. oracle10g生成awr报告,awr报告生成位置.docx
  10. 安装chrome_Chrome 离线安装包下载
  11. 好用的import: Vite的Glob 导入
  12. 素数在c语言中怎么表示,请问素数怎么样表示
  13. 协调器周期性以广播的形式向终端节点发送数据(每隔5s广播一次),终端节点接收数据后,使开发板上的LED灯状态翻转, 同时向协调器发送字符串“EndDevice1 received!”(按组网节点数编号
  14. 使用Jimi处理图像
  15. 热电阻PT100转4-20mA温度信号转换器,变送分配器
  16. php的样式怎么设置字体大小,css中如何改变字体大小
  17. Java实现蓝桥杯分金币
  18. STM32F10xxx启动模式分析 – 梦想照旧
  19. C 语言 结构体_finddata_t _findfirst, _findnext, _findclose 函数讲解
  20. android 手机 拍 全景 java_Android开发如何调用相机的全景拍摄功能

热门文章

  1. 华为交换机端口配置删除_华为交换机配置_华为交换机怎么清除端口下所有配置?...
  2. 用户管理后台管理项目总结
  3. 上拉电阻的作用原理_单片机P0口以及上拉电阻
  4. linux startx无效_startx命令_Linux startx 命令用法详解:用来启动X Window
  5. 实例学习Ansible系列:颜色与设定
  6. 程序员面试中一面、二面、三面有什么区别?
  7. SONY PS3 摄像头windows驱动CL-Eye-Driver-5.3.0.0341
  8. ps怎么将图片制作成ico图标? ps制作ico图标的教程
  9. 支付回答——如何理解借记和贷记
  10. jqGrid----下拉列表框下拉联动,dataEvents回调函数。