Bloom-Filter算法

一、 Bloom-Filter算法简介。
Bloom-Filter,即布隆过滤 器,1970年由Bloom中提出。它可以用于检索一个元素是否在一个集合中,其优点是空间效率和查询时间都远远超过其他算法,其不足在于Bloom- Filter存在着误判。


二、 Bloom-Filter的基本思想。
Bloom-Filter算法的核心思想就是利用 多个不同的Hash函数来解决“冲突”。
计算某元素x是否在一个集合中,首先能想到的方法就是将所有的已知元素保存起来构成一个集合R,然后用元 素x跟这些R中的元素一一比较来判断是否存在于集合R中;我们可以采用链表等数据结构来实现。但是,随着集合R中元素的增加,其占用的内存将越来越大。试 想,如果有几千万个不同网页需要下载,所需的内存将足以占用掉整个进程的内存地址空间。即使用MD5,UUID这些方法将URL转成固定的短小的字符串, 内存占用也是相当巨大的.

日常生活中,包括在设计计算机软件 时,我们经常要判断一个元素是否在一个集合中。比如在字处理软件中,需要检查一个英语单词是否拼写正确(也就是要判断它是否在已知的字典中);在 FBI,一个嫌疑人的名字是否已经在嫌疑名单上;在网络爬虫里,一个网址是否被访问过等等。最直接的方法就是将集合中全部的元素存在计算机中,遇到一个新 元素时,将它和集合中的元素直接比较即可。

   一般来讲,计算机中的集合是用哈希表(hash table)来存储的。它的好处是快速准确,缺点是费存储空间。当集合比较小时,这个问题不显著,但是当集合巨大时,哈希表存储效率低的问题就显现出来 了。


三、 Bloom-Filter的应用。
Bloom-Filter一般用于在大数据量的集合中判定某元素是否 存在。例如邮件服务器中的垃圾邮件过滤器。在搜索引擎领域,Bloom-Filter最常用于网络蜘蛛(Spider)的URL过滤,网络蜘蛛通常有一个 URL列表,保存着将要下载和已经下载的网页的URL,网络蜘蛛下载了一个网页,从网页中提取到新的URL后,需要判断该URL是否已经存在于列表中。此 时,Bloom-Filter算法是最好的选择。

   比如说,一个象 Yahoo,Hotmail 和 Gmai 那样的公众电子邮件(email)提供商,总是需要过滤来自发送垃圾邮件的人(spamer)的垃圾邮件。一个办法就是记录下那些发垃圾邮件的 email 地址。由于那些发送者不停地在注册新的地址,全世界少说也有几十亿个发垃圾邮件的地址,将他们都存起来则需要大量的网络服务器。

布隆过滤器是由巴顿.布隆于一九七零年提出的。它实际上是一个很长的二进制向量和一系列随机映射函数。我们通过上面的例子来说明起工作原理。

  假定我们存储一亿个电子邮件地址,我们先建立一个十六亿二进制(比特),即两亿字节的向量,然后将这十六 亿个二进制位全部设置为零。对于每一个电子邮件地址 X,我们用八个不同的随机数产生器(F1,F2, ...,F8) 产生八个信息指纹(f1, f2, ..., f8)。再用一个随机数产生器 G 把这八个信息指纹映射到 1 到十六亿中的八个自然数 g1, g2, ...,g8。现在我们把这八个位置的二进制位全部设置为一。当我们对这一亿个 email 地址都进行这样的处理后。一个针对这些 email 地址的布隆过滤器就建成了。(见下图)
 现在,让我们看看如何用布隆过滤器来检测一个可疑的电子邮件地址 Y 是否在黑名单中。我们用相同的八个随机数产生器(F1, F2, ..., F8)对这个地址产生八个信息指纹 s1,s2,...,s8,然后将这八个指纹对应到布隆过滤器的八个二进制位,分别是 t1,t2,...,t8。如果 Y 在黑名单中,显然,t1,t2,..,t8 对应的八个二进制一定是一。这样在遇到任何在黑名单中的电子邮件地址,我们都能准确地发现。

   布隆过滤器决不会漏掉任何一个在黑名单中的可疑地址。但是,它有一条不足之处。也就是它有极小的可能将 一个不在黑名单中的电子邮件地址判定为在黑名单中,因为有可能某个好的邮件地址正巧对应八个都被设置成一的二进制位。好在这种可能性很小。我们把它称为误 识概率。在上面的例子中,误识概率在万分之一以下。

