程序猿回到过去:红花会与布隆过滤器

这是一个台风夜,雨还在下,敲着窗户,叮叮当当。阿智终于写完最后一行代码,合上了笔记本电脑。他看了看时钟,23点56分,他笑着说了一声“今天好早啊”。阿智还没有女朋友,自从做了一名程序猿,每天晚上都是机械键盘的响声陪着他到深夜。偶尔他也觉得这种生活有点苦闷,不过还好不知道从什么时候开始阿智迷上了金庸的武侠小说,每天工作完后他总要看上那么一段时间。沉浸在武侠世界里面的阿智直觉得天地开阔了很多,潇洒而自由。

此刻他又抱着《书剑恩仇录》在看,不过连续几天的熬夜已经让他十分疲惫,看着看着他的意识开始有点模糊。

“猿”来自未来,误闯红花堂

迷迷糊糊地阿智醒来了,耳朵传入一阵一阵人声,像是有一群人在开会。阿智看了下四周,一下惊呆了!他一个人躺在一个庙堂的大厅中间,旁边坐满了一群穿着清代服饰的人,而上首的位置坐着一个仪表堂堂,相貌颇为英俊的公子。这位公子的胸前佩戴着一朵娇艳欲滴的大红花,红花上用宝石点缀着,在烛光的照耀下显得熠熠生辉。阿智再看了一下周围的人,每一个胸前都佩戴这一朵红花。阿智突然感觉眼前的场景有点熟悉,但又好像想不起是为什么。

左边一个人突然站起来,对阿智怒目而视,问道:“你是哪门哪派的人?为何晕倒在我红花会庙堂的花园中?”。此人满面胡渣,手臂粗壮,说话时显得中气颇足。

阿智被吓的一阵哆嗦,慌乱中摸到自己身边有个书包,他打开一看原来是自己的笔记本电脑和机械键盘。“你要拿武器吗?好,那我奔雷手文泰来就跟你比试比试!”那满面胡渣的人一下欺到阿智身前不足一丈的位置。阿智吓得又一个哆嗦,惊声叫到:“什么?我穿越来清朝了?”。此时右手边一个脸带书生气的人站起来对这文泰来道:“三哥且慢,看他不像会武功的人。”,然后转过脸来跟阿智说:“你是什么人,你包里的是什么东西?”

阿智这时终于清醒过来,意识到自己真的穿越到了清朝,并误入了红花会的庙堂。幸好他的《书剑恩仇录》已经看得差不多,里面红花会的人物他全都记得住。他对那书生模样的人说道:“这位是武诸葛,徐天宏?”,那书生模样的人回道:“正是”。阿智于是站起来向大厅中的各人作揖,说道:“各个英雄大家好!我叫阿智,我是生活在离现在几百年后的人,我也不知道自己为什么会来到这里。”。然后阿智边介绍自己从哪里来,边从自己书包里面拿出了电脑和机械键盘。接着演示了一遍电脑和机械键盘的用途以及作用。

阿智说完之后群雄无不惊叹来自未来的武器的厉害,并对阿智的身份渐渐起了信任感。此时一直坐上在上首位置的公子站起来做了一揖说道,“阿智兄台你好。我是红花会总舵主陈家洛。兄台刚说确实令在下惊讶,没想到我们竟然遇上一位来自未来的人。我们红花会目前遇到一个难题,望兄台能帮组我们。”接着陈家洛跟阿智说道红花会当前遇到的问题。

原来红花会正在制作一份清廷贪官污吏的黑名册,用于各自红花会兄弟追捕朝廷狗官。但碍于清廷的狗官成千上万,红花会各位当家觉得管理起来非常困难,而且每次抓到一名可疑的狗官时,总要匹配一遍黑名册,耗时巨大。

阿智听后哈哈大笑:“这不简单!在我们的世时代里面这些问题非常容易解决!请陈总舵主和各位英雄放心。”于是阿智边在电脑上演示,边跟红花会的各位当家讲解自己的解决方案。

红花堂内群雄静,程序猿述布隆法

传统意义上,我们如果需要存储一大的集合,并要判断某个给定的元素是否存在于这一大集合时,我们首先可能会想到利用树、链表、哈希表这样的数据结构来存储这一大批元素集合。但是如果集合越来越大,或者直接是一个非常庞大的集合时,对于树、链表来讲,检索时间会相应增加。对树、链表、哈希表三者来讲,集合越大所需的存储空间也越大。思想试想一下,如果集合是一个巨无霸,其中有上亿的元素时,树、链表、哈希表会需要多少存储空间?这时就需要用到布隆过滤器。

布隆过滤器的概念是在1970年有巴顿.布隆提出的。布隆过滤器实际上是由多个随机散列函数以及一个很长的二进制向量组成,从而实现过滤器的功能。布隆过滤器的空间占用比树、链表、哈希表这样的数据结构少非常多,而检索时间也是非常优秀的。布隆过滤器能够非常好地解决在超大型集合中快速检索元素的需求,不过其缺点是存在一定的误判率。

