布隆过滤器是什么?为什么会误判,又为什么不能直接删除元素?
下面是一段教学用的模拟面试。
🧑💻 面试官:布隆过滤器说一个用户存在,就能直接返回用户资料吗?
🙋♂️ 我:不能,它有误判。
🧑💻 面试官:为什么会误判?它又没有保存这个用户的完整记录。
🙋♂️ 我:不同元素可能把相同的位置设成一。
🧑💻 面试官:那用户删除以后,把这些位置改回零,不就清理了吗?
核心在「共享的位」:几个人可能留下同一处标记,你不能根据一处标记认定是谁,也不能替一个人擦掉所有标记。
面试速答(60 秒版)
标准布隆过滤器用一个位数组和多个哈希函数,判断一个元素是否可能已经加入集合。
加入元素时,把它映射到的多个位置设成一。查询时,只要有一个位置是零,就可以判定它没有加入;如果全部为一,只能说可能存在,因为这些位置也可能分别被其他元素设成一。
因此,在正确维护、没有随意清位的条件下,它允许假阳性,但不会把已经加入的元素误判为未加入。
标准布隆过滤器不能直接删除,是因为一个位可能被多个元素共享。删除时清零,会破坏其他元素的标记。需要删除能力,可以考虑计数布隆等不同结构,但要承担额外空间与维护约束。

知识点详解:从一条位数组看懂误判
添加元素,没有存下一张完整名单
假设位数组有八个位置,初始都是零。为了方便解释,我们用两个教学哈希映射:
A 对应位置 1、4,B 对应位置 4、6。加入它们以后,位置 1、4、6 都为一。
过滤器没有保存“位置 4 由 A 和 B 共同使用”这份完整关系,也没有把 A、B 的原始数据放进去。它只保留有限的位状态。
示意位置很小,只用于理解,不代表实际工程的参数。
误判为什么会发生?
假设从未加入的 C,恰好映射到位置 1、6。
查询 C 时,两个位置都是一,看起来满足条件。但位置 1 来自 A,位置 6 来自 B,它们拼出了一个不存在的 C。
这就是假阳性:本来没有加入,却判断为可能存在。它不是“返回了一条错误用户资料”,因为过滤器本来就没有保存用户资料。
如果另一个 D 对应 2、6,位置 2 是零,就能确定 D 没有加入。只要维护过程正确,已加入元素需要的所有位置都被设过一,不会因为标准查询而变成零。

为什么清零会带来假阴性?
现在删除 A,把位置 1、4 改回零。
问题是 B 也依赖位置 4。之后查询 B,看到位置 4 为零,就说 B 没有加入。但 B 其实仍在集合里。
原本没有假阴性的保证,被错误的删除方式破坏了。
计数布隆过滤器把位换成计数器,加入时增加计数,删除时减少。但删除必须对应真实的已加入元素,计数溢出等问题也要处理。它不是标准位数组直接清零就能得到的能力。

用在数据库前面,应该怎样理解“存在”?
假设我们把数据库中现有用户 ID 加入过滤器。请求到来时,过滤器判定不在集合,就可以提前拦下;判定可能在,仍然查询真正的数据源。
这里的保证还依赖同步。数据库新用户已经提交,过滤器尚未更新,那么过滤器可能说“没加入”。这不是数学结构的查询误判,而是应用维护的数据落后了。
所以接入之前要安排新数据更新、初始化覆盖和重建切换。不能把“结构理论上无假阴性”直接当成整个系统永不漏掉真实用户。
Redis 的 Bloom 文档解释了概率判断与容量、误判率的关系,具体部署能力还要核对服务版本。
容量与误判率怎么考虑?
数组越拥挤,越容易把一个新元素映射到的位置全部占满。目标误判率、预期元素数量和哈希次数需要一起配置。
工程上先估计要加入多少元素,明确能接受多少额外回源。之后观察实际容量和查询结果,不是一开始设一个很低的误判率,就认为永远不需要维护。
本篇只讲集合过滤,不重复缓存穿透、击穿、雪崩的整体治理方案。
面试官继续追问
数据删除后,不从过滤器删除,会有什么后果?
旧 ID 可能继续得到“可能存在”,多查一次真实数据源。它不会因此凭空返回已删除数据。要控制这种残留,可以重建并正确处理切换期间的更新。
能不能替代数据库唯一约束?
不能。假阳性让“可能存在”无法作为确定重复的结论,也不能解决并发写入的一致性。唯一性仍由可信存储边界保证。
误判率是一成不变的吗?
不是不看条件的常量。它依赖实际装入数量、结构参数以及扩展策略。要看你的实现是否支持扩展,也要监控实际数据规模。
面试速记卡
- 添加:多个哈希位置设为一,不保存完整元素记录。
- 查询:任一零说明未加入;全部一只能说明可能存在。
- 误判:不同元素的标记可能拼成一次假阳性。
- 删除:共享位不能直接清零,需使用合适变体或重建。
- 系统边界:过滤器更新落后仍会让真实数据被错误拦下。
公司面试真题
真题根据求职者公开面经整理,题意经过概括,非逐字原话或公司官方题库;本文为 Sunday 的独立解析。
美团 · Java后端 · 实习
布隆过滤器的原理、优点和缺点是什么?(题意整理)
4.21美团Java实习一二面面经 ↗
面试记录为 2020-04-21、2020-04-24;原帖编辑于 2020-11-14