python bit array bit array布隆过滤器:一针见血,误判率背后藏着多少坑?

📅 发布时间:2026/8/10 10:38:58
python bit array bit array布隆过滤器:一针见血,误判率背后藏着多少坑?
0.简介互联网发展之际, 应用数据量持续增多, 高效判定元素于集合里是否存在变得愈发关键。布隆过滤器, 也就是Bloom, 以及布谷鸟过滤器, 是两种常见的用以解决此问题的数据结构。本文会把这两种结构作详细的介绍。1.布隆过滤器Bloom )1.1 概念布隆过滤器是由Bloom于1970年提出的, 一种空间效率颇高的概率型的数据结构, 它籍由一个甚长的二进制向量, 也就是bit array, 以及一系列随机映射函数, 即hash组成, 其主要用途在于判定一个元素有无可能存在于一个集合里, 它准许出现一定程度的误判率, 就是有可能把一个并不存在的元素误判成存在, 然而却不会把一个已知存在的元素误判为不存在。能把它理解成类似一种hash set , 它被用来判定某个元素也就是key是不是在某个集合里头。和普通的那种hash set有的不一样之处在于 , 这种算法不需要去存储key的值 , 针对每个key , 仅仅只要k个比特位 , 每个这样的比特位存一个标志 , 靠这个来判别key在集合里不。1.2 原理首先说一说它从组成方面来讲, 是涵盖着两部分的, 其中一部分是呈现为一个很长的二进向量形式存在的, 说通俗点就是位数组所表现的样子而另一部分则是多个hash函数。就像下面所展示的这个图是示意其结构形态的, 这里面k1和k2是两个不同的值, 而后a、b、c是hash函数, 接下来能被看到的就是数组了, 先是把这两个不同的值分别通过三个hash函数计算, 之后它们将会分别落到数组相应位置上, 其中被绿色所代表的那个位置需要将其置为1。完成对其结构的知悉之后, 紧接着进行的是其应用进程里的原理剖析。首先首要的是针对布隆过滤器展开初始化, 在此过程当中, 所要抉择的是hash函数的数量以及位数组的规模大小。而其进行抉择的依据所在是判断的误算率False, 下面呈现的乃是其推导历程:以等概率条件选择并设置位数组中的某一位, 此为假说哈希函数要做的, m象征该位数组的大小, 这是已知的情况, k代表Hash函数的个数, 也是给定的, 那么位数组中某一特定的位, 在其特定位置, 于进行元素插入时的Hash操作里, 没有被置位, 这种情况出现的概率是:那么, 在进行所有的,k次,Hash操作之后, 该位一直都没有被设置为1的概率是:要是我们放进了 n 个元素, 进而则是某一位依旧为0 的概率是:因而该位为 1的概率是现在, 对某一元素于该集合之中与否进行检测。将标明某个元素于集合之中情况下所需的 k 个位置, 皆依照如上所述的方法设定为1, 然而, 此方法具有这样一个可能, 即会致使算法错误地判定某一本质上不在集合里的元素, 却被检测成处于该集合之中, 这种情况发生的概率, 是由以下公式来确定的:其实, 上述那些结果, 是在这样的前提之下计算出来的, 这个前提就是, 假定由每个Hash计算出的, 要设置的位, 也就是bit的位置, 它们是相互独立的, 不难看出来, 随着m, 也就是位数组大小的增加, False的概率会下降, 同时, 随着插入元素个数n的增加, False的概率又会上升, 对于给定的m和n, 要怎么去选择Hash函数个数k, 这是由以下公式确定的:此时False 的概率为最优的k为当面对给定的, 代表错误的概率p时, 要怎样去挑选, 最为合适的, 位数组大小m呢。由上式可知, 位数组的大小最优情况乃是与插入元素的个数呈现出线性关系, 针对于给定的 m, n, k, 假正例概率的最大值是:初始化依据选好的数组以及随机函数数量开展后的首个工作当属增添元素与查找元素, 增添元素的举措于概念引入时就作出了说明, 经hash函数运算得出结果后于位置1实施操作来增添查找元素时, 需判定经hash运算后各个位置均为1方可认定存在并推进后续查找步骤。1.3 使用场景及优缺点布隆过滤器的使用场景, 主要是针对那种对效率要求较高, 然而又能够容忍一定误判情况的场景, 比方说, 要判断文件里是不是存在某个元素, 要是存在的话, 再读文件去进行查询, 以此来提高查询的性能。其优点在于, 空间占用比较小, 这是位数组的特点, 计算时间比较快, hash函数处于O(n)级别, 不过, 其多个hash可能命中多个bit, 从而导致降低cpu缓存命中率其缺点在于, 存在一定误判率, 并且无法删除, 因为可能删除后影响其他元素。2. 布谷鸟过滤器 2.1 概念首先把布谷鸟过滤器设定成一种空间高效的数据载体, 专门予以用以检验一个实体是不是隶属某个集合, 它属于布隆过滤器的延伸拓展, 具备支持消除操作的优点长处, 其设计灵感源自布谷鸟的寄生繁衍行为, 会运用哈希量表去存放要点的指纹, 并且借助若干次哈希办法来明确储存地点。2.2 原理2.2.1 布谷鸟hash原理布谷鸟哈希算法名称和布谷鸟也就是大杜鹃有关联、有联系, 大杜鹃这种鸟类在进行筑巢行为的时候常常把自身所产之蛋放置在余下别的什么鸟巢里面去, 可以说是一种鸠占鹊巢的行为活动。布谷鸟哈希算法的核心思想同样也是经过把关键字搁置安放在两个具备可能性的位置上去从而解决冲突问题。该算法运用使用两个甚至更多超过两个的哈希函数, 把关键字各自分别映射映照到两个或者更多超过两个的具备可能性的位置上去。要是某个位置已经被别的元素占据占有了, 那就尝试着将占据处于该位置的元素“踢出去”除掉, 也就是替换替代安置到另另外一个为之位置上去, 并与此同时一同将当前当前被考虑的该元素插入添至到该位置里面去。如此这般重复着去实行替换操作, 一直持续到寻觅到一个空位置, 或者是达成了最大替换次数。要是最终寻觅到了空位置, 随即就把关键字给插入到其中否则的话, 哈希表就要进行扩容。如图所示, k1经两次hash后, 会得到两个位置, 选择其中一个进行put, k2历经两次hash后, 得到两个位置, 发现其中一个已被k1占用, 于是将数据放入第二个位置, 倘若第二个位置也被占用, 就随机踢出一个元素, 被踢出的元素会重新运算哈希以找到对应的位置, 同时避免一直踢出, 会设定一个踢出的阈值, 当达到阈值后, 便进行扩容。2.2.2 布谷鸟过滤器原理依据上面所呈现的图示来讲, 布谷鸟过滤器是由一个桶数组构建而成的, 这意味着一个位置能够放置多个元素, 每一个元素是n位, 这里的n位是通过数据计算得出的指纹, n的大小对误判率会产生影响, n越大的情况下, 误判的几率就越小, 有可能是类似这样的结构, n选取8位也就是一个字节, 每个桶能够容纳四个。type bucket [4]byte // 一个桶容纳四个元素 type cuckoo_filter struct { buckets [size]bucket // 多个桶 nums int // 容纳的元素的个数 kick_max // 最大挤兑次数 }知晓了结构之后, 接下来去看它的hash函数, 布谷鸟过滤器所设计的是并非相互独立的两个hash函数。fp fingerprint(x) p1 hash(x) p2 p1 ^ hash(fp) // 异或根据其对偶性可以知道p1 p2 ^ hash(fp)好处在于, 我们无需知道当前位置是 p1 还是 p2, 只需把当前位置与 hash(fp) 做异或计算, 便能得到对偶位置。并且, 只要保证 hash(fp)! 0, 就能确保 p1! p2, 如此可避免出现自己踢自己致使死循环的情况。随后, 继续瞧插入, 它的流程当中, 插入的过程, 跟布谷鸟哈希保持完全相同情况算位置, 会专门去算两个位置, 倘若其中一项位置已经存在元素了, 那就会把元素放置到另外一项位置, 要是另外一项位置也存在同等状态的占据情况, 就有可能会随机地将其中一个元素给踢出, 与此同时, 并设置好踢走元素时的上限数值。进行查找操作这事相对而言就简单些了, 给出的是一个要查找的项目, 算法一开始, 依据上面提到的插入公式, 对x的指纹以及两个候选桶进行计算。之后读取这两个桶。要是两个桶里任何现有的指纹存在匹配情况, 布谷鸟过滤器就返回true不然的话, 过滤器就返回false。删除的话就是在哈希表删除相应的指纹删除插入的项。2.3 使用场景和优缺点有着能够在数据去重、数据库索引等场景里运用的布谷鸟过滤器, 是用来判定元素是否存在的一种极为高效的数据结构, 它较之于布隆过滤器, 更为有效地利用了cpu高速缓存, 因而效率更高, 除此之外, 它能够轻易支持删除操作, 也比作布隆过滤器更好用。它的优势主要涵盖这些方面: 其一, 能够支持动态地进行插入操作以及删除操作其二, 空间利用效率处在较高水平其三, 查询效率偏高, 仅仅只需开展两次计算以及查找其四, 错误报告的概率较低。它的缺点关键涵盖这些: 其一, 访问的地址并非连续, 存在hash操作其二, 插入性能有所降低, 兴许要挪动别的元素其三, 若是支持多个重复元素插入, 会致使位置被占满进而来回挤占再则, 一旦不支持多个重复元素插入, 那么就会造成误删。