布隆过滤器:用少量内存判断一个元素是否可能存在

如果一个接口被大量查询不存在的数据,比如用户不断请求不存在的商品 ID、缓存里没有的用户 ID,系统很容易被拖进一个尴尬局面:缓存没命中,请求继续打到数据库;数据库查不到,下一次同样的请求又会重复发生。 这类问题的关键不是“如何更快地查到数据”,而是先回答一个更便宜的问题:这个东西是不是一定不存在? 布隆过滤器解决的正是这个问题。它不能像哈希集合那样给出完全精确的答案,但它能用很少的内存,在极快的时间内告诉你: 如果结果是“不存在”,那它一定不存在。 如果结果是“存在”,那它只是可能存在。 这个“可能”就是布隆过滤器最重要的取舍。它用少量误判,换来了很高的空间效率。 先从一个普通集合说起 假设我们要记录 1 亿个已经注册过的用户 ID,最直接的做法是把这些 ID 放进一个集合: registered_users = set() registered_users.add("user:10086") if "user:10086" in registered_users: print("exists") 这个方案很好理解,也很精确。但问题是:集合为了支持快速查询,通常不只存储原始元素,还要维护哈希表、桶、指针、扩容状态等额外结构。数据量一大,内存会明显上去。 如果我们的目标只是提前过滤掉明显不存在的请求,真的需要保存完整的字符串吗? 布隆过滤器的答案是:不需要。它只保存一些 bit。 布隆过滤器的直觉 可以把布隆过滤器想成一个很大的位图,也就是一串只包含 0 和 1 的数组: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 普通位图通常要求元素能直接映射成整数位置,比如数字 13 就对应第 13 个 bit。但现实里的元素可能是字符串、URL、邮箱、订单号,不一定能直接当数组下标。 布隆过滤器在中间加了一层哈希函数。 对于一个元素,它不用一个位置表示,而是用多个哈希函数算出多个位置: element = "user:10086" hash1(element) -> 3 hash2(element) -> 9 hash3(element) -> 14 插入这个元素时,就把这些位置都置为 1: ...

May 21, 2026 · 5 min · Icyyan

位图 Bitmap:用一个 bit 记录海量状态

如果让你记录“今天哪些用户登录过”,最直接的想法可能是放进一个集合: logged_in_users = set() logged_in_users.add(10086) 这样当然能用。但如果用户 ID 范围很大、查询又特别频繁,集合会带来不少额外开销。有没有一种更省空间的办法? 位图,也就是 Bitmap,解决的就是这类问题:用一个 bit 表示一个状态。这个状态通常只有两种结果:有或没有、是或否、出现过或没出现过。 位图到底是什么 先从一个字节说起。 一个字节有 8 个 bit: 0 0 0 0 0 0 0 0 每个 bit 都可以表示一个编号是否存在。比如我们用 bit 记录数字是否出现过: bit 0 表示数字 0 是否出现 bit 1 表示数字 1 是否出现 bit 2 表示数字 2 是否出现 ... bit 7 表示数字 7 是否出现 如果数字 3 出现过,就把第 3 个 bit 置为 1: 0 0 0 0 1 0 0 0 ↑ 数字 3 当编号超过 7 时,就放到下一个字节里。比如数字 13: ...

May 18, 2026 · 3 min · Icyyan