原文链接:http://blog.csdn.net/qq_38646470/article/details/79431659

1.概念:

如果想判断一个元素是不是在一个集合里,一般想到的是将所有元素保存起来,然后通过比较确定。链表,树等等数据结构都是这种思路. 但是随着集合中元素的增加,我们需要的存储空间越来越大,检索速度也越来越慢。不过世界上还有一种叫作散列表(又叫哈希表,Hash table)的数据结构。它可以通过一个Hash函数将一个元素映射成一个位阵列(Bit Array)中的一个点。这样一来,我们只要看看这个点是不是 1 就知道可以集合中有没有它了。这就是布隆过滤器的基本思想。

它的优点是空间效率和查询时间都远远超过一般的算法,缺点是有一定的误识别率(假正例False positives,即Bloom Filter报告某一元素存在于某集合中,但是实际上该元素并不在集合中)和删除困难,但是没有识别错误的情形(即假反例False negatives,如果某个元素确实没有在该集合中,那么Bloom Filter 是不会报告该元素存在于集合中的,所以不会漏报)。

2.实现原理:

直观的说,bloom算法类似一个hash set,用来判断某个元素(key)是否在某个集合中。和一般的hash set不同的是,这个算法无需存储key的值,对于每个key,只需要k个比特位,每个存储一个标志,用来判断key是否在集合中。

算法:

1). 首先需要k个hash函数,每个函数可以把key散列成为1个整数

2). 初始化时,需要一个长度为range比特的数组,每个比特位初始化为0

3). 某个key加入集合时,用k个hash函数计算出k个散列值,并把数组中对应的比特位置为1

4). 判断某个key是否在集合时,用k个hash函数计算出k个散列值,并查询数组中对应的比特位,如果所有的比特位都是1,认为在集合中。

3.代码实现:

采用3个hash函数计算散列值。

布隆结构设计:

typedef char* KeyType;

typedef size_t(*HASH_FUNC)(KeyType str);

typedef struct BloomFilter
{
BitMap _bm;
HASH_FUNC _Hashfunc1;
HASH_FUNC _Hashfunc2;
HASH_FUNC _Hashfunc3;
}BloomFilter;

hash函数:

static size_t BKDRHash(KeyType str)
{
unsigned int seed = 131; // 31 131 1313 13131 131313
unsigned int hash = 0;
while (*str )
{
hash = hash * seed + (*str++);
}
return (hash & 0x7FFFFFFF);
} size_t DEKHash(KeyType str)
{
if(!*str) // 这是由本人添加,以保证空字符串返回哈希值0
return 0;
register size_t hash = 1315423911;
while (size_t ch = (size_t)*str++)
{
hash = ((hash << 5) ^ (hash >> 27)) ^ ch;
}
return hash;
} size_t FNVHash(KeyType str)
{
if(!*str) // 这是由本人添加,以保证空字符串返回哈希值0
return 0;
register size_t hash = 2166136261;
while (size_t ch = (size_t)*str++)
{
hash *= 16777619;
hash ^= ch;
}
return hash;
}

bloom算法实现函数:

void BloomFilterInit(BloomFilter *bf,size_t range) //初始化
{
BitMapInit(&bf->_bm,range);
bf->_Hashfunc1 = BKDRHash;
bf->_Hashfunc2 = FNVHash;
bf->_Hashfunc3 = DEKHash;
} void BloomFilterSet(BloomFilter *bf,KeyType key)//标记相应位
{
assert(bf);
BitMapSet(&bf->_bm,bf->_Hashfunc1(key)%bf->_bm._range);
BitMapSet(&bf->_bm,bf->_Hashfunc2(key)%bf->_bm._range);
BitMapSet(&bf->_bm,bf->_Hashfunc3(key)%bf->_bm._range);
} int BloomFilterTest(BloomFilter *bf,KeyType key)
{
assert(bf);
if (BitMapTest(&bf->_bm,bf->_Hashfunc1(key)%bf->_bm._range))
return -1;
if (BitMapTest(&bf->_bm,bf->_Hashfunc2(key)%bf->_bm._range))
return -1;
if (BitMapTest(&bf->_bm,bf->_Hashfunc3(key)%bf->_bm._range))
return -1; return 0;
} void BloomFilterDestory(BloomFilter *bf) //销毁
{
BitMapDestory(&bf->_bm);
}

算法测试案例及运行结果:

void TestBlooomFilter()
{
BloomFilter bf;
BloomFilterInit(&bf,-1);
BloomFilterSet(&bf,"123.5.3.6");
BloomFilterSet(&bf,"123.5.3.8");
BloomFilterSet(&bf,"123.5.3.6");
BloomFilterSet(&bf,"123.5.3.7");
BloomFilterSet(&bf,"123.5.3.4");
BloomFilterSet(&bf,"123.5.3.6");
BloomFilterSet(&bf,"123.5.3.8");
BloomFilterSet(&bf,"123.5.3.8");
BloomFilterSet(&bf,"123.5.3.6"); printf("ip is exist? %d\n",BloomFilterTest(&bf,"123.5.3.6"));
printf("ip is exist? %d\n",BloomFilterTest(&bf,"123.5.3.7"));
printf("ip is exist? %d\n",BloomFilterTest(&bf,"123.5.3.8"));
printf("ip is exist? %d\n",BloomFilterTest(&bf,"123.5.3.4"));
printf("ip is exist? %d\n",BloomFilterTest(&bf,"123.5.3.1")); BloomFilterDestory(&bf); }