布隆过滤器是怎么样做到所需存储空间少,而检索速度还能保持极快的?布隆过滤器为什么会存在一定的误判率?

我们先来看一下布隆过滤器的原理。先看下面这个图,有一个长度为28的位数组,我们先将其全部初始化为0。假设有3个hash函数分别为hash1,hash2,hash3。我们现在需要往布隆过滤器里面放入三个狗官的名字,分别是狗官甲、狗官乙、狗官丙。放入狗官甲时,布隆过滤器会分别用3个hash函数对其进行运算得出三个位置值,然后布隆过滤器会将这对应三个位置上的数设置为1。如此类推地将狗官乙和狗官丙放入。
在这里插入图片描述
从这上面的例子我们就能看出布隆过滤器所使用的空间是非常小的,比哈希表更节省空间。另外由于hash函数存在哈希冲突的情况,因此布隆过滤器会有一定的误判率。

接下来我们看下从布隆过滤器中检索的过程
在这里插入图片描述

放置完各种狗官进基于布隆过滤器实现的黑名册后,我们就可以检查某个给定的狗官名字是否在黑名册中了。假如有良民戊,他经过三个hash函数运算后得到的三个位置中,有一个的值是0,也就是说良民戊不存在于黑名册中,那么我们就可以断定这位良民戊真的是良民,而不是乔装打扮的狗官。现在又有身份未明丁,它经过三个hash函数的分别运算后得出三个位置数据,然后布隆过滤器在检查位数组中这三个位置时发现值均是1,我们就可以判断这个身份未明丁很有可能是黑名册中的狗官,这时我们就可以着重去审查一下丁到底是黑名册上的狗官呢,还是只是误判。

从上面我们能看出布隆过滤器有如下特点:
1,无论放置到布隆过滤器中的元素有多少,都能快速地判断这个元素是否存在。
2,布隆过滤器返回某个元素不存在时,那么这个元素就一定不存在。
3,如果某个元素在布隆过滤器中已经存在时,那么布隆过滤器就一定返回存在。
4,如果某个元素不存在与布隆过滤器时,布隆过滤器也可能返回存在。这就是布隆过滤器的误判。

总结一下,布隆过滤器的优缺点如下:

  • 优点:

    布隆过滤器相比其它数据结构能节省下巨大的空间,而且插入和检索的操作都是常数。

  • 缺点:

    布隆过滤器存在一定的误判率,并且不能从中删除元素。

布隆过滤器的应用实例
Google的Guava类库对布隆过滤器做了很好的封装,我们可以直接使用。

import java.nio.charset.Charset;

import com.google.common.hash.BloomFilter;
import com.google.common.hash.Funnels;

public class TestBloomFilter {
	public static void main(String[] args) {
		BloomFilterTest();
	}

	private static void BloomFilterTest() {
		int capacity = 100;
		BloomFilter<String> filter = BloomFilter.create(Funnels.stringFunnel(Charset.forName("UTF8")), capacity, 0.01);// capacity是预估的存入量,0.01为误判率
		for (int i = 0; i < capacity; i++) {
			filter.put("狗官" + i);
		}
		System.out.println("狗官1:" + filter.mightContain("狗官1"));
		System.out.println("狗官2:" + filter.mightContain("狗官2"));
		System.out.println("良民3:" + filter.mightContain("良民3"));
		System.out.println("狗官200:" + filter.mightContain("狗官200"));
	}
}

运行后输出如下:
狗官1:true
狗官2:true
良民3:false
狗官200:true

从输出结果可以看到,狗官200是没有存入到布隆过滤器的,但是布隆过滤器的返回结果却是true,这就是误判的情况。

今为古用,群雄称奇
阿智讲解完自己的方案后,红花会的各位英雄虽啧啧称奇,但又一面茫然。文泰来向徐天宏问道:“武诸葛,你听没听懂?”。只见徐天宏眉头紧缩,缓缓说道:“未来的武器武功与心法果然秒,秒得我这个武诸葛也听不懂。”大厅内群雄听到后无不哈哈大笑,大厅内顿时一片欢声笑语。陈家洛说道:“未来人的厉害不是我们能明白的,三哥你就不要难为武诸葛了。”,然后对阿智又作了一揖,“阿智兄弟,就请你帮我们解决了这问题吧”。阿智听到后心里一喜,心想想不到我这么一个小小的程序员竟然能收到大名鼎鼎的陈家洛的器重。阿智对陈家洛说道:“请放心,我这就开干。”

只见阿智席地而坐,在机械键盘一顿猛敲。不一会儿,一个红花会狗官黑名册的布隆过滤器就完成了。

发布了87 篇原创文章 · 获赞 42 · 访问量 10万+

猜你喜欢

转载自blog.csdn.net/vipshop_fin_dev/article/details/100069581