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<