文章目录

  • 前言
  • 1. Traditional BloomFilter
  • 2. Counter BloomFilter

本文traditional bloomfilter 和 counter bloomfilter的C++实现 均已上传至:
https://github.com/BaronStack/BloomFilter

前言

Bloomfilter 是一个老生常谈的数据结构,应用在存储领域的各个系统之中,用来准确判断一个字符串是否不存在,高效判断一个字符串是否存在,有容错率

详细描述和代码实现均已上传至github中,本文简单描述一下原理和关键代码。

1. Traditional BloomFilter

传统的BloomFilter实现 就是针对输入的一个字符串列表 作为我们的数据集。
对其中的每一个字符串 通过一个或者多个hash函数生成一个唯一的hash值,将这个值映射到bloomfilter上,把bloomfilter维护的一个bit序列相关的bit位置1。

如下 bloom filter维护的一个bit序列:

第一个string 通过hash 函数 生成的hash值,映射到bloomfilter的三个bit位中,将对应的bit位置1

第二个string 通过同样的hash函数生成一个唯一的hash值,映射到同一个bloomfilter的bit位中,已经为1的就不用置位了

依此,后续的字符串在构造bloom filter的时候都通过如上方式来构造,这样一个数据集只需要完成一次构造。

后续拿着构造好的bit序列来检测输入的string,只需要通过hash函数拿到hash值就能够 通过O(1)的时间(位运算)精确匹配这个输入的string不存在(hash值映射的bit位为0,说明肯定不存在,存在的话之前通过hash值映射的就为1)。

看看如下代码 构造bloomfilter :

// CreateFilter:根据输入的key 批量构建bloom filter
// 参数1: keys, 输入的需要构造成bloomfilter的string列表
// 参数2: n,输入的元素个数
// 参数3: dst 最终的bloomfilter结果
//
// 这里的构造逻辑是通过双hash算法实现的,
// 针对输入的string 先生成一个uint32_t 的hash值
// 再针对其中的num_probe_个bit位进行置1
void BloomFilter::CreateFilter(std::string* keys,int n, std::string *dst ) {size_t bits = n * bits_per_key_; // bits_pter_key_表示需要维护的bloomfilter的位数if(bits < 64) {bits = 64;}size_t bytes = (bits + 7) / 8;bits = bytes * 8;const size_t init_size = dst->size();dst->resize(init_size + bytes, 0);dst->push_back(static_cast<char>(num_probe_));  // Remember # of probeschar* array = &(*dst)[init_size];// Use double-hashing to generate a sequence of hash values.// 这里使用双hash算法来生成hash值// See analysis in [Kirsch,Mitzenmacher 2006].for(size_t i = 0;i < static_cast<size_t>(n); i++) {uint32_t h = hash_func_(keys[i]);const uint32_t delta = (h >> 17) | (h << 15);for (size_t j = 0; j < num_probe_; j++) {const uint32_t bitpos = h % bits;array[bitpos/8] |= (1 << (bitpos % 8)); // 将bitpos位置置为1h += delta;}}
}

通过如上构造的bloomfilter 来匹配对应的key,输入的key是否存在于bloomfilter之中

// 检查输入的key 是否存在于构造的bloom filter 之中
bool BloomFilter::KeyMayMatch(std::string key, std::string& bloom_filter){const size_t len = bloom_filter.size();if (len < 2) return false;const char* array = bloom_filter.c_str();const size_t bits = (len - 1) * 8;// Use the encoded k so that we can read filters generated by// bloom filters created using different parameters.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 = hash_func_(key);const uint32_t delta = (h >> 17) | (h << 15);for (size_t j = 0; j < k; j++) {const uint32_t bitpos = h % bits;if ((array[bitpos/8] & (1 << (bitpos % 8))) == 0) return false;h += delta;}return true;
}

2. Counter BloomFilter

