【问题标题】:BloomFilter in C++ using the MurmurHash3 hash functionC++ 中的 BloomFilter 使用 MurmurHash3 哈希函数
【发布时间】:2017-04-21 15:49:16
【问题描述】:

我正在尝试使用 MurmurHash3 哈希函数编写 Bloom 过滤器的 C++ 实现。我的实现基于这个站点:http://blog.michaelschmatz.com/2016/04/11/how-to-write-a-bloom-filter-cpp/

不知何故,在我的 BloomFilter 头文件中,哈希函数抛出了一个不完整的类型错误,而且,当我在 add 函数中使用哈希函数时,我得到一个“哈希是模棱两可的错误”。

我能做些什么来解决这个问题?我对 C++ 有点陌生,所以我不确定我是否正确使用了结构的接口/实现。

我还使用了一个包含此文件的主函数并运行一些测试来分析误报率、位数、过滤器大小等。 . .

#ifndef BLOOM_FILTER_H
#define BLOOM_FILTER_H
#include "MurmurHash3.h"
#include <vector>


//basic structure of a bloom filter object
struct BloomFilter {
BloomFilter(uint64_t size, uint8_t numHashes);
void add(const uint8_t *data, std::size_t len);
bool possiblyContains(const uint8_t *data, std::size_t len) const;
private:
uint8_t m_numHashes;
   std::vector<bool> m_bits;
};
//Bloom filter constructor
BloomFilter::BloomFilter(uint64_t size, uint8_t numHashes)
   : m_bits(size),
   m_numHashes(numHashes) {}
//Hash array created using the MurmurHash3 code
std::array<uint64_t, 2> hash(const uint8_t *data, std::size_t len)
{
   std::array<uint64_t, 2> hashValue;
   MurmurHash3_x64_128(data, len, 0, hashValue.data());
   return hashValue;
}
//Hash array created using the MurmurHash3 code
inline uint64_t nthHash(uint8_t n,
   uint64_t hashA,
   uint64_t hashB,
   uint64_t filterSize) {
   return (hashA + n * hashB) % filterSize;
}
//Adds an element to the array
void BloomFilter::add(const uint8_t *data, std::size_t len) {
   auto hashValues = hash(data, len);
   for (int n = 0; n < m_numHashes; n++)
   {
       m_bits[nthHash(n, hashValues[0], hashValues[1], m_bits.size())]        = true;
   }
}
//Returns true or false based on a probabilistic assesment of the array         using MurmurHash3
bool BloomFilter::possiblyContains(const uint8_t *data, std::size_t   len) const {
   auto hashValues = hash(data, len);
   for (int n = 0; n < m_numHashes; n++)
   {
       if (!m_bits[nthHash(n, hashValues[0], hashValues[1],         m_bits.size())])
        {
           return false;
       }
   }
   return true;
}
#endif

【问题讨论】:

  • 请发布您所面临的确切的、未经编辑的错误消息。
  • MurmurHash3_x64_128(data, len, 0, hashValue.data());这在我看来很可疑。你从哪里得到定义?

标签: c++ hash bloom-filter


【解决方案1】:

如果您的 MurmurHash3_x64_128 返回两个 64 位数字作为哈希值,只要您的位字符串中不需要超过 40 亿位,我会将其视为 4 个不同的 uint32_t 哈希。很可能您不需要超过 2-3 个哈希,但这取决于您的用例。要确定您需要多少哈希,您可以查看"How many hash functions does my bloom filter need?"。

使用 MurmurHash3_x64_128 我会这样做(如果我将其视为 4 x uint32_t 哈希):

void BloomFilter::add(const uint8_t *data, std::size_t len) {
    auto hashValues = hash(data, len);
    uint32_t* hx = reinterpret_cast<uint32_t*>(&hashValues[0]);
    assert(m_numHashes <= 4);
    for (int n = 0; n < m_numHashes; n++)
        m_bits[hx[n] % m_bits.size()] = true;
}

您的代码在类型转换方面存在一些问题,这就是它无法编译的原因:

  • 缺少#include &lt;array&gt;
  • 您必须使用 size_t 作为大小(可能是 32 位无符号或 64 位无符号整数)
  • 最好将您的哈希命名为其他名称(例如 myhash)并将其设为静态。

这是您的代码版本,经过这些更正,这应该可以工作:

#ifndef BLOOM_FILTER_H
#define BLOOM_FILTER_H
#include "MurmurHash3.h"
#include <vector>
#include <array>


