filter - 布谷鸟过滤器必须使用 2 的下一个幂作为容量吗?
问题描述
我发现大多数布谷鸟过滤器实现都将调用者提供的容量增加到了 2 的下一个幂。我没有在论文中看到任何提到“m”必须是 2 的幂的地方。这样做会导致较小的平均负载因子。
解决方案
我认为没有必要使容量为2的幂,但需要对原始方法进行一些更改。
我之前搜索过这个问题。从这个答案中,Giuseppe Ottaviano 认为论文给出的 95% 负载系数取决于表格大小的 2 次方,否则负载系数可能差到 50%。在那里,DW 推广了一种替代公式,该公式与非 2 的幂一起使用来解决这个问题。
虽然负载因子不依赖于此(我将在下面的实验中展示),但使用 xor 选择候选位置确实需要杜鹃滤波器的容量为 2 的幂。例如,如果指纹是 128 并且 i1 = 32,哈希(128)= 73,容量= 100。i2 = (i1 xor hash(fingerprint)) mod 100 = 5
而不是105。
但是,(105 xor hash(128)) mod 100 = 32, (5 xor hash(128)) mod 100 = 76。这意味着 xor 不是对合,会导致 cuckoo 滤波器的意外行为。
所以在这种情况下,它应该使用其他对合方法来选择候选位置,就像 DW 提到的那样h_2(x) = hash(fingerprint) - h_1(x) mod n
。
使用上述数据,h1(x) = i1 = 32, hash(fingerprint) = 73, h2(x) = hash(fingerprint) - h1(x) = 41。如果 hash(fingerprint) 小于 h1(x ) 这种方法仍然有效。当 h1(x) = 89, h2(x) = (73-89) +100 = 84
, 时h1(x) = (73-84) + 100 = 89
,它仍然是对合的。
实验
然而,与异或不同,替代方法可以使用与候选相同的位置。仍在使用capacity = 100
, lethash(fingerprint)=70
和h1(x) = 85
, h2(x) = hash(fingerprint) - h1(x) mod capacity = 85 = h1(x)
。这可能对负载系数有一些影响,因为插入更容易失败。我最近在 go 中完成了一个布谷鸟过滤器,并对负载因子进行了测试。
我测试了许多具有不同容量和桶大小的参数。单元测试代码如下。它将随机整数插入 cuckoo 过滤器,直到交换操作的时间超过 500。
ckflter := cuckooFilter.CuckooFilter{}
ckflter.NewCuckooFilter(tt.args.capacity,tt.args.bucketSize)
over := false
for !over{
element := rand.Intn(123456789000)
ok,_ := ckflter.Add(bloomfilter.CFElement{ElementValue: strconv.Itoa(element)})
if !ok{
over = true
}
}
fmt.Printf("Go test %s. Load factor %f",tt.name,ckflter.CalculateLoadFactor())
不同场景和论据的结果(capacity,bucket_size)
。那里的容量意味着布谷鸟过滤器中的桶数。Bucket_size 表示一个bucket中的指纹个数,b
在paper中。
原始数据发布在此答案的末尾。我计算了不同存储桶大小的平均负载因子,并在下面列出。
情况 | 不使用 2 的下一个幂 | 使容量成为 2 的次幂 | 替代方法 |
---|---|---|---|
桶大小 1 | 0.393278 | 0.45014 | 0.40673 |
桶大小 2 | 0.884191 | 0.878049 | 0.872531 |
桶大小 4 | 0.970461 | 0.963951 | 0.964365 |
桶尺寸 8 | 0.990913 | 0.989525 | 0.990372 |
no use next power of 2
表示即使容量不是 2 的幂,也使用 xor 计算候选位置。alternative method
表示不使用 2 的下一个幂,并h2(x) = hash(fingerprint) - h1(x) mod capacity
根据这篇文章计算候选位置
结果表明,上述所有三种方法的负载因子都非常相似。因此,替代方法适用于不是 2 的幂的容量。
PS:很抱歉我不能在互联网上发布我的代码,因为它被一家公司用于商业用途。我的实现是基于seiflotfy/cuckoofilter
PS2:原点数据
情况 | 不使用 2 的下一个幂 | 使容量成为 2 的次幂 | 替代方法 |
---|---|---|---|
(100,1) | 0.170000 | 0.656250 | 0.460000 |
(128,1) | 0.539062 | 0.507812 | 0.546875 |
(800,1) | 0.591250 | 0.417969 | 0.582500 |
(1024,1) | 0.517578 | 0.488281 | 0.593750 |
(10000,1) | 0.565100 | 0.491699 | 0.362200 |
(16384,1) | 0.458374 | 0.505737 | 0.483582 |
(100000,1) | 0.302530 | 0.451401 | 0.238530 |
(131072,1) | 0.372047 | 0.341164 | 0.315895 |
(1000000,1) | 0.145227 | 0.328159 | 0.125209 |
(1048576,1) | 0.271615 | 0.312927 | 0.358754 |
(100,2) | 0.935000 | 0.898438 | 0.885000 |
(128,2) | 0.875000 | 0.898438 | 0.878906 |
(800,2) | 0.887500 | 0.886719 | 0.872500 |
(1024,2) | 0.868164 | 0.886230 | 0.894043 |
(10000,2) | 0.916100 | 0.868591 | 0.871800 |
(16384,2) | 0.868042 | 0.874420 | 0.871399 |
(100000,2) | 0.895480 | 0.867485 | 0.861490 |
(131072,2) | 0.867046 | 0.871918 | 0.861286 |
(1000000,2) | 0.868981 | 0.863855 | 0.859927 |
(1048576,2) | 0.860598 | 0.864397 | 0.868959 |
(100,4) | 0.997500 | 0.974609 | 0.972500 |
(128,4) | 0.980469 | 0.953125 | 0.972656 |
(800,4) | 0.967187 | 0.975098 | 0.965000 |
(1024,4) | 0.968750 | 0.973389 | 0.969971 |
(10000,4) | 0.974725 | 0.967117 | 0.962075 |
(16384,4) | 0.967117 | 0.965134 | 0.966309 |
(100000,4) | 0.966420 | 0.960672 | 0.957130 |
(131072,4) | 0.963726 | 0.960442 | 0.961651 |
(1000000,4) | 0.959142 | 0.954331 | 0.956140 |
(1048576,4) | 0.959578 | 0.955596 | 0.960214 |
(100,8) | 1.000000 | 0.995117 | 1.000000 |
(128,8) | 1.000000 | 0.989258 | 0.995117 |
(800,8) | 0.992031 | 0.992798 | 0.988125 |
(1024,8) | 0.994751 | 0.991211 | 0.993896 |
(10000,8) | 0.987962 | 0.989838 | 0.989287 |
(16384,8) | 0.991455 | 0.989746 | 0.991959 |
(100000,8) | 0.985891 | 0.987493 | 0.987804 |
(131072,8) | 0.987256 | 0.987178 | 0.987913 |
(1000000,8) | 0.984694 | 0.986127 | 0.983695 |
(1048576,8) | 0.985085 | 0.986484 | 0.985922 |
总时间 | 14.74s | 15.22s | 14.49s |
推荐阅读
- mysql - 使用 pgloader 将 MySQL 数据库转换为 Postgres 数据库
- php - 通过 mysql cli 快速连接 MySQL,但使用 PDO 速度较慢
- flutter - 有没有办法在颤振中制作像模态一样的css?
- java - org.neo4j.ogm.exception.core.MappingException:多个类具有简单名称
- java - 无法创建 Sinch 客户端
- templates - 如何在 Flask 中呈现错误页面,不会导致请求的蓝图出现错误循环?
- c - 如果数据类型像 unsigned long int 等,如何标记 ac 程序
- java - 当我使用两个图表时,如何在导航图中获取当前选定的片段 ID
- php - PHP浮点输出格式
- java - 如何在java中使用javamail读取转发的邮件?