0 代表存在 ,-1代表不存在。

代码中调用了位图相关函数代码: 位图相关部分知识在上篇博文中有详细解释。

#define _CRT_SECURE_NO_WARNINGS 1

#include"BitMap.h"

void BitMapInit(BitMap *bm,size_t range) //初始化
{
assert(bm);
bm->_bits = NULL;
bm->_range = range;
bm->_bits = (size_t *)malloc(sizeof(char)*bm->_range/8 +1);
assert(bm->_bits);
memset(bm->_bits,0,sizeof(char)*bm->_range/8 +1);
} void BitMapSet(BitMap *bm,size_t x)//标记相应位
{
size_t num = x>>5;
size_t bit = x%32; bm->_bits[num] |=(1<<bit);
} int BitMapTest(BitMap *bm,size_t x)
{
size_t num = x>>5;
size_t bit = x%32; if ((1<<bit)&bm->_bits[num])
return 0;
return -1;
} void BitMapDestory(BitMap *bm)
{
free(bm->_bits);
bm->_bits = NULL;
bm->_range = 0;
}

4.布隆过滤器的实际用例[1]

Google 著名的分布式数据库 Bigtable 使用了布隆过滤器来查找不存在的行或列,以减少磁盘查找的IO次数。

Squid 网页代理缓存服务器在 cache digests 中使用了也布隆过滤器。

Venti 文档存储系统也采用布隆过滤器来检测先前存储的数据。

SPIN 模型检测器也使用布隆过滤器在大规模验证问题时跟踪可达状态空间。

Google Chrome浏览器使用了布隆过滤器加速安全浏览服务。

在很多Key-Value系统中也使用了布隆过滤器来加快查询过程,如 Hbase,Accumulo,eveldb,一般而言,Value 保存在磁盘中,访问磁盘需要花费大量时间,然而使用布隆过滤器可以快速判断某个Key对应的Value是否存在,因此可以避免很多不必要的磁盘IO操作,只是引入布隆过滤器会带来一定的内存消耗,下图是在Key-Value系统中布隆过滤器的典型使用:



5.布隆过滤器相关扩展[1]

Counting filters

基本的布隆过滤器不支持删除(Deletion)操作,但是 Counting filters 提供了一种可以不用重新构建布隆过滤器但却支持元素删除操作的方法。在Counting filters中原来的位数组中的每一位由 bit 扩展为 n-bit 计数器,实际上,基本的布隆过滤器可以看作是只有一位的计数器的Counting filters。原来的插入操作也被扩展为把 n-bit 的位计数器加1,查找操作即检查位数组非零即可,而删除操作定义为把位数组的相应位减1,但是该方法也有位的算术溢出问题,即某一位在多次删除操作后可能变成负值,所以位数组大小 m 需要充分大。另外一个问题是Counting filters不具备伸缩性,由于Counting filters不能扩展,所以需要保存的最大的元素个数需要提前知道。否则一旦插入的元素个数超过了位数组的容量,false positive的发生概率将会急剧增加。当然也有人提出了一种基于 D-left Hash 方法实现支持删除操作的布隆过滤器,同时空间效率也比Counting filters高。

Data synchronization

Byers等人提出了使用布隆过滤器近似数据同步。

Bloomier filters

Chazelle 等人提出了一个通用的布隆过滤器,该布隆过滤器可以将某一值与每个已经插入的元素关联起来,并实现了一个关联数组Map。与普通的布隆过滤器一样,Chazelle实现的布隆过滤器也可以达到较低的空间消耗,但同时也会产生false positive,不过,在Bloomier filter中,某 key 如果不在 map 中,false positive在会返回时会被定义出的。该Map 结构不会返回与 key 相关的在 map 中的错误的值。

参考资料

[1] https://www.cnblogs.com/liyulong1982/p/6013002.html

