文章已收录Github精选,欢迎Star:https://github.com/yehongzhi
概念
布隆过滤器(BloomFilter)是由一个叫“布隆”的小伙子在1970年提出的,它是一个很长的二进制向量,主要用于判断一个元素是否在一个集合中。
原理
在介绍原理之前,要先讲一下Hash函数的概念。
我们在Java中的HashMap,HashSet其实也接触过hashcode()这个函数,哈希函数是可以将任意大小的输入数据转换成特定大小的输出数据的函数,转换后的数据称为哈希值。
哈希函数有以下特点:
- 如果根据同一个哈希函数得到的哈希值不同,那么这两个哈希值的原始输入值肯定不同。
- 如果根据同一个哈希函数得到的两个哈希值相等,两个哈希值的原始输入值有可能相等,有可能不相等。
布隆过滤器是由一个很长的二进制向量和一系列的哈希函数组成。那么布隆过滤器是怎么判断一个元素是否在一个集合中的呢?
假设布隆过滤器的底层存储结构是一个长度为16的位数组,初始状态时,它的所有位置都设置为0。
当有变量添加到布隆过滤器中,通过K个映射函数将变量映射到位数组的K个点,并把这K个点的值设置为1(假设有三个映射函数)。
查询某个变量是否存在的时候,我们只需要通过同样的K个映射函数,找到对应的K个点,判断K个点上的值是否全都是1,如果全都是1则表示很可能存在,如果K个点上有任何一个是0则表示一定不存在。
特性
第一个问题,为什么说全都是1的情况是很可能存在,而不是一定存在呢?
还记得前面说的哈希函数的特点,根据同一个哈希函数得到相同的哈希值,输入值不一定相等。类似于Java中两个对象的hashcode相等,但是不一定相等的道理。说白了,映射函数得到位数组上映射点全都是1,不一定是要查询的这个变量之前存进来时设置的,也有可能是其他变量映射的点。
所以这里引出了布隆过滤器的其中一个特点,存在一定的误判。
第二个问题,布隆过滤器能不能删除元素呢?
答案是不能的。因为在位数组上的同一个点有可能有多个输入值映射,如果删除了会影响布隆过滤器里其他元素的判断结果。
如上图,如果删除obj1,把4,7,15置为0,那么判断obj2是否存在时就会导致因为映射点7是0,结果判断obj2是不存在的,结果出错。
这是第二个特点,不能删除布隆过滤器里的元素。
优缺点
优点:
- 在空间和时间方面,都有着巨大的优势。因为不是存完整的数据,是一个二进制向量,能节省大量的内存空间,时间复杂度方面,是根据映射函数查询,假设有K个映射函数,那么时间复杂度就是O(K)。
- 因为存的不是元素本身,而是二进制向量,所以在一些对保密性要求严格的场景有一定优势。
缺点:
- **存在一定的误判。**存进布隆过滤器里的元素越多,误判率越高。
- **不能删除布隆过滤器里的元素。**随着使用的时间越来越长,因为不能删除,存进里面的元素越来越多,占用内存越来越多,误判率越来越高,最后不得不重置。
应用于缓存穿透
**用于缓解缓存穿透。**缓存穿透的问题主要是因为传进来的key在Redis中是不存在的,