C-64位整数中的快速Bloom过滤器,高频初始化/查询/销毁循环
我需要一个布鲁姆过滤器的实施,为一个大型项目的一部分。整个项目都是C语言的(而且只有C语言!没有C++),不幸的是,我还没有找到任何合适的基于C的BloomFilter实现(除了一个实现) 我的布卢姆过滤器要求:C-64位整数中的快速Bloom过滤器,高频初始化/查询/销毁循环,c,hashtable,bloom-filter,C,Hashtable,Bloom Filter,我需要一个布鲁姆过滤器的实施,为一个大型项目的一部分。整个项目都是C语言的(而且只有C语言!没有C++),不幸的是,我还没有找到任何合适的基于C的BloomFilter实现(除了一个实现) 我的布卢姆过滤器要求: 1.包含布卢姆过滤器的模块每50毫秒运行一次 整个模块需要在5-6ms内完成执行, 这意味着整个布卢姆过滤器代码必须在3毫秒内完成 2.元素是64位整数 3.我总共少于8k个元素(包括插入/查询) 常见的情况是向过滤器中插入几百个,以及1000-1500个查询 每50毫秒,我会收到两组
1.包含布卢姆过滤器的模块每50毫秒运行一次
整个模块需要在5-6ms内完成执行,
这意味着整个布卢姆过滤器代码必须在3毫秒内完成
2.元素是64位整数
3.我总共少于8k个元素(包括插入/查询)
常见的情况是向过滤器中插入几百个,以及1000-1500个查询 每50毫秒,我会收到两组(W,R)64位整数。我需要找到这个历元中接收到的W&R之间的交点(注意,bloom过滤器必须为每个历元重新启动)。下面的代码显示了一般控制流程
sleep(50ms)
...module code..
clear(bloomfilter) /* basically a memset(0) on bloomfilter bitmap */
W = getListW()
for each entry in W
insert(bloomfilter, entry)
R = getListR()
for each entry in R
if (present(bloomfilter, entry))
..do something with entry..
..rest of module code..
现在,我看到了几篇论文,它们声称在非常大的数据集上进行快速布鲁姆过滤器操作。但我的要求不同。我需要快速种子(插入W)和快速查询。散列函数是另一个关注点。由于时间限制,我负担不起像SHA1这样的重载哈希函数。您希望保持这种简单。因为您处理的是少量元素,它们是64位整数(在32位机器上比较快,在64位机器上比较快)。首先,我将使用一个包含64K元素的哈希表。插入时,对64位int进行16位“散列”,方法是将每个16位片段异或到一起以获得表索引。如果速度不够快,请分析它以找出原因 这听起来不像用bloom过滤器做某事那么性感。但实际上,您只处理8K整数。下面是我现在编写的一些代码(没有尝试编译)。假设插入的数字是随机分布的,这可能会非常快,如果任何一个插入为0,这将不起作用
uint64_t table[65536] = {0};
void clear()
{
memset(table, 0, sizeof(table));
}
uint16_t hash(uint64_t val)
{
assert(ele != 0);
uint16_t *parts = (uint16_t*)&ele;
uint16_t h = 0x5AA5;
h = h * 131 + parts[0];
h = h * 131 + parts[1];
h = h * 131 + parts[2];
h = h * 131 + parts[3];
return h;
}
void insert(uint64_t ele)
{
uint16_t h = hash(ele);
while (table[h])
++h;
table[h] = ele;
}
int find(uint64_t ele)
{
int res = 0;
uint16_t h = hash(ele);
while (table[h] != ele)
{
if (!table[h])
return 0;
++h;
}
return 1;
}
如果插入内容不是随机分布的,则需要更好的冲突解决方案。你也可以想出一个更好的散列方法。如果我理解你的意思:
set1={e1}
和set2={e2}
,e1!=e2
,即set1与set2={}
相交,但bf(set1)与bf(set2){}
。注意,你永远不会得到假阴性——如果bf(set1)与bf(set2)={}
相交,那么必然set1与set2={}
我认为您的算法应该为R和W形成BFs,然后一次使它们相交尽可能多的位,如下面的变量2所示
快砍,生锈的C:
const unsigned N = 1024 * 8;
const unsigned BPW = 8 * sizeof ulong;
typedef unsigned long ulong;
typedef struct BF { ulong bits[N/BPW]; } BF;
unsigned hash(ulong e) { return foo(e) % N; }
void clear(BF* pbf) { memset(pbf->bits, 0, sizeof(pbf->bits)); }
void add(BF* pbf, ulong e) { unsigned h = hash(e); bf.bits[h/BPW] |= 1 << (h%BPW); }
bool hit(BF* pbf, ulong e) { unsigned h = hash(e); return (bf.bits[h/BPW]>>(h%BPW)) & 1; }
bool intersect(BF* pbfResult, BF* pbf1, BF* pbf2) {
bool empty = TRUE;
for (unsigned i = 0; i < N/BPW; i++)
if ((pbfResult->bits[i] = pbf1->bits[i] & pbf2->bits[i]) != 0)
empty = FALSE;
return !empty;
}
void intersectRW(unsigned nr, ulong* r, unsigned nw, ulong* w) {
BF bfR, bfW, bfIntesection;
unsigned i;
clear(&bfR);
for (i = 0; i < nr; i++)
add(&bfR, r[i]);
// variant 1: enumerate elements of W that hit in BF(R)
for (i = 0; i < nw; i++)
if (hit(&bfR, w[i]))
... w[i] ...
// variant 2: determine if intersection of BFs is empty and get intersection BF
clear(&bfW);
for (i = 0; i < nw; i++)
add(&bfW, w[i]);
bool any = intersect(&bfIntersection, &bfR, &bfW);
...
}
const无符号N=1024*8;
常量无符号BPW=8*sizeof ulong;
typedef无符号长ulong;
typedef结构BF{ulong bits[N/BPW];}BF;
无符号散列(ulonge){返回foo(e)%N;}
无效清除(BF*pbf){memset(pbf->bits,0,sizeof(pbf->bits));}
void add(BF*pbf,ulong e){unsigned h=hash(e);BF.bits[h/BPW]|=1>(h%BPW))&1;}
布尔相交(BF*pbfResult,BF*pbf1,BF*pbf2){
bool empty=TRUE;
for(无符号i=0;ibits[i]=pbf1->bits[i]&pbf2->bits[i])!=0)
空=假;
返回!空;
}
无效相交RW(无符号nr、ulong*r、无符号nw、ulong*w){
BF-bfR、bfW、BF段;
未签名的i;
清除(&bfR);
对于(i=0;i
预期运行时间