bloom

BloomFilter

模块信息

util/bloom.cc

模块概要

布隆过滤器由一个很大的bit数组和很多的哈希函数组成,用于判断一个元素是否在集合中。

当要往集合中加入一个元素时,就通过这些哈希函数将这个元素映射到bit数组不同的位上,并将该位设置为1。

当要判断一个元素是否在集合中时,同样通过一系列哈希函数将元素映射到bit数组不同位上,如果出现某个位不为1,则说明该元素不在集合中。

布隆过滤器是有可能产生错误的,为了减少错误,bit数组不能太小,不然很快各个位就变为1了。假设要加入n个元素,有k个哈希函数,bit数组大小位m,则满足以下公式时有最低误差率:
k = ( m / n ) ∗ l n 2 k=(m/n)*ln2 k=(m/n)ln2

主要接口
方法说明
void CreateFilter(const Slice* keys, int n, std::string* dst)加入n个key到dst中,用string来表示
bool KeyMayMatch(const Slice& key, const Slice& bloom_filter)判断key是否在集合中
源码分析
void CreateFilter(const Slice* keys, int n, std::string* dst) const override {
    // 总共的位数为n个key*每个key所占的位数
    size_t bits = n * bits_per_key_;

	// 为了保证位数不能太少,不然很快就全1了
    if (bits < 64) bits = 64;
	// 向上找到第一个8的倍数,因为一个字节是8位,为了方便查找
    size_t bytes = (bits + 7) / 8;
    bits = bytes * 8;
	
	// 获取原有string的大小,resize是调整大小,新增的bytes部分置0,最后一个字节放k
	// 可以看出,一个string装了多个bit数组
    const size_t init_size = dst->size();
    dst->resize(init_size + bytes, 0);
    dst->push_back(static_cast<char>(k_));  // Remember # of probes in filter
    
    // (*dst)[init_size]是刚刚新增加内容的首个元素,用一个指针array指向它,这样就可以通过
    // array来改变string即bit数组的内容了
    char* array = &(*dst)[init_size];
    for (int i = 0; i < n; i++) {
      // 获取元素的哈希值
      uint32_t h = BloomHash(keys[i]);
      const uint32_t delta = (h >> 17) | (h << 15);  // Rotate right 17 bits
      for (size_t j = 0; j < k_; j++) {
        const uint32_t bitpos = h % bits;
        // bitpos/8代表在第几个字节中(char占一个字节),bitpos%8代表在这个字节中的第几位
        array[bitpos / 8] |= (1 << (bitpos % 8));
        // 每次改变这个哈希值,就像用了k个哈希函数一样
        h += delta;
      }
    }
}
bool KeyMayMatch(const Slice& key, const Slice& bloom_filter) const override {
    const size_t len = bloom_filter.size();
    if (len < 2) return false;

    const char* array = bloom_filter.data();
    // len包括了最后一个k的,所以减1
    const size_t bits = (len - 1) * 8;

    // 获取哈希函数个数
    const size_t k = array[len - 1];
    if (k > 30) {
      // Reserved for potentially new encodings for short bloom filters.
      // Consider it a match.
      return true;
    }
	// 映射的方法和插入一样
    uint32_t h = BloomHash(key);
    const uint32_t delta = (h >> 17) | (h << 15);  // Rotate right 17 bits
    for (size_t j = 0; j < k; j++) {
      const uint32_t bitpos = h % bits;
      // 哈希映射到的那一位不为1
      if ((array[bitpos / 8] & (1 << (bitpos % 8))) == 0) return false;
      h += delta;
    }
    return true;
  }
TO_DO
  • delta设置为循环右移17位有什么讲究?
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值