BloomFilter(布隆过滤器)的更多相关文章

  1. 第三百五十八节,Python分布式爬虫打造搜索引擎Scrapy精讲—将bloomfilter(布隆过滤器)集成到scrapy-redis中

    第三百五十八节,Python分布式爬虫打造搜索引擎Scrapy精讲—将bloomfilter(布隆过滤器)集成到scrapy-redis中,判断URL是否重复 布隆过滤器(Bloom Filter)详 ...

  2. 三十七 Python分布式爬虫打造搜索引擎Scrapy精讲—将bloomfilter(布隆过滤器)集成到scrapy-redis中

    Python分布式爬虫打造搜索引擎Scrapy精讲—将bloomfilter(布隆过滤器)集成到scrapy-redis中,判断URL是否重复 布隆过滤器(Bloom Filter)详解 基本概念 如 ...

  3. 将bloomfilter(布隆过滤器)集成到scrapy-redis中

    Python分布式爬虫打造搜索引擎Scrapy精讲—将bloomfilter(布隆过滤器)集成到scrapy-redis中,判断URL是否重复 布隆过滤器(Bloom Filter)详解 基本概念 如 ...

  4. BloomFilter布隆过滤器

    BloomFilter 简介 当一个元素被加入集合时,通过K个散列函数将这个元素映射成一个位数组中的K个点,把它们置为1.检索时,我们只要看看这些点是不是都是1就(大约)知道集合中有没有它了:如果这些 ...

  5. BloomFilter布隆过滤器使用

    从上一篇可以得知,BloomFilter的关键在于hash算法的设定和bit数组的大小确定,通过权衡得到一个错误概率可以接受的结果. 算法比较复杂,也不是我们研究的范畴,我们直接使用已有的实现. go ...

  6. 使用BloomFilter布隆过滤器解决缓存击穿、垃圾邮件识别、集合判重

    Bloom Filter是一个占用空间很小.效率很高的随机数据结构,它由一个bit数组和一组Hash算法构成.可用于判断一个元素是否在一个集合中,查询效率很高(1-N,最优能逼近于1). 在很多场景下 ...

  7. 白话布隆过滤器BloomFilter

    通过本文将了解到以下内容: 查找问题的一般思路 布隆过滤器的基本原理 布隆过滤器的典型应用 布隆过滤器的工程实现 场景说明: 本文阐述的场景均为普通单机服务器.并非分布式大数据平台,因为在大数据平台下 ...

  8. 布隆过滤器(BloomFilter)持久化

    摘要 Bloomfilter运行在一台机器的内存上,不方便持久化(机器down掉就什么都没啦),也不方便分布式程序的统一去重.我们可以将数据进行持久化,这样就克服了down机的问题,常见的持久化方法包 ...

  9. HBase之八--(3):Hbase 布隆过滤器BloomFilter介绍

    布隆过滤器( Bloom filters) 数据块索引提供了一个有效的方法,在访问一个特定的行时用来查找应该读取的HFile的数据块.但是它的效用是有限的.HFile数据块的默认大小是64KB,这个大 ...

随机推荐

  1. MS SQL 模仿ORACLE的DESC

    前言: 在ORACLE数据库的SQL*PLUS里面有个DES(DESCRIBE)命令,它可以返回数据库所存储对象的描述,如下所示 SQL> DESC STUDENT_SCORE   Name T ...

  2. struts2 添加请求后缀的3种方式

    第一种方式在struts.xml文件中添加 <constant name="struts.action.extension" value="">&l ...

  3. 号外号外!解决github+hexo+yilia评论插件的问题!!!

    先走一波效果图!    本人网站--http://www.wenzheng.club/ ps:效果还是不错的,支持QQ微信登录,支持表情,甚至gif动图评论! 插件采用韩国服务器的来必力评论插件--h ...

  4. 02_HTML5+CSS详解第一天

    视频来源:麦子学院 讲师:朱朝兵 HTML5概念:HTML即超文本标记语言(HyperText Makeup Language),是一种语法简单,结构清晰的解释型文档,不同于其他编程语言. HTML5 ...

  5. CentOS7修改主机名(hostname)

    Linux中的hostname在大多数应用中至为重要,例如有些应用强制使用主机名称而不能使用IP地址,如果默认主机名称都为localhost.localdomain 的话那一定会出现问题,而且看起来也 ...

  6. AngularJS执行流程详解(转)

    一.启动阶段 大家应该都知道,当浏览器加载一个HTML页面时,它会将HMTL页面先解析成DOM树,然后逐个加载DOM树中的每一个元素节点.我们可以把AngularJS当做一个类似jQuery的js库, ...

  7. js函数知识

    1.函数基本知识 通过函数可以封装任意条语句,在任何地方调用,js中用function关键字来声明, //基本格式,函数名,传递参数,代码块 function functionName(arg0,ar ...

  8. https原理及实践

    转载请注明出处 安全知识 网络安全问题 数据机密性 在网络传输数据信息时,对数据的加密是至关重要的,否则所有传输的数据都是可以随时被第三方看到,完全没有机密性可言. 数据机密性解决问题思路 利用算法 ...

  9. 18_Python列表常用方法总结

    ''' 1.列表切片索引\截取 2.列表的增删改查 3.列表最大值\列表最小值\排序 4.列表的遍历 5.列表的嵌套 6.列表和字符串的互转 7.判断元素是否在列表中 ''' #列表使用中括号表示 元 ...

  10. python的组合数据类型及其内置方法说明

    python中,数据结构是通过某种方式(例如对元素进行编号),组织在一起数据结构的集合. python常用的组合数据类型有:序列类型,集合类型和映射类型 在序列类型中,又可以分为列表和元组,字符串也属 ...