我应该使用什么哈希函数用于带有+ 128位密钥的bloom-filter?

时间:2013-09-01 00:04:20

标签: c# .net optimization hash bloom-filter

https://github.com/joeyrobert/bloomfilter使用Random类作为哈希函数performance killer 我要做的是用byte [] s而不是泛型参数(T)输入类并摆脱

    private int Hash(T item) {
        return item.GetHashCode();
    }

我知道有一个巨大的性能优势,但我不知道如何在这里替换_random.Next(_bitSize)

#region Public Methods
/// <summary>
/// Adds an item to the bloom filter.
/// </summary>
/// <param name="item">Item to be added</param>
public void Add(T item)
{
    _random = new Random(Hash(item));

    for (int i = 0; i < _numberOfHashes; i++)
        _bitArray[_random.Next(_bitSize)] = true;
}

使用一些非延迟代码行,每个位不会占用数千个CPU周期。

我知道代码中还有很多其他问题可以使它更快/更安全。我(大多数时候)修复它们并且在推动我的更改之前卡在最后一个上。 任何帮助都非常感谢。

2 个答案:

答案 0 :(得分:2)

我不明白你为什么要在这里使用随机数生成器...但是,我可以帮助你加快速度。

布隆过滤器基本上是一个位向量,您可以在其中设置位。如果你想弄清楚一个项目是否存在,如果项目可能存在,布隆过滤器会给你一个真假,如果项目肯定不存在则布隆过滤器

(我在一个简单的文本编辑器中执行此操作,因此代码中可能存在一些错误)

我假设你的哈希空间可以使用32位整数计算;如果你有一个非常大的bloom表,你可能想要使用64位整数。

布隆过滤器的最简单(也可能是最快)实现是:

byte[] bloomFilter = new byte[MyBloomFilterSize];

foreach (var item in myItems) 
{
    int hash = Hash(item) & 0x7FFFFFFF;
    int bit = 1 << (hash & 7); // you have 8 bits
    int index = (hash >> 3) % MyBloomFilterSize;
    bloomFilter[hash % MyBloomFilterSize] |= bit;
}

您可以尝试将byte[]更改为uint[]ulong[];我不确定这是否有所作为。

如果您想检查项目是否存在,则计算相同的索引和位,并获得结果。

public bool PossiblyExists(MyItem item)
{
    int hash = Hash(item) & 0x7FFFFFFF;

    int bit = 1 << (hash & 7); // you have 8 bits
    int index = (hash >> 3) % MyBloomFilterSize;
    return (bloomFilter[hash % MyBloomFilterSize] & bit) != 0;
}

这里唯一剩下的就是你可以计算哈希的速度。如果你使用的是整数,我只需将它乘以一个大的素数;如果你使用SHA256固定长度字节[](你似乎在做),你需要使它成为一个整数(或长整数)。

我在这里使用Buffer.BlockCopy来转换类型。为了安全起见,我更喜欢使用数据中的几个字节,但由于SHA256应该已经是随机的,因此一个简单的BitConverter.ToInt32(data, [0..28])也可以做到这一点。

public int CalculateHash(byte[] data) 
{
    // Data = >128 bits = >16 bytes -- which is the same as >4 integers

    int[] tmp = new int[4];
    Buffer.BlockCopy(data, 0, tmp, 0, data.Length);
    return tmp[0] ^ tmp[1] ^ tmp[2] ^ tmp[3];
}

应该这样做。

答案 1 :(得分:1)

例如,以下是一种有效的实现。如果您具有返回64位的哈希函数,则最好使用此函数代替murmur3_64。警告:我没有对其进行测试。

void Add(string item) {
    ulong hash = murmur3_64((ulong) item.GetHashCode());
    uint a = (uint) (hash >> 32);
    uint b = (uint) hash;
    for (int i = 0; i < k; i++) {
        _bitArray[reduce(a, _bitSize)] = true;
        // "Less Hashing, Same Performance: Building a Better Bloom Filter"
        a += b;
    }
}

ulong murmur3_64(ulong x) {
    x = (x ^ (x >> 33)) * 0xff51afd7ed558ccdL;
    x = (x ^ (x >> 23)) * 0xc4ceb9fe1a85ec53L;
    x = x ^ (x >> 33);
    return x;
}

uint reduce(uint hash, uint n) {
    // http://lemire.me/blog/2016/06/27/a-fast-alternative-to-the-modulo-reduction/
    return (hash * n) >> 32;
}