布隆过滤器的好处在于快速,省空间。但是有一定的误识别率。常见的补救办法是在建立一个小的白名单,存储那些 可能别误判的邮件地址。

四、 Bloom-Filter的具体实现(java语言)。
import java.util.BitSet;
public class SimpleBloomFilter {
private static final int DEFAULT_SIZE =2 << 24 ;
private static final int [] seeds =new int []{5,7, 11 , 13 , 31 , 37 , 61};
private BitSet bits= new BitSet(DEFAULT_SIZE);
private SimpleHash[] func=new SimpleHash[seeds.length];
public static void main(String[] args) {
String value = "stone2083@yahoo.cn" ;
SimpleBloomFilter filter=new SimpleBloomFilter();
System.out.println(filter.contains(value));
filter.add(value);
System.out.println(filter.contains(value));
}
public SimpleBloomFilter() {
for( int i= 0 ; i< seeds.length; i ++ ) {
func[i]=new SimpleHash(DEFAULT_SIZE, seeds[i]);
}
}
public void add(String value) {
for(SimpleHash f : func) {
bits.set(f.hash(value), true );
}
}
public boolean contains(String value) {
if(value ==null ) {
return false ;
}
boolean ret = true ;
for(SimpleHash f : func) {
ret=ret&& bits.get(f.hash(value));
}
return ret;
}
public static class SimpleHash {
private int cap;
private int seed;
public SimpleHash( int cap, int seed) {
this.cap= cap;
this.seed =seed;
}
public int hash(String value) {
int result=0 ;
int len= value.length();
for (int i= 0 ; i< len; i ++ ) {
result =seed* result + value.charAt(i);
}
return (cap - 1 ) & result;
}
}
}

四、 Bloom-Filter的具体实现(C语言)。
这里的实现使用两个hash函数。
1. 数据结构。
/** bitmap array of bloom‐filter */
struct
bitmap_bloomfilter_t
{
u32_t * bitmap1; /* 第一个hash可映射到这里 */
u32_t
* bitmap2; /* 第二个hash可映射到这里 */
long max_size; /*
};
2.函数。
bitmap_bloomfilter_t
结构用于保存元素是否存在的位数组,我们需要相关的函数分别创建和释放它。
(1)bitmap_bloomfilter_t *
create_bitmap_bloomfilter( long max_size
),创建bitmap_bloomfilter_t对象,参数max_size表示位图数组中最大容纳的元素数。
(2)void
free_bitmap_bloomfilter( bitmap_bloomfilter_t ** bbf
),释放一个bitmap_bloomfilter_t对象,该对象同时被销毁。
bloom‐filter过滤函数,判断一个元素是否在集合中。
(3)int
bloomfilter_filter( const bitmap_bloomfilter_t * bbf, const void *
data, long len )
以下是几个内部函数。我们还需要两个函数,一个用来来判断位图数组中某一位的值是否为1,另一个用于将位图数组
中的某一位设置为1。
(4)static __INLINE__ BOOL get_bitmap_bit( const u32_t *
bitmap, u32_t 2
搜索引擎技术文档
offset ), 判断位图数组中某一位的值是否为1。
(5)static
__INLINE__ void set_bitmap_bit( const u32_t * bitmap, u32_t offset
),将位图数组中的某一位设置为1。
我们使用的两个hash函数。
(6)static u32_t hash_f1( const
void * data, long len )
(7)static u32_t hash_f2( const void * data,
long len )
2. 示例程序。
long * url[10] = {
“http://www.baidu.com/”,
“http://www.google.com/”,
“http://www.rising.com.cn”,
“http://www.yahoo.com/”,
“http://www.microsoft.com/”,
“http://www.baidu.com/”,
“http://www.baidu.com.cn”,
“http://www.baidu.com”,
“http://www.baidu.com/index.html”,
“http://www.firefox.org/”
};
int
main( int argc, char ** argv )
{
int i;
bitmap_bloomfilter_t *
bbf = create_bitmap_bloomfilter( 10000 );/*创建位图数组结构*/
for ( i=0;
i<10; i++ ) /*分别对url中的10元素进行过滤操作*/
{
fprintf( stdout,
"%ld‐>filtered(%d)./n", data[i], bloomfilter_filter(bbf,
(void*)(data+i), strlen(url[i])) );
}
free_bitmap_bloomfilter(
&bbf );/*释放位图数组结构*/
return 0;
}
  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值