BitSet基础
我们会遇到这样的需求,在海量数据中找出某个数据,我们想要的就是BitSet,BitSet本质是一个bit数组,使用1表示存在,0表示不存在。
简单使用示例:
BitSet bitSet = new BitSet(10);# 数组大小10
bitSet.set(1); # 索引1,记1
bitSet.set(2); # 索引2,记1
System.out.println(bitSet.get(1212));# 索引1212,没有数据,所以为0
System.out.println(bitSet.get(1));# 索引1,值为1,表示存在
BitSet占用空间小,1G的空间,可以表示85亿的不同数,所以广泛应用于大数据处理。
当然,BitSet也有不好的地方,
- 当数据分布不均匀,BitSet造成空间浪费。比如1,2,999,存入bitSet的时候,需要初始化BitSet空间为999,有效位置只有3个,其他都被浪费。
- BitSet只面向数字,且是正数,其他类型需要转为int类型,但是转换的时间也难免出现重复,BitSet准确率则降低。
所以,guava的BloomFilter诞生了,它就是bitSet的增强版本。
BloomFilter布隆过滤器
话不多说,使用起来很方便,如下:
- 引入google的guava pom
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>19.0</version>
</dependency>
- 实现代码
BloomFilter blackListIps = BloomFilter.create(Funnels.stringFunnel(Charset.forName("utf-8")),10000);
blackListIps.put("192.168.2.1");
blackListIps.put("192.168.2.3");
blackListIps.put("192.168.3.3");
System.out.println(blackListIps.mightContain("192.168.2.1"));
System.out.println(blackListIps.mightContain("192.168.4.1"));
应用
- 缓存穿透
在使用缓存时候,需要注意很多的坑,其中黑客利用不存在的key去进行缓存穿透,很容易将DB打爆,BloomFilter就可以派上用场了,在每次查询redis之前加个BloomFilter,看是否存在key,没有则直接返回空,防止无效请求到db。
- 推荐内容去重
- 爬虫URL判重
- 垃圾邮件过滤