//basic structure of a bloom filter object
struct BloomFilter {
    BloomFilter(size_t size, uint8_t numHashes);
    void add(const uint8_t *data, std::size_t len);
    bool possiblyContains(const uint8_t *data, std::size_t len) const;
private:
    uint8_t m_numHashes;
    std::vector<bool> m_bits;
};
//Bloom filter constructor
BloomFilter::BloomFilter(size_t size, uint8_t numHashes)
    : m_bits(size),
    m_numHashes(numHashes) {}
//Hash array created using the MurmurHash3 code
static std::array<uint64_t, 2> myhash(const uint8_t *data, std::size_t len)
{
    std::array<uint64_t, 2> hashValue;
    MurmurHash3_x64_128(data, len, 0, hashValue.data());
    return hashValue;
}
//Hash array created using the MurmurHash3 code
inline size_t nthHash(int n,
    uint64_t hashA,
    uint64_t hashB,
    size_t filterSize) {
    return (hashA + n * hashB) % filterSize; // <- not sure if that is OK, perhaps it is.
}
//Adds an element to the array
void BloomFilter::add(const uint8_t *data, std::size_t len) {
    auto hashValues = myhash(data, len);
    for (int n = 0; n < m_numHashes; n++)
    {
        m_bits[nthHash(n, hashValues[0], hashValues[1], m_bits.size())] = true;
    }
}
//Returns true or false based on a probabilistic assesment of the array         using MurmurHash3
bool BloomFilter::possiblyContains(const uint8_t *data, std::size_t   len) const {
    auto hashValues = myhash(data, len);
    for (int n = 0; n < m_numHashes; n++)
    {
        if (!m_bits[nthHash(n, hashValues[0], hashValues[1], m_bits.size())])
        {
            return false;
        }
    }
    return true;
}
#endif

Run this code on ideone.

如果你刚开始使用 c++,首先从基本示例开始,尝试使用 std::hash 可能吗?创建工作实现,然后使用可选的散列函数参数对其进行扩展。如果您需要快速的 BloomFilter,我可能会远离 vector&lt;bool&gt; 并改用无符号整数数组。

基本的 impl 可以是这样的,前提是你已经实现了 MurmurHash3:

uint32_t MurmurHash3(const char *str, size_t len);

class BloomFilter
{
public:
    BloomFilter(int count_elements = 0, double bits_per_element = 10)
    {
        mem = NULL;
        init(count_elements, bits_per_element);
    }
    ~BloomFilter()
    {
        delete[] mem;
    }

    void init(int count_elements, double bits_per_element)
    {
        assert(!mem);
        sz = (uint32_t)(count_elements*bits_per_element + 0.5);
        mem = new uint8_t[sz / 8 + 8];
    }

    void add(const std::string &str)
    {
        add(str.data(), str.size());
    }

    void add(const char *str, size_t len)
    {
        if (len <= 0)
            return;
        add(MurmurHash3(str, len));
    }

    bool test(const std::string &str)
    {
        return test(str.data(), str.size());
    }

    bool test(const char *str, size_t len)
    {
        return test_hash(MurmurHash3(str, len));
    }

    bool test_hash(uint32_t h)
    {
        h %= sz;
        if (0 != (mem[h / 8] & (1u << (h % 8))))
            return true;
        return false;
    }

    int mem_size() const
    {
        return (sz + 7) / 8;
    }

private:
    void add(uint32_t h)
    {
        h %= sz;
        mem[h / 8] |= (1u << (h % 8));
    }

public:
    uint32_t sz;
    uint8_t *mem;
};

【讨论】:

  • 问题是我的作业需要使用 MurmurHash 并使用 10 个哈希函数进行测试。我只需要知道如何摆脱不完整的类型错误和模糊的哈希函数。
  • @LoganLaFollette 我更新了你的函数should work now。
  • 嗨@Pavel 很高兴看到你的代码ideone。我实际上是在尝试创建一个布隆过滤器数组(可以是静态的或动态的)。你能帮我如何修改这段代码吗?
  • @viz12 只是创建指针数组并手动创建/删除它们?
  • @Pavel 是的,我创建如下,但它给了我编译错误。 BloomFilter *BFs = (BloomFilter *) malloc(sizeof(BloomFilter)*10); for(int i=0; i&lt;10; i++) BFs[i] = new BloomFilter (1024 * 1024, 5);
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-11-05
  • 1970-01-01
  • 2012-05-09
  • 2015-06-22
  • 1970-01-01
  • 2019-03-26
  • 1970-01-01
相关资源
最近更新 更多