Counter Blooomfilter的应用场景是 我们想要动态变更构造好的bloomfilter,比如从bloomfilter中删除一个key的映射。这样我们之前说的traditional bloomfilter的设计就无法实现了,毕竟bit只有一个值,且可能被多个key的hash映射公用。

这个时候可以维护一个counter(下面的代码是一个uint32_t的数值表示上面traditional的bit位,当然也可以uint8_t),按照之前的方式来构造,对每一个输入的key生成一个hash值, 这个hash值映射到bloomfilter之上,让对应的"bit"位自增即可。删除其中的key映射的时候,可以让对应的bit位自减少。

输入第一个string时保持各个bit位为1

当输入第二个时,string的hash值映射到同一个bit,则让bit位数值++即可:

后续的字符串构造过程中类似,也是针对匹配的’bit’位自增即可:

构造过程的实现代码如下:

// CreateCounterFilter: 创建一个计数功能的bloomfilter
// 参数1:keys ,输入多个string类型 的字符串
// 参数2: n, 输入的字符串串长度
// 参数3: 根据输入的字符串构造出来的计数bloom filter
//
// 原理如下:
// 维护一个uint32_t 的数组,其中每一个元素代表一个bit位
// 0 0 0 0 0 ... 0 0 0
//
// add string1 --> hash_func
//          |
//          |
// 0 1 0 1 1 ... 1 0 0
//
// add string2 --> hash_func
//          |
//          |
// 1 2 1 1 2 ... 1 0 1
//
// 如果想要从构造的bloom filter中删除string1,则只需要让hash_func
// 的对应 "bit" 位的数值-1 即可
// remove string1 --> hash_func
//          |
//          |
// 1 1 1 0 1 ... 0 0 1
void CounterFilter::CreateCounterFilter(std::string* keys, int n,vector<uint32_t> *dst) {size_t bits = n* bits_per_key_;// 构造一个存放 uint32_t的bloomfilter数组 -- dstif(bits < 32) {bits = 32;}size_t bytes = (bits + 7) / 8;bits = bytes * 8;const size_t init_size = dst->size();dst->resize(bits, 0);uint32_t* array = &(*dst)[init_size];for(size_t i = 0;i < static_cast<size_t>(n); i++) {uint32_t h = hash_func_(keys[i]);vector<BITTYPE> bit_types;Bitcount(h, &bit_types);for(size_t j = 0; j < bit_types.size(); j++) {if(bit_types[j].is1) {array[bit_types[j].bit_pos] ++;}}}
}

需要注意的是Counter bloomfilter需要针对每一个bit位用更多的字节表示,所以Counter Bloomfilter会消耗更多的内存。

相关代码完整实现均已上传至:
https://github.com/BaronStack/BloomFilter

