布隆过滤器(BloomFilter)是一种空间效率高的概率型数据结构,用于判断元素是否存在于集合中。其核心原理是通过多个哈希函数将元素映射到位数组的多个位置,并通过位数组的状态快速判断元素是否存在。以下是详细解析:
一、布隆过滤器原理数据结构
位数组:每个元素仅占1 bit(0或1),初始值全为0。例如,10000个元素的位数组仅需约1250字节。
哈希函数:使用多个(如3个)独立哈希函数,将元素映射到位数组的不同位置。
添加元素
对元素(如"oracle")计算多个哈希值,将对应位数组的位置设为1。
例如,"oracle"通过h1()、h2()、h3()映射到位数组的第1、4、5位,将其置1。查询元素
计算待查元素的哈希值,检查对应位是否全为1。若全为1,则可能存在;若有0,则一定不存在。
误判:不同元素可能因哈希碰撞导致相同位被置1(如"mysql"的哈希值4、5、10已被占用),从而误判存在。
特点
优点:空间效率高、查询速度快(O(k),k为哈希函数数量)。
缺点:无法删除元素(因共享位)、存在误判率(可通过增大位数组或增加哈希函数降低)。
二、布隆过滤器使用场景缓存穿透防护
在查询缓存前,先通过布隆过滤器判断Key是否存在。若不存在,直接返回,避免无效数据库查询。
去重与黑名单
判断用户是否已阅读文章/视频(允许少量误判)。
邮件黑名单、IP爬虫过滤等。
大数据场景
垃圾邮件过滤(从数十亿邮箱中快速筛查)。
三、实践实现1. Java手动实现import java.util.BitSet;public class MyBloomFilter { private static final int DEFAULT_SIZE = 2 << 24; // 位数组大小 private static final int[] SEEDS = {5, 17, 48, 73, 93, 132}; // 哈希种子 private BitSet bits = new BitSet(DEFAULT_SIZE); private SimpleHash[] func = new SimpleHash[SEEDS.length]; public MyBloomFilter() { for (int i = 0; i < SEEDS.length; i++) { func[i] = new SimpleHash(DEFAULT_SIZE, SEEDS[i]); } } // 添加元素 public void add(Object value) { for (SimpleHash f : func) { bits.set(f.hash(value), true); } } // 判断是否存在 public boolean contains(Object value) { boolean ret = true; for (SimpleHash f : func) { ret = ret && bits.get(f.hash(value)); } return ret; } // 哈希函数内部类 public static class SimpleHash { private int cap; private int seed; public SimpleHash(int cap, int seed) { this.cap = cap; this.seed = seed; } public int hash(Object value) { int h = value == null ? 0 : value.hashCode(); return Math.abs(seed * (cap - 1) & (h ^ (h >>> 16))); } }}2. Redis布隆过滤器- Docker快速体验:docker run -d -p 6379:6379 --name bloomfilter redislabs/rebloomdocker exec -it bloomfilter redis-cli
- 核心命令:
bf.add urls
http://example.com
:添加元素。bf.exists urls
http://example.com
:检查是否存在。 - 参数配置:bf.reserve urls 0.01 100 # 错误率1%,初始容量100
注意:过滤器需提前创建,重复创建会报错。
四、关键注意事项- 误判率权衡:错误率(error_rate)越低,位数组越大,需根据业务场景调整。
- 动态扩容:Redis布隆过滤器在超过initial_size后准确率下降,需预估数据量。
- 替代方案:若需删除功能,可考虑布谷鸟过滤器(Cuckoo Filter)。
通过合理使用布隆过滤器,可显著优化缓存命中率,降低数据库压力,尤其适合高并发、大数据量的去重或存在性校验场景。