news 2026/4/16 7:23:45

布隆过滤器进阶:布谷鸟过滤器 (Cuckoo Filter) 是如何支持“删除”操作的?

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
布隆过滤器进阶:布谷鸟过滤器 (Cuckoo Filter) 是如何支持“删除”操作的?

标签:#Algorithm #BloomFilter #CuckooFilter #DataStructure #SystemDesign


🚫 前言:布隆过滤器的“死穴”

布隆过滤器的原理是将一个元素通过 个哈希函数映射到位数组的 个点上。

为什么不能删?
假设元素 A 映射到了位置[1, 5, 8],元素 B 映射到了[2, 5, 9]
它们共享了位置5
如果你想删除 A,把1, 5, 8都置为 0,那么 B 在查询时,发现位置5是 0,就会被误判为“不存在”。
这破坏了过滤器的正确性(False Negative 是绝对不允许的)。


🥚 一、 布谷鸟哈希 (Cuckoo Hashing) 的基本思想

布谷鸟过滤器不再存 Bit,而是存储元素的指纹 (Fingerprint)(比如 8-12 bit 的哈希值)。
它有两个哈希桶(Bucket),每个桶有 个位置(Slot)。

“鸠占鹊巢”的插入逻辑:

  1. 计算元素 的两个候选桶索引: 和 。
  2. 如果 有空位,放进去。
  3. 如果 满了,试试 。
  4. 如果 也满了?踢人!
    随便把 或 里现有的一个指纹踢出来,把新指纹放进去。
    被踢出来的那个倒霉蛋,再去寻找它自己的另一个备用位置。如果备用位置也满了,继续踢……
    直到所有鸟都有巢,或者达到最大踢出次数(扩容)。

交互流程图 (Mermaid):

计算位置

计算位置

有空位

已满

有空位

已满 (冲突)

旧元素 Y

插入元素 X

位置 1

位置 2

插入成功

尝试位置 2

插入成功

👿 踢出旧元素 Y

插入 X

计算 Y 的另一个位置

重新插入 Y


🪄 二、 核心魔法:对偶位置计算 (XOR)

在标准的 Cuckoo Hash Map 中,我们需要存储完整的 Key,才能在被踢出时重新计算它的另一个哈希位置。
但在过滤器中,为了省空间,我们只存了指纹(Fingerprint)。由于指纹丢失了信息,我们无法通过指纹还原出原始 Key,那怎么算它的另一个位置呢?

Cuckoo Filter 的作者设计了一个极其巧妙的异或 (XOR)公式:

这个公式的精髓在于“自反性”:

这意味着:

  • 如果你在位置 ,指纹是 ,那么另一个位置 。
  • 如果你在位置 ,指纹是 ,那么另一个位置 。

结论:只要知道当前位置和指纹,就可以算出的另一个位置,根本不需要原始元素 !这就是布谷鸟过滤器支持“踢人”和“移动”的数学基础。


🗑️ 三、 删除操作的实现

有了上面的基础,删除操作变得异常简单且安全。

删除流程:

  1. 用户请求删除元素 。
  2. 计算指纹 。
  3. 计算两个候选位置:
    1. 检查桶 :有没有指纹 ?如果有,从桶里移除它,返回成功。
    2. 检查桶 :有没有指纹 ?如果有,从桶里移除它,返回成功。
    3. 都找不到?说明元素不存在。

    为什么安全?
    因为我们删除的是一个具体的指纹,而不是像布隆过滤器那样粗暴地把一个置零。
    即使两个不同的元素 和 发生了哈希碰撞(映射到了同一个桶),只要它们的指纹不同(概率极高),删除 就绝对不会影响 。

    如果指纹也碰撞了呢?(两个元素哈希位置一样,指纹也一样)。
    这被称为False Deletion。但这只会发生在你有两个完全一样的数据,或者极低概率的指纹碰撞时。对于过滤器来说,这通常是可以接受的(只会导致该存在的元素被误删,变为 False Negative,但这在工程上极少发生)。


    ⚔️ 四、 布隆 vs 布谷鸟:巅峰对决

    特性布隆过滤器 (Bloom Filter)布谷鸟过滤器 (Cuckoo Filter)
    删除支持不支持支持
    空间效率只有在 FPR (误判率) 很高时占优在低 FPR (❤️%) 时更省空间
    查询性能总是 K 次哈希访问2 次内存访问 (通常 1 次命中)
    插入性能稳定快满了会变慢 (因为要踢人)
    实现难度简单稍复杂 (需处理挤兑死循环)
    容量限制必须预估,不可动态扩容必须预估 (虽然支持删除,但桶大小固定)

    🎯 总结

    布谷鸟过滤器通过“指纹存储”+“异或位置推导”,完美解决了布隆过滤器的删除难题。
    它的核心在于那个精妙的异或公式,让我们在不存储原始数据的情况下,依然能在两个哈希桶之间反复横跳。

    Next Step:
    如果你的业务场景是Redis 缓存穿透防护,且数据基本不删除,继续用 Bloom Filter 即可,简单稳定。
    但如果你的场景是垃圾邮件黑名单实时风控系统,黑名单里的 IP 需要频繁添加和移除,那么Cuckoo Filter(或者 Redis 的模块RedisBloom里的 CF 实现)绝对是你的最佳选择。

    版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
    网站建设 2026/4/15 11:03:59

    AI产品经理必修课:拆解大模型落地的关键能力与实战技巧

    文章从四大维度系统阐述了AI产品经理的必备能力:两大定律(AI能力定律和AI提效定律)强调判断力的重要性;五要素(业务人员参与、AI能力认知、编程能力、小处着手、老板支持)确保大模型成功落地;技…

    作者头像 李华
    网站建设 2026/4/8 10:44:31

    CodeArts Doer代码智能体

    什么是CodeArts Doer代码智能体 CodeArts Doer代码智能体是一款集代码大模型、AI IDE、代码Agent为一体的智能编码产品。面向代码生成、研发知识问答、单元测试用例生成、代码解释、代码注释、代码调试、代码翻译、代码检查、代码优化等场景功能,为开发者提高研发效…

    作者头像 李华
    网站建设 2026/4/12 14:55:49

    SpringMVC的处理流程

    一张图搞懂 SpringMVC 完整请求流程:从浏览器到页面响应的全链路拆解作为 Java 后端开发者,SpringMVC 的请求处理流程是日常开发的核心逻辑,但很多时候我们只知其然不知其所以然。今天,我就通过这张经典的 SpringMVC 处理流程图&a…

    作者头像 李华
    网站建设 2026/4/7 7:57:44

    YOLOv8科研级轻量化升级:基于SOTA ADown的高效下采样设计

    文章目录 【YOLOv8科研级轻量化】集成SOTA轻量下采样ADown,让模型下采样效率跃升20%+ 一、为什么要做这个改进? 二、先搞懂原理:ADown的设计逻辑 1. ADown的核心设计 2. 替换YOLOv8下采样的思路 三、动手改造YOLOv8:从代码到训练的完整路径 步骤1:实现ADown的核心代码 步骤…

    作者头像 李华