从BloomFilter到Counter BloomFilter相关推荐

  1. Redis 高级主题之布隆过滤器(BloomFilter)

    最近计划准备整理几篇关于Reids高级主题的博文,本文整理的是关于布隆过滤器在Redis中如何应用,先来一张思维导图浏览全文. 1. 认识BloomFilter 1.1 原理 布隆过滤器,英文叫Blo ...

  2. 网络爬虫:URL去重策略之布隆过滤器(BloomFilter)的使用

    前言: 最近被网络爬虫中的去重策略所困扰.使用一些其他的"理想"的去重策略,不过在运行过程中总是会不太听话.不过当我发现了BloomFilter这个东西的时候,的确,这里是我目前找 ...

  3. 谷歌guava_Google Guava BloomFilter

    谷歌guava 当Guava项目发布版本11.0时,新添加的功能之一是BloomFilter类. BloomFilter是唯一的数据结构,用于指示元素是否包含在集合中. 使BloomFilter有趣的 ...

  4. Google Guava BloomFilter

    当Guava项目发布版本11.0时,新添加的功能之一是BloomFilter类. BloomFilter是唯一的数据结构,用于指示元素是否包含在集合中. 使BloomFilter有趣的是,它将指示元素 ...

  5. 【算法】BloomFilter 如何判断一个元素在亿级数据中是否存在?

    1.概述 转载: 如何判断一个元素在亿级数据中是否存在? 前言 最近有朋友问我这么一个面试题目: 现在有一个非常庞大的数据,假设全是 int 类型.现在我给你一个数,你需要告诉我它是否存在其中(尽量高 ...

  6. 【算法】BloomFilter 与 CuckooFilter

    自定义 基于Redis的BloomFilter实现 http://lxw1234.com/archives/2015/12/580.htm https://www.cnblogs.com/z94103 ...

  7. BloomFilter原理学习

    文章目录 BloomFilter简单介绍 BloomFilter中的数学知识 fpp(误判率/假阳性)的计算 k的最小值 公式总结 各方实现 golang [已知n, p求m和k](https://g ...

  8. bloomFilter和哈希函数murmur3

    Murmur哈希算法是一种非加密hash算法,适用于哈希查找. 优点是时间和空间消耗较少,可检索一个元素是否在集合中 缺点是误识别率和删除困难 bloomFilter原理 ​ 元素被加入集合时,选择k ...

  9. 【数据结构】布隆过滤器:BloomFilter原理及Java实现

    布隆过滤器(Bloom Filter)是一个叫做 Bloom 的大佬在1970年提出的.我们可以把它看做由二进制向量(或者说数组)和一系列随机映射函数(哈希函数)两部分组成的数据结构.相比于我们平时用 ...

最新文章

  1. wikioi 3027 线段覆盖 2
  2. tcp/ip 协议栈Linux内核源码分析13 udp套接字发送流程二
  3. 强大的PHP防SQL注入类,可以过滤敏感参数
  4. JVM_04 对象的实例化+内存布局+访问定位+直接内存
  5. python3 object_detection_demo_yolov3_async.py出现ImportError: numpy.core.multiarray failed to import
  6. linux 连接wifi wpa2,RHEL等Linux系统使用wpa_supplicant以WPA-PSK/WPA2-PSK连接WIFI
  7. 详尽kmp_详尽的分步指南,用于数据准备
  8. 训练数据的分布对F-measure, recall 和 precision的影响
  9. jq之hide(1000)
  10. Flashdevelop解决ANE报Not supported native extensions profile
  11. DataSet运用DES加解密到Xml
  12. 关于mpvue 切换页面数据没清空
  13. 交换机通过port-channel互联
  14. D盘下的 msdia80.dll 怎么处理?
  15. 混合动力hev汽车控制模型 simulink stateflow搭建 电机 电池 发动机 模型 动力分配 能量控制策略 及 经济性仿真测试。
  16. 数据结构——克鲁斯卡尔(Kruskal)算法
  17. linux环境开启kettle Carte
  18. 解决Maven打包报错:Failed to clean project: Failed to delete
  19. 小米5c android7.0,小米5C推送安卓7.1:系统更流畅,联通信号更稳定
  20. 没有灵感头发都快抓掉了!推荐几款创意网站,让大脑灵光一动!

热门文章

  1. 利用“哨兵”“实现双链表
  2. linux安装vsftpt服务,centos安装vsftp服务.md
  3. fcm算法的MATLAB实现,FCM算法的matlab程序(初步)
  4. xml放在工程的那个路径下_Ubuntu下配置pyrouge
  5. java 证件识别_证件识别接口JAVA调用示例
  6. 服务器主机防御系统,主机入侵防御系统
  7. python如何保存列表_Python 基础知识全篇-列表(Lists)
  8. python打印万年历_python青苔计划(六)打印万年历
  9. 刚进入大学觉得计算机课很难,高校代码条幅迎新生,00后表示刚开学就感受到秃头压力!程序员太难了...
  10. ndk 不用java_使用NDK创建及配置C++程序(原生纯C++项目,不包含JAVA代码)