海量数据处理利器之布隆过滤器

      看见了海量数据去重,找到停留时间最长的IP等问题,有博友提到了Bloom Filter,我就查了查,不过首先想到的是大叔,下面就先看看大叔的风采。

            

一、布隆过滤器概念引入

      (Bloom Filter)是由布隆(Burton Howard Bloom)在1970年提出的。它实际上是由一个很长的二进制向量和一系列随机映射函数组成,布隆过滤器可以用于检索一个元素是否在一个集合中。它的优点是空间效率和查询时间都远远超过一般的算法,缺点是有一定的误识别率(假正例False positives,即Bloom Filter报告某一元素存在于某集合中,但是实际上该元素并不在集合中)和删除困难,但是没有识别错误的情形(即假反例False negatives,如果某个元素确实在该集合中,那么Bloom Filter 是不会报告该元素不存在于集合中的,所以不会漏报)。

      下面从简单的排序谈到BitMap算法,再谈到数据去重问题,谈到大数据量处理利器:布隆过滤器。

  • 对无重复的数据进行排序

      给定数据(2,4,1,12,9,7,6)如何对它排序?

     方法1:基本的排序方法包括冒泡,快排等。

     方法2:使用BitMap算法

     方法1就不介绍了,方法2中所谓的BitMap是一个位数组,跟平时使用的数组的唯一差别在于操作的是位。首先是开辟2个字节大小的位数组,长度为12(该长度由上述数据中最大的数字12决定的),然后,读取数据,2存放在位数组中下标为1的地方,值从0改为1,4存放在下标为3的地方,值从0改为1....最后,读取该位数组,得到排好序的数据是:(1,2,4,6,7,9,12)。

      比较方法1和方法2的差别:方法2中,排序需要的时间复杂度和空间复杂度很依赖与数据中最大的数字比如12,因此空间上讲需要开2个字节大小的内存,时间上需要遍历完整个数组。当数据类似(1,1000,10万)只有3个数据的时候,显然用方法2,时间复杂度和空间复杂度相当大,但是当数据比较密集时该方法就会显示出来优势。

  • 对有重复的数据进行判重

   数据(2,4,1,12,2,9,7,6,1,4)如何找出重复出现的数字?

   首先是开辟2个字节大小的位数组,长度为12(该长度由上述数据中最大的数字12决定的,当读取完12后,当读取2的时候,发现数组中的值是1,则判断出2是重复出现的。

二、布隆过滤器原理

      布隆过滤器需要的是一个位数组(这个和位图有点类似)和k个映射函数(和Hash表类似),在初始状态时,对于长度为m的位数组array,它的所有位都被置为0。对于有n个元素的集合S={s1,s2......sn},通过k个映射函数{f1,f2,......fk},将集合S中的每个元素sj(1<=j<=n)映射为k个值{g1,g2......gk},然后再将位数组array中相对应的array[g1],array[g2]......array[gk]置为1;如果要查找某个元素item是否在S中,则通过映射函数{f1,f2.....fk}得到k个值{g1,g2.....gk},然后再判断array[g1],array[g2]......array[gk]是否都为1,若全为1,则item在S中,否则item不在S中。这个就是布隆过滤器的实现原理。

      当然有读者可能会问:即使array[g1],array[g2]......array[gk]都为1,能代表item一定在集合S中吗?不一定,因为有这个可能:就是集合中的若干个元素通过映射之后得到的数值恰巧包括g1,g2,.....gk,那么这种情况下可能会造成误判,但是这个概率很小,一般在万分之一以下。

      很显然,布隆过滤器的误判率和这k个映射函数的设计有关,到目前为止,有很多人设计出了很多高效实用的hash函数。尤其要注意的是,布隆过滤器是不允许删除元素的(实际就是因为多个str可能都应设在同一点,而判断str存在的话是所有映射点都存在,所以不能删除),因为若删除一个元素,可能会发生漏判的情况。不过有一种布隆过滤器的变体Counter Bloom Filter,可以支持删除元素,感兴趣的读者可以查阅相关文献资料。

三、布隆过滤器False positives 概率推导

      假设 Hash 函数以等概率条件选择并设置 Bit Array 中的某一位,m 是该位数组的大小,k 是 Hash 函数的个数,那么位数组中某一特定的位在进行元素插入时的 Hash 操作中没有被置位为1的概率是:;那么在所有 k 次 Hash 操作后该位都没有被置 "1" 的概率是:;如果我们插入了 n 个元素,那么某一位仍然为 "0" 的概率是:因而该位为 "1"的概率是:;现在检测某一元素是否在该集合中。标明某个元素是否在集合中所需的 k 个位置都按照如上的方法设置为 "1",但是该方法可能会使算法错误的认为某一原本不在集合中的元素却被检测为在该集合中(False Positives),该概率由以下公式确定:

      其实上述结果是在假定由每个 Hash 计算出需要设置的位(bit) 的位置是相互独立为前提计算出来的,不难看出,随着 m (位数组大小)的增加,假正例(False Positives)的概率会下降,同时随着插入元素个数 n 的增加,False Positives的概率又会上升,对于给定的m,n,如何选择Hash函数个数 k 由以下公式确定:;此时False Positives的概率为:;而对于给定的False Positives概率 p,如何选择最优的位数组大小 m 呢,;该式表明,位数组的大小最好与插入元素的个数成线性关系,对于给定的 m,n,k,假正例概率最大为:

四、布隆过滤器应用

      布隆过滤器在很多场合能发挥很好的效果,比如:网页URL的去重,垃圾邮件的判别,集合重复元素的判别,查询加速(比如基于key-value的存储系统)等,下面举几个例子:

  • 有两个URL集合A,B,每个集合中大约有1亿个URL,每个URL占64字节,有1G的内存,如何找出两个集合中重复的URL。

很显然,直接利用Hash表会超出内存限制的范围。这里给出两种思路:

      第一种:如果不允许一定的错误率的话,只有用分治的思想去解决,将A,B两个集合中的URL分别存到若干个文件中{f1,f2...fk}和{g1,g2....gk}中,然后取f1和g1的内容读入内存,将f1的内容存储到hash_map当中,然后再取g1中的url,若有相同的url,则写入到文件中,然后直到g1的内容读取完毕,再取g2...gk。然后再取f2的内容读入内存。。。依次类推,知道找出所有的重复url。

      第二种:如果允许一定错误率的话,则可以用布隆过滤器的思想。

  • 在进行网页爬虫时,其中有一个很重要的过程是重复URL的判别,如果将所有的url存入到数据库中,当数据库中URL的数

量很多时,在判重时会造成效率低下,此时常见的一种做法就是利用布隆过滤器,还有一种方法是利用berkeley db来存储url,Berkeley db是一种基于key-value存储的非关系数据库引擎,能够大大提高url判重的效率。

      布隆过滤器主要运用在过滤恶意网址用的,将所有的恶意网址建立在一个布隆过滤器上,然后对用户的访问的网址进行检测,如果在恶意网址中那么就通知用户。这样的话,我们还可以对一些常出现判断错误的网址设定一个白名单,然后对出现判断存在的网址再和白名单中的网址进行匹配,如果在白名单中,那么就放行。当然这个白名单不能太大,也不会太大,布隆过滤器错误的概率是很小的。

五、布隆过滤器简单Java实现 

package a;

import java.util.BitSet;
/*
 * 存在的问题
 * DEFAULT_LEN长度设置为多少合适呢?
 * 我发现result和DEFAULT_LEN有关,不应该啊,没发现原因
 */
public class BloomFilterTest {
	//30位,表示2^2^30种字符
	static int DEFAULT_LEN = 1<<30;
	//要用质数
	static int[] seeds = {3,5,7,11,17,31};
	static BitSet bitset = new BitSet(DEFAULT_LEN);
	static MyHash[] myselfHash = new MyHash[seeds.length];

	public static void main(String[] args) {
		String str = "791909235@qq.com";

		//生成一次就够了
		for(int i=0; i<seeds.length; i++) {
			myselfHash[i] = new MyHash(DEFAULT_LEN, seeds[i]);
		}
		bitset.clear();
		for(int i=0; i<myselfHash.length; i++) {
			bitset.set(myselfHash[i].myHash(str),true);
		}
		boolean flag = containsStr(str);
		//System.out.println("========================");
		System.out.println(flag);

	}

	private static boolean containsStr(String str) {
		// TODO Auto-generated method stub
		if(null==str)
			return false;
		for(int i=0; i<seeds.length; i++) {
			if(bitset.get(myselfHash[i].myHash(str))==false)
				return false;
		}
		return true;
	}
}
class MyHash {
	int len;
	int seed;

	public MyHash(int len, int seed) {
		super();
		this.len = len;
		this.seed = seed;
	}

	public int myHash(String str) {
		int len = str.length();
		int result = 0;
		//这的len就是str的len,不是成员变量的len
		for(int i=0; i<len; i++) {
			//System.out.println(seed+"oooooooooooo");
			result = result*seed + str.charAt(i);
			//System.out.println(result);
			//长度就是1<<24,如果大于这个数 感觉结果不准确
			//<0就是大于了0x7ffffff
			if(result>(1<<30) || result<0) {
				//System.out.println("-----"+(1<<30));
				System.out.println(result+"myHash数据越界!!!");
				break;
			}
		}
		return (len-1)&result;
	}
}
时间: 2024-10-11 20:08:07

海量数据处理利器之布隆过滤器的相关文章

[算法系列之十]大数据量处理利器:布隆过滤器

[引言] 在日常生活中,包括在设计计算机软件时,我们经常要判断一个元素是否在一个集合中.比如在字处理软件中,需要检查一个英语单词是否拼写正确(也就是要判断 它是否在已知的字典中):在 FBI,一个嫌疑人的名字是否已经在嫌疑名单上:在网络爬虫里,一个网址是否被访问过等等.最直接的方法就是将集合中全部的元素存在计算机中,遇到一个新 元素时,将它和集合中的元素直接比较即可.一般来讲,计算机中的集合是用哈希表(hash table)来存储的.它的好处是快速准确,缺点是费存储空间.当集合比较小时,这个问题

[算法系列之十八]海量数据处理之BitMap

一:简介 所谓的BitMap就是用一个bit位来标记某个元素对应的Value, 而Key即是该元素.由于采用了bit为单位来存储数据,因此在存储空间方面,可以大大节省. 二:基本思想 我们用一个具体的例子来讲解,假设我们要对0-7内的5个元素(4,7,2,5,3)排序(这里假设这些元素没有重复).那么我们就可以采用BitMap的方法来达到排序的目的.要表示8个数,我们就只需要8个bit(1Bytes). (1)首先我们开辟1字节(8bit)的空间,将这些空间的所有bit位都置为0,如下图: (2

从Hadoop框架与MapReduce模式中谈海量数据处理(含淘宝技术架构)

 文章转载自: http://blog.csdn.net/v_july_v/article/details/670407 从hadoop框架与MapReduce模式中谈海量数据处理 前言     几周前,当我最初听到,以致后来初次接触Hadoop与MapReduce这两个东西,我便稍显兴奋,觉得它们很是神秘,而神秘的东西常能勾起我的兴趣,在看过介绍它们的文章或论文之后,觉得Hadoop是一项富有趣味和挑战性的技术,且它还牵扯到了一个我更加感兴趣的话题:海量数据处理.     由此,最近凡是空闲时

《Hadoop海量数据处理:技术详解与项目实战》一1.2 Hadoop和大数据

1.2 Hadoop和大数据 Hadoop海量数据处理:技术详解与项目实战 在人们对云计算这个词汇耳熟能详之后,大数据这个词汇又在最短时间内进入大众视野.云计算对于普通人来说就像云一样,一直没有机会能够真正感受到,而大数据则更加实际,是确确实实能够改变人们生活的事物.Hadoop从某个方面来说,与大数据结合得更加紧密,它就是为大数据而生的. 1.2.1 大数据的定义 "大数据"(big data),一个看似通俗直白.简单朴实的名词,却无疑成为了时下IT界最炙手可热的名词,在全球引领了新

教你如何迅速秒杀掉:99%的海量数据处理面试题

作者:July 出处:结构之法算法之道blog   前言    一般而言,标题含有"秒杀","99%","史上最全/最强"等词汇的往往都脱不了哗众取宠之嫌,但进一步来讲,如果读者读罢此文,却无任何收获,那么,我也甘愿背负这样的罪名,:-),同时,此文可以看做是对这篇文章:十道海量数据处理面试题与十个方法大总结的一般抽象性总结.     毕竟受文章和理论之限,本文将摒弃绝大部分的细节,只谈方法/模式论,且注重用最通俗最直白的语言阐述相关问题.最后,

BloomFilter(布隆过滤器)简介

判断一个元素是否在一个集合中,有很多种方法,这里介绍一个用在Google的搜索系统中的一个很有意思的算法. 如何判断一个元素是否在一个集合中: 首先,我们假设,元素的数量为n,元素的长度为m. 最简单的方法: 用一个数组存储,然后每次for循环来查找.忽略元素比较的时间,一次查询的时间复杂度是O(n),空间复杂度为O(n*m).在数据量不大的情况下,这是很不错的选择. 采用树状索引: 常用的二叉树,或者btree这类的索引方法也是不错的选择.它们将时间复杂度缩减到O(nlogn),空间复杂度依然

十七道海量数据处理面试题与Bit-map详解

作者:小桥流水,redfox66,July.   前言     本博客内曾经整理过有关海量数据处理的10道面试题(十道海量数据处理面试题与十个方法大总结),此次除了重复了之前的10道面试题之后,重新多整理了7道.仅作各位参考,不作它用.     同时,程序员编程艺术系列将重新开始创作,第十一章以后的部分题目来源将取自下文中的17道海量数据处理的面试题.因为,我们觉得,下文的每一道面试题都值得重新思考,重新深究与学习.再者,编程艺术系列的前十章也是这么来的.若您有任何问题或建议,欢迎不吝指正.谢谢

布隆过滤器Bloom Filter算法的Java实现(用于去重)

在日常生活中,包括在设计计算机软件时,我们经常要判断一个元素是否在一个 集合中.比如在字处理软件中,需要检查一个英语单词是否拼写正确(也就是要判断它是否在已知的字典中):在 FBI,一个嫌疑人的名字是否已经在嫌疑名单上:在网络爬虫里,一个网址是否被访问过等等.最直接的方法就是将集合中全部的元素存在计算机中,遇到一个新 元素时,将它和集合中的元素直接比较即可.一般来讲,计算机中的集合是用哈希表(hash table)来存储的.它的好处是快速准确,缺点是费存储空间.当集合比较小时,这个问题不显著,但

海量数据处理技巧

目录(?)[-]       教你如何迅速秒杀掉99的海量数据处理面试题 前言 何谓海量数据处理 第一部分从setmap谈到hashtablehash_maphash_set 第二部分处理海量数据问题之六把密匙 密匙一分而治之Hash映射 Hash_map统计 堆快速归并排序 密匙二多层划分 密匙三Bloom filterBitmap Bloom filter Bitmap 密匙四Trie树数据库倒排索引 密匙五外排序 密匙六分布式处理之Mapreduce 其它模式方法论结合操作系统知识 [-]