从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
相关文章:

进程、线程、多线程相关总结
进程、线程、多线程相关总结 一、说说概念 1、进程(process) 狭义定义:进程就是一段程序的执行过程。 广义定义:进程是一个程序关于某个数据集合的一次运行。它是操作系统动态执行的基本单元,在传统的操作系统中&#…

Java项目:在线蛋糕商城系统(java+jsp+jdbc+mysql)
源码获取:博客首页 "资源" 里下载! 一、项目简述 功能: 主页显示热销商品;所有蛋糕商品展示,可进行商品搜 索;点击商品进入商品详情页,具有立即购买和加入购物 车功能,可…

业界对生成图片缩略图的做法归纳
网站如果有很多用户上传图片(相册,商品图片),一般的做法是将用户图片保存在磁盘上面(数据库中记录图片的地址)。用户上传的时候按照原图、中图、小图等各个尺寸都生成一份保存在磁盘上。比如php的网店系统echsop就是这么做的,而shopex之类也大…

thinkPHP5.0 URL路由优化
在tp中访问页面的时候URL地址是 域名/模块/控制器/方法,在点击首页的时候URL是 域名/index/index/index 而不是只显示域名,这样不利于SEO,而且强迫症的我看着很不爽,这个时候我们需要优化路由 Route::rule(路由表达式,路由地址,请…

Rocksdb 获取当前db内部的有效key个数 (估值)
文章目录1. 基本接口2. Memtable key个数统计3. Immutable Memtable key个数统计4. Sstables key个数统计5. 疑问Rocksdb因为是AppendOnly 方式写入,所以没有办法提供db内部唯一key个数的接口(可能存在多版本的key,对用户来说只有一个userkey…

Java项目:网上花店商城系统(java+jsp+servlert+mysql+ajax)
源码获取:博客首页 "资源" 里下载! 一、项目简述 功能: 一套完整的网上花店商场系统,系统支持前台会员的注册 登陆系统留言,花朵的品种选择,详情浏览,加入购物 车,购买花…

使用Uboot启动内核并挂载NFS根文件系统
配置编译好内核之后,将生成的内核文件uImage拷贝到/tftpboot/下,通过tftp服务器将内核下载到开发板,使用命令:tftp 31000000 uImage.下载完成之后配置bootargs环境变量:setenv bootargs noinitrd consolettySAC0,11520…

Centos系统上安装php遇到的错误解决方法集锦
Centos系统上安装php遇到的错误解决方法集锦1.configure: error: xml2-config not found. Please check your libxml2 installationyum install libxml2 libxml2-devel2.configure: error: Cannot find OpenSSL’s yum install openssl openssl-devel3.configure: error: Pleas…

2.27 MapReduce Shuffle过程如何在Job中进行设置
一、shuffle过程 总的来说: *分区 partitioner*排序 sort*copy (用户无法干涉) 拷贝*分组 group可设置 *压缩 compress*combiner map task端的Reduce二、示例 package com.ibeifeng.hadoop.senior.mapreduce;import java.io.IOException; import java.util.StringTo…

Rocksdb Slice使用中的一个小坑
本文记录一下使用Rocksdb Slice过程中的一个小小坑,差点没一口老血吐出来。 rocksdb的Slice 数据结构是一个小型得不可变类string数据结构,设计出来的目的是为了保证rocksdb内部处理用户输入的key在从内存到持久化磁盘的整个处理链路是不会被修改的&…

Java项目:仿天猫网上商城项目(java+jsp+servlet+mysql+ajax)
源码获取:博客首页 "资源" 里下载! 一、项目简述 功能: 前台: * 用户模块 * 分类模块 * 商品模块 * 购物车模块 * 订单模块 后台: * 管理员模块 * 分类管理模块 * 商品管理模块 * 订单模块…

转--Android如何在java代码中设置margin
3 在Java代码里设置button的margin(外边距)? 1、获取按钮的LayoutParams LinearLayout.LayoutParams layoutParams (LinearLayout.LayoutParams)button.getLayoutParams(); 2、在LayoutParams中设置margin layoutParams.setMargins(100,20,10,5);//4个参数按顺序分…

poj12月其他题解(未完)
最近编程的时间比较少啊…… poj3253 就是个合并果子,各种优先队列即可(显然单调队列最优) poj3263 线段树统计每个点被覆盖了多少次即可,注意要去重 poj3625 最小生成树 poj3626 bfs poj3624 01背包 poj3615 floyd即可 poj3278 简…

0409-0416的笔记
1 获取前几天,近几个月的时间 function getDay(day) {var today new Date();var targetday_milliseconds today.getTime() 1000 * 60 * 60 * 24 * day;today.setTime(targetday_milliseconds); //注意,这行是关键代码var tYear today.getFullYear();…

Linux NUMA 架构 :基础软件工程师需要知道一些知识
文章目录前言从物理CPU、core到HT(hyper-threading)UMA(Uniform memory access)NUMA架构NUMA下的内存分配策略1. MPOL_DEFAULT2. MPOL_BIND3. MPOL_INTERLEAVE4. MPOL_PREFERRED5. 一些NUMA架构下的内核配置总结参考前言 NUMA(Non-Uniform m…

Java项目:网上书城+后台管理系统(java+jsp+servlert+mysql+ajax)
源码获取:博客首页 "资源" 里下载! 一、项目简述(附带IW文档) 功能: 前台: * 用户模块 * 分类模块 * 图书模块 * 购物车模块 * 订单模块 后台: * 管理员模块 * 分类管理模块 * 图书管理模块 * 订单模块 …

java.util.concurrent包API学习笔记
newFixedThreadPool 创建一个固定大小的线程池。 shutdown():用于关闭启动线程,如果不调用该语句,jvm不会关闭。 awaitTermination():用于等待子线程结束,再继续执行下面的代码。该例中我设置一直等着子线程结束。Java…

oracle读书记录
很久没有关注自己怕博客了,差不多有两年了。虽然这两年来一直关注51CTO,每天上班打开电脑或者周末在家开启电脑的时候都会浏览一下,这已经是习惯了,但是把自己的blog给忘了。今天,周末,2013年12月21日,同往…

输入、方法的运用
/ /猜数游戏,编写一个功能,完成猜数游戏,产生一个1~10之间的随机数 //与输入的数对对比,返回结果 猜中和没猜中 import java.util.Scanner; //引入(输入)的util包Scanner public class HelloWorld { public static void main(String[] args) {System…

Rocksdb 利用recycle_log_file_num 重用wal-log文件
recycle_log_file_num 复用wal文件信息, 优化wal文件的空间分配,减少pagecache中文件元信息的更新开销。 为同事提供了一组rocksdb写优化参数之后有一个疑惑的现象被问到,发现之前的一些代码细节有遗忘情况,同时也发现了这个参数…

Java项目:网上商城系统(java+jsp+servlert+mysql+ajax)
源码获取:博客首页 "资源" 里下载! 一、项目简述(需求文档PPT) 功能: 主页显示热销商品;所有商品展示,可进行商品搜索;点 击商品进入商品详情页,显示库存&…

clock函数返回负值~ (转)
使用clock() 函数来进行计时,时不时的返回一个很大的负数,怎么检查也检查不出错误,现在找出错误原因,给大家分享一下。 来源网页:http://kebe-jea.blogbus.com/logs/33603387.html 跑实验的时候,结果时不时…

c实现面向对象编程(3)
http://blog.csdn.net/kennyrose/article/details/7564105转载于:https://www.cnblogs.com/pengkunfan/p/3486612.html

echarts - 条形图grid设置距离绘图区域的距离
在一些数据量过大的情况下,在一个固定的区域绘图往往需要对图表绘制区域的大小进行动态改变。这时候设置条形图距离绘图区域上下左右的距离可使用如下方式:表示条形图的柱子距离绘图区左边30%,距离右边40%,而距离顶部和底部分别为…

TitanDB 中使用Compaction Filter ,产生了预期之外几十倍的读I/O
Compaction过程中 产生大量读I/O 的背景 项目中因大value 需求,引入了PingCap 参考Wisckey 思想实现的key-value分离存储 titan, 使用过程中因为有用到Rocksdb本身的 CompactionFilter功能,所以就直接用TitanDB的option 传入了compaction fi…

Java项目:前台+后台精品图书管理系统(java+SSM+jsp+mysql+maven)
源码获取:博客首页 "资源" 里下载! 一、项目简述 功能包括: 登录注册,办理借阅。借阅记录,预约借阅,借出未还, 借阅逾期,学生管理,图书管理,书库分类查询搜索…

消除 activity 启动时白屏、黑屏问题
默认情况下 activity 启动的时候先把屏幕刷成白色,再绘制界面,绘制界面或多或少有点延迟,这段时间中你看到的就是白屏,显然影响用户体验,怎么消除呢? 在 Activity theme 设置style 即可 1 <style na…

理解并实施:HSRP(CCNA200-120新增考点)
理解并实施:HSRP思科热备路由器协议HSRP(HotStandby Router Protocol)是企业级网络路由器的故障冗余服务。如图9.116所示,192.168.2.0/24的子网需要与目标192.168.5.2的计算机通信。192.168.2.0/24的子网有两台出口路由器,一台是R…

使用机智云APP控制战舰V3 (转)
源:使用机智云APP控制战舰V3 转载于:https://www.cnblogs.com/LittleTiger/p/10725586.html

从JoinBatchGroup 代码细节 来看Rocksdb的相比于leveldb的写入优势
文章目录1. Rocksdb写入模型2. LevelDB写入的优化点3. Rocksdb 的优化1. Busy Loop2. Short Wait -- SOMETIMES busy Loop3. Long-wait4. 测试验证4. 总结1. Rocksdb写入模型 本节讨论一下Rocksdb在写入链路上的一个优化点,这个优化细节可以说将Rocksdb这个存储引擎…