【问题标题】:How to map hashfunction output to bloomfilter indices?如何将哈希函数输出映射到布隆过滤器索引?
【发布时间】:2012-07-25 16:13:05
【问题描述】:

谁能帮助我提供关于哈希函数输出如何映射到布隆过滤器索引的概述?这是bloomfilters的概述。

【问题讨论】:

    标签: c++ database algorithm bloom-filter


    【解决方案1】:

    哈希函数输出如何映射到布隆过滤器索引的概述

    对于每个使用的 k 哈希函数,它们映射到布隆过滤器中的一个位,就像哈希映射到哈希表中的哈希桶一样。因此,通常你可能会说一个生成 32 位整数的哈希函数,然后使用模数 % 运算符来获取位索引 0 << i < n 其中n 是布隆过滤器中的位数。

    为了更具体,假设一个哈希函数生成从 0 到 2^32-1 的数字,并且布隆过滤器中有 1000 位:

    int bit_index = hash_function(input_value) % 1000;
    

    这里需要注意的是 2^32-1 远远大于 1000。假设哈希函数生成了相当均匀分布的数字,但仅在 0 和 1023 之间,那么在模运算之后,它的可能性会增加一倍与 24..999 相比,该 bit_index 将在 0..23 范围内(因为例如输入 2 和 1002 都导致模数后值为 2,但只有输入 25 会产生输出 25)。出于这个原因,如果您有一个生成 32 位的散列函数,您可能希望使用一个大小为 2 的幂的位数的布隆过滤器,然后切出散列值的部分以用作独立散列函数- 所有在您链接的维基百科文章中都有解释。不过,这需要一个高质量的散列函数,因为散列函数中的任何“聚类”缺陷都会直接传递到输出;具有质数位是减轻这种不良散列的一种方法。尽管如此,对于良好的散列函数,2 的幂也可以很容易地使用按位与运算和 - 如果需要 - 位移来提取位索引,这可能比整数模数更快,尽管散列函数可能会使这种考虑相形见绌整体性能概况。

    编辑 - 寻址 cmets...

    假设你的 MD5 函数返回一个 unsigned char* "p" 到 MD5_DIGEST_LENGTH 字节的数据,我建议你试试:

    BOOST_STATIC_ASSERT(MD5_DIGEST_LENGTH >= sizeof(int));
    int bit_index = *reinterpret_cast<unsigned int*>(p) % num_of_bloom_filter_bits;
    

    这实际上是一个特别糟糕的主意 - 抱歉 - 我稍后会解释其中的两个原因。首先,回答您关于它的作用的问题:BOOST_STATIC_ASSERT() 旨在在其传递的表达式已评估为 false 时为您提供编译错误。在这里,它基本上是一种记录MD5_DIGEST_LENGTH 要求的方法 - 它是 MD5 散列的文本表示的字符大小 - 至少与系统用于 int 整数类型的字节数一样长. (该大小可能是 4 个字节,但也可能是 8 个字节。)该要求旨在确保下一行中的 reinterpret_cast 是安全的。这样做是从 MD5 散列的文本表示开头的字节中读取一个值,就好像这些字节包含一个int。因此,假设您的 int 大小 is 4,MD5 哈希为“0cc175b9c0f1b6a831c399e269772661”,如您的评论:前 4 个字节包含“0cc1”。该文本的 ASCII 代码是十进制的 48、99、99、49。当它们被读入int 时,值可能会有所不同,具体取决于 CPU 的字节序,但基本上你会得到其中一个数字乘以 256^3 再加上一个乘以 256^2 再加上第三个乘以 256 加最后的数字。

    我说这是一个特别糟糕的主意的原因是:

    • MD5 字符串中的每个字符要么是数字(ASCII 代码 48-57),要么是从“a”到“f”(97-102)的字母。这 16 个值只是一个字节可以具有的变化的 16 分之一,而您生成的 int 值占用 32 位,您实际上只能得到 2^16 个不同的值。
    • 在某些计算机上,ints 必须与 2、4、8 等倍数的内存地址对齐。reinterpret_cast - 如果文本恰好从不兼容的地址开始,可能会导致计算机崩溃.注意:英特尔和 AMD 没有这样的对齐要求,尽管它们对正确对齐的数据进行操作可能会更快。

    所以,另一个建议:

    // create a buffer of the right size to hold a valid unsigned long in hex representation...
    char data[sizeof(unsigned long) * 2 + 1];
    
    // copy as much of the md5 text as will fit into the buffer, NUL terminating it...
    sprintf(data, "%.*s", sizeof data - 1, md5);
    
    // convert to an unsigned long...
    m = strtoul(data, /*endptr*/ NULL, /*base*/ 16);
    

    这里,如果 md5 表示比数据缓冲区短,则只会安全复制它的初始部分,因此不需要 BOOST_STATIC_ASSERT。

    使用非加密哈希函数要容易得多,因为它们通常只会返回一个数字而不是数字的可读文本缓冲区表示,因此您可以避免所有这些废话。

    【讨论】:

    • 如果我使用输出 32 位的 MD5 哈希函数,如何从中获取bloomfilter 的索引?假设 MD5 ("a")=0cc175b9c0f1b6a831c399e269772661,我怎样才能从中得到实际上是整数的位索引?
    • 假设你的MD5函数返回一个unsigned char* "p" 到MD5_DIGEST_LENGTH字节的数据,你可以试试BOOST_STATIC_ASSERT(MD5_DIGEST_LENGTH &gt;= sizeof(int)); int bit_index = *reinterpret_cast&lt;unsigned int*&gt;(p) % num_of_bloom_filter_bits;
    • 另外 - MD5 可能有点矫枉过正...... partow.net/programming/hashfunctions/index.html 描述了一些更简单/更快的算法(链接了 C++ 实现),尽管我没有亲自使用它们,但在其他地方推荐了这些算法。
    • 非常感谢 tony 让我知道我急需的其他哈希函数!当我应用您为将 MD5 输出转换为bloomfilter 索引而编写的上述代码块时,您介意解释一下实际发生了什么吗?我测试了你的代码,它实际上给了我一个在布隆过滤器位数范围内的值,但我错过了它实际工作的部分,我很抱歉我也不熟悉 boost 库,请告诉我你为什么使用在这里?
    • 嗯 - 这是一个足够大的问题,我将在我的答案中编辑讨论......
    猜你喜欢
    • 2014-11-10
    • 1970-01-01
    • 1970-01-01
    • 2018-07-21
    • 2012-08-10
    • 1970-01-01
    • 2019-04-27
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多