从BloomFilter到Counter BloomFilter
文章目录
- 前言
- 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相关推荐
- Redis 高级主题之布隆过滤器(BloomFilter)
最近计划准备整理几篇关于Reids高级主题的博文,本文整理的是关于布隆过滤器在Redis中如何应用,先来一张思维导图浏览全文. 1. 认识BloomFilter 1.1 原理 布隆过滤器,英文叫Blo ...
- 网络爬虫:URL去重策略之布隆过滤器(BloomFilter)的使用
前言: 最近被网络爬虫中的去重策略所困扰.使用一些其他的"理想"的去重策略,不过在运行过程中总是会不太听话.不过当我发现了BloomFilter这个东西的时候,的确,这里是我目前找 ...
- 谷歌guava_Google Guava BloomFilter
谷歌guava 当Guava项目发布版本11.0时,新添加的功能之一是BloomFilter类. BloomFilter是唯一的数据结构,用于指示元素是否包含在集合中. 使BloomFilter有趣的 ...
- Google Guava BloomFilter
当Guava项目发布版本11.0时,新添加的功能之一是BloomFilter类. BloomFilter是唯一的数据结构,用于指示元素是否包含在集合中. 使BloomFilter有趣的是,它将指示元素 ...
- 【算法】BloomFilter 如何判断一个元素在亿级数据中是否存在?
1.概述 转载: 如何判断一个元素在亿级数据中是否存在? 前言 最近有朋友问我这么一个面试题目: 现在有一个非常庞大的数据,假设全是 int 类型.现在我给你一个数,你需要告诉我它是否存在其中(尽量高 ...
- 【算法】BloomFilter 与 CuckooFilter
自定义 基于Redis的BloomFilter实现 http://lxw1234.com/archives/2015/12/580.htm https://www.cnblogs.com/z94103 ...
- BloomFilter原理学习
文章目录 BloomFilter简单介绍 BloomFilter中的数学知识 fpp(误判率/假阳性)的计算 k的最小值 公式总结 各方实现 golang [已知n, p求m和k](https://g ...
- bloomFilter和哈希函数murmur3
Murmur哈希算法是一种非加密hash算法,适用于哈希查找. 优点是时间和空间消耗较少,可检索一个元素是否在集合中 缺点是误识别率和删除困难 bloomFilter原理 元素被加入集合时,选择k ...
- 【数据结构】布隆过滤器:BloomFilter原理及Java实现
布隆过滤器(Bloom Filter)是一个叫做 Bloom 的大佬在1970年提出的.我们可以把它看做由二进制向量(或者说数组)和一系列随机映射函数(哈希函数)两部分组成的数据结构.相比于我们平时用 ...
最新文章
- wikioi 3027 线段覆盖 2
- tcp/ip 协议栈Linux内核源码分析13 udp套接字发送流程二
- 强大的PHP防SQL注入类,可以过滤敏感参数
- JVM_04 对象的实例化+内存布局+访问定位+直接内存
- python3 object_detection_demo_yolov3_async.py出现ImportError: numpy.core.multiarray failed to import
- linux 连接wifi wpa2,RHEL等Linux系统使用wpa_supplicant以WPA-PSK/WPA2-PSK连接WIFI
- 详尽kmp_详尽的分步指南,用于数据准备
- 训练数据的分布对F-measure, recall 和 precision的影响
- jq之hide(1000)
- Flashdevelop解决ANE报Not supported native extensions profile
- DataSet运用DES加解密到Xml
- 关于mpvue 切换页面数据没清空
- 交换机通过port-channel互联
- D盘下的 msdia80.dll 怎么处理?
- 混合动力hev汽车控制模型 simulink stateflow搭建 电机 电池 发动机 模型 动力分配 能量控制策略 及 经济性仿真测试。
- 数据结构——克鲁斯卡尔(Kruskal)算法
- linux环境开启kettle Carte
- 解决Maven打包报错:Failed to clean project: Failed to delete
- 小米5c android7.0,小米5C推送安卓7.1:系统更流畅,联通信号更稳定
- 没有灵感头发都快抓掉了!推荐几款创意网站,让大脑灵光一动!
热门文章
- 利用“哨兵”“实现双链表
- linux安装vsftpt服务,centos安装vsftp服务.md
- fcm算法的MATLAB实现,FCM算法的matlab程序(初步)
- xml放在工程的那个路径下_Ubuntu下配置pyrouge
- java 证件识别_证件识别接口JAVA调用示例
- 服务器主机防御系统,主机入侵防御系统
- python如何保存列表_Python 基础知识全篇-列表(Lists)
- python打印万年历_python青苔计划(六)打印万年历
- 刚进入大学觉得计算机课很难,高校代码条幅迎新生,00后表示刚开学就感受到秃头压力!程序员太难了...
- ndk 不用java_使用NDK创建及配置C++程序(原生纯C++项目,不包含JAVA代码)