布隆过滤器

  • Post author:
  • Post category:其他

1、介绍

布隆过滤器(boomFilter)的出现是为了解决“如何在海量(例如10亿无序、不定长、不重复)元素中,快速判断一个元素是否存在?”。这样正好就可以解决缓存穿透问题,在缓存前面再加入布隆过滤器,key存在则访问缓存。

2、使用(guava的实现)

2.1、基本使用

引入jar包

<dependency>
	<groupld>com.google.guava</groupId>
    <artifactId guava</artifactId>
	<version>21.0</version>
</dependency>

创建布隆过滤器

BloomFilter<String> bf= BloomFilter.create(Funnels.stringFunnel(Charsets.UTF_8),insertions); //insertions是预估有多少元素

布隆过滤器提供的存放元素的方法是put()。

布隆过滤器提供的判断元素是否存在的方法是mightContain()。

if (bf.mightContain(data)){
    if (sets.contains(data)){
		//判断存在实际存在的时候,命中
    	right++;
		continue;
    }
	// 判断存在却不存在的时候,错误
    wrong++;
}

布隆过滤器把误判率默认设置为0.03,也可以在创建的时候指定。

public static <T> BloomFilter<T>create(Funnel<? super T> funnel, long expectedInsertions){
    return create(funnel, expectedInsertions,0.03D);
}

布隆过滤器可以存储多少元素(位图的容量)是基于元素个数和误判率计算出来的。

long numBits = optimalNumOfBits(expectedInsertions, fpp);

根据位数组的大小,我们进一步计算出了哈希函数的个数。

int numHashFunctions = optimalNumOfHashFunctions(expectedInsertions, numBits);

存储100万个元素只占用了0.87M的内存,生成了5个哈希函数。

https://hur.st/bloomfilter

2.2、分布式环境使用

分布式布隆过滤器

它是通过Redisson来实现的,创建方式如下;

RBloomFilter<SomeObject> bloomFilter = redisson.getBloomFilter("sample");
// 初始化布隆过滤器,预计统计元素数量为55000000,期望误差率为0.03
bloomFilter.tryInit(55000000L, 0.03);
bloomFilter.add(new SomeObject("field1Value", "field2Value"));
bloomFilter.add(new SomeObject("field5Value", "field8Value"));
bloomFilter.contains(new SomeObject("field1Value", "field8Value"));

3、原理

3.1、数据结构

布隆过滤器是什么样的结构,能够存储这么的数据而且占用很小的内存?

答案是位图(BitMap、BitSet)

位图:是一个有序的数组,只有两个值,0和1。0代表不存在,1代表存在。也就是说用标记的方式,标记这个元素是否存在。

在这里插入图片描述

3.2、存储数据

举个栗子,现在我们需要存储100w元素,这时候布隆过滤器,经过计算需要3个hash函数进行存储。

在这里插入图片描述

问题1:元素和位图之间是如何进行映射的?

通过哈希函数计算出下标;使用多个哈希函数,计算出不同的下标。如上图,通过3个哈希函数,计算出3个下标来确定元素是否存在。

首先,我们要知道是元素的key长度是不固定的,但是要得到数据长度一样的下标;而且还需要在位图上分布均匀。那我们是用什么方法来做呢?这就需要哈希函数登场了,比如MD5、SHA-1等等。通过哈希函数,我们计算出了元素的下标,但是,使用哈希函数就一定会出现哈希碰撞的问题。如果一个哈希函数存在哈希碰撞问题,那就多用几个哈希函数来计算下标,通过多个下标,确定元素是否存在。

至于使用几个哈希函数可以通过如下方法计算出来

int numHashFunctions = optimalNumOfHashFunctions(expectedInsertions, numBits);

问题2:通过3个或者更多哈希函数确定元素位置,就一定能准确判断元素是存在的吗?

不能,但是,如果某个元素的一个下标不匹配,则这个元素一定不存在位图数组中

如果需要使用布隆过滤器来判断元素是否存在,则就要忍受一定的误识率,这个误识率可以通过创建布隆过滤器的时候设置。

布隆过滤器把误判率默认设置为0.03,也可以在创建的时候指定。

public static <T> BloomFilter<T>create(Funnel<? super T> funnel, long expectedInsertions{
    return create(funnel, expectedInsertions,0.03D);
}

问题3:布隆过滤器的元素可以删除吗?

不能,因为通过多个下标标记确定元素是否存在。哈希碰撞的下标是存在多个元素标记的,所以不能擦去标记。所以不能删除。


版权声明:本文为qq_16116881原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。