1. 什么是布隆过滤器
布隆过滤器实际上是一种特殊的数据结构,它能够在海量的数据中查询一个给定的数据是否存在其中。
- 比如:从1亿的数据中,查询100个数据。这种情况下就可以使用布隆过滤器。
- 此外,布隆过滤器经常用于解决redis的缓存穿透的问题。
什么是缓存穿透?
就是在高并发的情况下,要查询的某个字段既不存在于redis缓存中,在数据库中也没有,这样所有的请求瞬间全部落在数据库上,导致数据库崩溃。
而通过布隆过滤器可以解决缓存穿透问题。我们将所有可能请求的值存放在布隆过滤器中,当用户请求过来的时候,先判断该值是否存在于布隆过滤器中,如果不存在,直接返回请求参数错误给客户端。存在的话,再从redis和数据库中去查询。
2.如何实现
布隆过滤器是如何实现在大数据量中进行快速查询的。布隆过滤器是由一个二进制向量(位数组)和一系列哈希函数组成的数据结构。看上去似乎和HashMap比较相似,但是它比hashMap更加节省空间,效率更高。但是也存在缺点,它返回的结果是一个概率性的,而不是一个准确的结果。
位数组中的每个元素都只占用 1 bit ,并且每个元素只能是 0 或者 1。这样申请一个 100w 个元素的位数组只占用 1000000Bit / 8 = 125000 Byte = 125000/1024 kb ≈ 122kb 的空间。
2.1 原理
- 使用布隆过滤器中的多个哈希函数对元素值进行计算,得到多个哈希值(有几个哈希函数得到几个哈希值)。
- 根据得到的哈希值,对位数组取余,余数的位置就是待插入的位置,在位数组中把对应下标的值置为 1。
当我们需要判断一个元素是否存在于布隆过滤器的时候,会进行如下操作:
- 对给定元素再次进行相同的哈希计算;
- 得到值之后判断位数组中的每个元素是否都为 1,如果值都为 1,那么说明这个值有一定概率在布隆过滤器中,如果存在一个值不为 1,说明该元素不在布隆过滤器中。

布隆过滤器说某个元素存在,小概率会误判。布隆过滤器说某个元素不在,那么这个元素一定不在。
位数组的长度越小,误判的概率就会增加。所以为了减小误判概率,可以增大位数组的长度。
2.2 实现
- 定义一个位数组bitset,数组长度为2的n次方,为了方便计算余数
- 定义一组hash函数数组,并设置随机种子
- 采用静态内部类实现一个hash函数的类,并创建多个hash函数
- 实现布隆过滤器添加和查询的操作
import java.util.BitSet;
public class MyBloomFilter {
//定义一个位数组长度,长为33554432(3000Wbit的位数组)
private static final int DEFAULT_SIZE = 2<<24;
//定义一个位数组
private BitSet bits = new BitSet(DEFAULT_SIZE);
//定义几个hash函数的随机种子
private static final int[] SEEDS = new int[] {3, 13, 46, 71, 91, 134};
//定义hash函数数组
private SimpleHash[] func = new SimpleHash[SEEDS.length];
public static class SimpleHash{
private int cap; //数组长度
private int seed; //随机种子
public SimpleHash(int cap,int seed) {
this.cap = cap;
this.seed = seed;
}
//计算hash值
public int hash(Object obj) {
int h;
//这里(cap-1)&hash就是取余,所以cap一定是2的n次方
return (obj==null)?0:Math.abs(seed*(cap-1)&((h=obj.hashCode())^(h>>>16)));
}
}
//布隆过滤器的构造方法,初始化多个hash函数
public MyBloomFilter() {
for (int i = 0; i < SEEDS.length; i++) {
func[i] = new SimpleHash(DEFAULT_SIZE, SEEDS[i]);
}
}
//添加元素
public void add(Object obj) {
for (int j = 0; j < SEEDS.length; j++) {
bits.set(func[j].hash(obj), true);
}
}
//查询元素
public boolean query(Object obj) {
for (int i = 0; i < SEEDS.length; i++) {
if(!bits.get(func[i].hash(obj)))
return false;
}
return true;
}
}
3. redis中使用布隆过滤器
Redis v4.0 之后有了 Module(模块/插件) 功能,Redis Modules 让 Redis 可以使用外部模块扩展其功能 。布隆过滤器就是其中的 Module。
布隆过滤器是一种数据结构,用于在海量数据中高效查询是否存在特定元素,常用于解决缓存穿透问题。它由位数组和哈希函数组成,通过多哈希值确定位数组中位置,存在误判概率但节省空间。在Redis中,可以通过Module扩展使用布隆过滤器。
3804

被折叠的 条评论
为什么被折叠?



