不同数据类型的布隆过滤器: Integer,Long等
两个步骤:
1)将数据放入bloom filter中;
2)判断数据是否已在bloom filter中;
基于url级别的权限判断,判断访问权限是否存在可用此方案解决, ip黑名单;
字节数组,元素是0或者1.
添加元素的时候,判断元素是否存在的时候。
错误率越大,所需空间和时间越小,错误率越小,所需空间和时间约大(可以自己定义错误率)。
它可以通过一个Hash函数将一个元素映射成一个位阵列(Bit array)中的一个点。这样一来,我们只要看看这个点是不是1就可以知道集合中有没有它了。这就是布隆过滤器的基本思想。
判断元素在不在一个集合里面,如果集合里面的元素非常大,这个判断过程是非常耗时的,而且集合占用空间也很大。
布隆过滤器存储空间和插入/查询时间都是常数。Hash函数相互之间没有关系,方便由硬件并行实现。布隆过滤器不需要存储元素本身,在某些对保密要求非常严格的场合有优势。
package com.demo.www.springbootdemo.crs.bloomfilter;
import com.google.common.hash.BloomFilter;
import com.google.common.hash.Funnels;
/**
* 测试布隆过滤器
*/
public class TestBloomFilter {
//定义布隆过滤器的长度
private static int total = 1000000;
//创建布隆过滤器
private static BloomFilter bloomFilter = BloomFilter.create(Funnels.integerFunnel(), total,0.0003);
private static int index = 0;
private static int count = 0;
public static void main(String[] args) {
for (int i = 0; i < total; i++) {
//将数据添加到过滤器中
bloomFilter.put(i);
}
//判断数据是否存在?
for (int i = 0; i < total; i++) {
if (!bloomFilter.mightContain(i)) {
index++;
System.out.println("有数据没检测到" + i);
}
}
System.out.println("是否能够识别过滤器中数据:"+index);
//数据全部存在
//测试另外的10000数据,看看过滤器的误杀情况?现在是都不存在与过滤器中。
for (int i = total; i < total+10000; i++) {
if ( bloomFilter.mightContain(i)){
count++;
}
}
System.out.println("误判的数据量"+count); //286个数据,本来不存在,但是确判定存在了。
//1,遍历这一百万个在过滤器中的数时,都被识别出来了。
//2,一万个不在过滤器中的数,误伤了320个,错误率是0.03左右。
//某个判断的执行时间
long startTime = System.nanoTime(); // 获取开始时间
//判断这一百万个数中是否包含29999这个数
if (bloomFilter.mightContain(29999)) {
System.out.println("命中了");
}
long endTime = System.nanoTime(); // 获取结束时间
System.out.println("程序运行时间: " + (endTime - startTime) + "纳秒");
//结果是1毫秒都不到即可判断出是否存在,所占用的空间也比较小。
}
}
错误率,所占用内存空间,执行hash的次数:
BloomFilter概念
它是一个很长的二进制向量和一系列随机映射函数。布隆过滤器可以用于检索一个元素是否在一个集合中。它的优点是空间效率和查询时间都远远超过一般的算法,缺点是有一定的误识别率和删除困难。
BloomFilter原理
当一个元素被加入集合时,通过K个散列函数将这个元素映射成一个位数组中的K个点,把它们置为1。检索时,我们只要看看这些点是不是都是1就(大约)知道集合中有没有它了:如果这些点有任何一个0,则被检元素一定不在;如果都是1,则被检元素很可能在。这就是布隆过滤器的基本思想。
Bloom Filter使用了k个哈希函数,每个字符串跟k个bit对应。从而降低了冲突的概率。
BloomFilter缺点
bloom filter之所以能做到在时间和空间上的效率比较高,是因为牺牲了判断的准确率、删除的便利性
1,存在误判,可能要查到的元素并没有在容器中,但是hash之后得到的k个位置上值都是1。如果bloom filter中存储的是黑名单,那么可以通过建立一个白名单来存储可能会误判的元素。
2,删除困难。一个放入容器的元素映射到bit数组的k个位置上是1,删除的时候不能简单的直接置为0,可能会影响其他元素的判断。可以采用CountingBloomFilter。
BloomFilter实现
Guava中提供了一种Bloom Filter的实现。
在使用bloom filter时,绕不过的两点:1是预估数据量n以及期望的误判率fpp,2是hash函数的选取以及bit数组的大小。
对于一个确定的场景,我们预估要存的数据量为n,期望的误判率为fpp,然后需要计算我们需要的Bit数组的大小m,以及hash函数的个数k,并选择hash函数.
(1)Bit数组大小选择
(2)哈希函数选择
布隆过滤器的设计
布隆过滤器思路比较简单,但是对于布隆过滤器的随机映射函数设计,需要计算几次,向量长度设置为多少比较合适,这个才是需要认真讨论的。
如果向量长度太短,会导致误判率直线上升。
如果向量太长,会浪费大量内存。
如果计算次数过多,会占用计算资源,且很容易很快就把过滤器填满。
缓存穿透(每次查询都会直接打到DB)
用户想要查询一个数据,发现redis内存数据库没有,也就是缓存没有命中,于是向持久层数据库查询。发现也没有,于是本次查询失败。当用户很多的时候,缓存都没有命中,于是都去请求了持久层数据库。这会给持久层数据库造成很大的压力,这时候就相当于出现了缓存穿透。