布谷鸟过滤器

布谷鸟过滤器是一种概率数据结构,用于检查元素是否存在于集合中

布谷鸟过滤器,就像布隆过滤器一样,是 Redis 开源版中的一种概率数据结构,它可以以非常快速且节省空间的方式检查元素是否存在于集合中,同时还支持删除操作,并在某些场景下表现优于布隆过滤器。

布隆过滤器是一个位数组,根据哈希函数确定的位置翻转位;而布谷鸟过滤器是一个桶数组,根据两个哈希函数确定的位置将值的指纹存储在其中一个桶中。对项目 x 的成员资格查询会搜索可能的桶以查找 x 的指纹,如果找到相同的指纹则返回 true。布谷鸟过滤器的指纹大小将直接决定误报率。

用例

定向广告活动(广告、零售)

此应用解答这个问题:用户是否已注册此活动?

为每个活动使用一个布谷鸟过滤器,填充目标用户的 ID。每次访问时,都会针对其中一个布谷鸟过滤器检查用户 ID。

  • 如果检查结果为“是”(即用户 ID 存在于过滤器中),表示用户尚未注册该活动。显示广告。
  • 如果用户点击广告并注册,将用户 ID 从该布谷鸟过滤器中移除。
  • 如果检查结果为“否”(即用户 ID 不存在于过滤器中),表示用户已注册该活动。尝试下一个广告/布谷鸟过滤器。

折扣码/优惠券验证(零售、网店)

此应用解答这个问题:此折扣码/优惠券是否已使用?

使用一个填充了所有折扣码/优惠券的布谷鸟过滤器。每次尝试时,都会根据过滤器检查输入的代码。

  • 如果检查结果为“否”(即代码不存在于过滤器中),则优惠券无效。
  • 如果检查结果为“是”(即代码存在于过滤器中),则优惠券可能有效。检查主数据库。如果有效,则从布谷鸟过滤器中移除,标记为 used

注意> 除了这两个用例,布谷鸟过滤器也非常适合所有布隆过滤器的用例。

示例

你将学习如何创建一个初始容量为 1,000 个项目的空布谷鸟过滤器,添加项目,检查它们是否存在,并删除它们。尽管 CF.ADD 命令可以在过滤器不存在时创建新过滤器,但其大小可能不适合你的需求。最好使用 CF.RESERVE 命令设置一个具有你偏好容量的过滤器。

布隆过滤器对比布谷鸟过滤器

布隆过滤器在插入项目时通常表现出更好的性能和可伸缩性(因此,如果你经常向数据集中添加项目,布隆过滤器可能是理想选择)。布谷鸟过滤器在检查操作上更快,并且允许删除。

布谷鸟过滤器大小调整

这些是布谷鸟过滤器的主要参数和特性

  • p 目标误报率
  • f 指纹长度(比特)
  • α 填充率或负载因子 (0≤α≤1)
  • b 每个桶的条目数
  • m 桶数
  • n 项目数
  • C 每个项目的平均比特数

首先要记住,布谷鸟过滤器的一个桶可以有多个条目(每个条目存储一个指纹)。如果所有条目都被指纹占用,我们将没有空槽来保存新元素,过滤器将被声明为满,这就是为什么我们应该始终保持一定比例的布谷鸟过滤器为空。
因此,一个项目的“实际”内存成本除了指纹大小外,还应包括该开销。如果 α 是负载因子(指纹大小 / 总过滤器大小),f 是一个条目中的比特数,则分摊空间成本为 f/α 比特

初始化新过滤器时,你需要选择其容量和桶大小。

CF.RESERVE {key} {capacity} [BUCKETSIZE bucketSize] [MAXITERATIONS maxIterations]
[EXPANSION expansion]

选择容量 (capacity)

布谷鸟过滤器的容量计算公式为

capacity = n*f/α

其中 n 是你期望过滤器中包含的元素数量,f 是指纹长度(比特),设置为 8α 是填充因子。因此,要确定过滤器的容量,必须首先选择一个填充因子。填充因子将决定你数据的密度以及内存占用。容量将被向上取整到下一个“2 的幂 (2n)”数。

请注意,在布谷鸟过滤器中插入重复项目会尝试多次添加它们,导致过滤器被填满

由于布谷鸟过滤器的工作原理,过滤器可能会在达到容量之前自行声明已满,因此填充率可能永远无法达到 100%。

选择桶大小 (BUCKETSIZE)

每个桶中的项目数。桶大小值越大,填充率越高,但也会导致更高的错误率和稍微慢的性能。

error_rate = (buckets * hash_functions)/2^fingerprint_size = (buckets*2)/256

当桶大小为 1 时,填充率为 55%,误报率为 2/256 ≈ 0.78%,这是你可以实现的最小误报率。更大的桶会线性增加错误率,但会提高过滤器的填充率。例如,桶大小为 3 会产生 2.34% 的错误率和 80% 的填充率。桶大小为 4 会产生 3.12% 的错误率和 95% 的填充率。

选择扩展因子 (EXPANSION)

当过滤器自行声明已满时,它将通过生成附加子过滤器来自动扩展,代价是性能降低和错误率增加。新子过滤器的大小是前一个子过滤器的大小乘以 EXPANSION(在创建过滤器时选择)。与桶大小一样,附加子过滤器会线性增加错误率(复合错误是所有子过滤器错误的总和)。新子过滤器的大小是最后一个子过滤器的大小乘以扩展因子,这一点非常重要。如果你知道将来某个时候必须进行扩展,最好选择一个更高的扩展值。默认值为 1。

也许你会问“如果我知道我反正会扩展,为什么还要创建一个具有高扩展率的小型过滤器呢?”答案是:在需要维护许多过滤器(例如,每个用户或每个产品一个过滤器)的情况下,大多数过滤器会保持较小规模,但有些活动较多的过滤器则需要扩展。

扩展因子将被向上取整到下一个“2 的幂 (2n)”数。

选择最大迭代次数 (MAXITERATIONS)

MAXITERATIONS 决定了寻找传入指纹槽位的尝试次数。一旦过滤器满载,高 MAXITERATIONS 值会减慢插入速度。默认值为 20。

有趣的事实

  • 先前子过滤器中未使用的容量在可能时会自动使用。
  • 过滤器可以扩展多达 32 倍。
  • 你可以删除项目以保持在过滤器限制内,而不是重建
  • 多次添加相同的元素将创建多个条目,从而填满你的过滤器。

性能

向布谷鸟过滤器添加元素的时间复杂度为 O(1)。

同样,检查元素和删除元素的时间复杂度也为 O(1)。

学术来源

评价此页面
返回顶部 ↑
© . This site is unofficial and not affiliated with Redis, Inc.