布隆过滤器、布隆算法笔记
文章目录
- 场景
- 和hashmap的对比
- java实现布隆算法
- 第三方类库-guava类库
- 第三方类库-bitset
- 自己用代码实现
- 优势和劣势
- 布隆过滤器如果超过条数限制会怎样 // TODO
这里的布隆不是lol的布隆啊,此布隆非彼布隆。
场景
布隆过滤器适用的场景。
1、key值较长。
2、数据量特别大。
典型的就是网页url的爬取落库,如何避免(大致避免)重复落库。
和hashmap的对比
肯定会有个疑问,为什么要用布隆过滤器,直接用hashmap不就行吗?
好问题。
数据量不是特别大时,例如100万,用hashmap也是可以的。但是如果是十亿呢?
布隆过滤器占用空间小很多,而且效率高。
主要原因就2个:
1、key值较长时,如url,map存取和检索效率较低(对比布隆算法)。
2、数据量很大时,map占用空间较大(对比布隆算法)。
这篇博客回答的不错。
https://blog.51cto.com/u_14691/6888196
java实现布隆算法
第三方类库-guava类库
引入maven依赖:
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>30.1.1-jre</version> <!-- 请使用最新版本 -->
</dependency>
代码:
import com.google.common.hash.BloomFilter;
import com.google.common.hash.Funnels;
public class BloomFilterExample {
public static void main(String[] args) {
// 创建一个布隆过滤器,预计会有10000个元素,误判率为3%
BloomFilter<Integer> bloomFilter = BloomFilter.create(
Funnels.integerFunnel(), 10000, 0.03);
// 添加一些元素到布隆过滤器中
bloomFilter.put(1);
bloomFilter.put(2);
// 检查元素是否可能在集合中(可能存在误判)
System.out.println(bloomFilter.mightContain(1)); // true
System.out.println(bloomFilter.mightContain(3)); // false,除非3也被加入过
}
}
第三方类库-bitset
引入maven依赖:
<dependency>
<groupId>com.bitset</groupId>
<artifactId>bloomfilter</artifactId>
<version>1.0.8</version> <!-- 请使用最新版本 -->
</dependency>
代码:
import com.bitset.bloomfilter.*;
import java.util.BitSet;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.List;
public class BloomFilterExample {
public static void main(String[] args) {
// 创建一个布隆过滤器,预计会有10000个元素,误判率为3%
int size = 10000; // 预计元素数量
double fpp = 0.03; // 误判率(False Positive Probability)
BloomFilter<Integer> bloomFilter = new BloomFilter<>(size, fpp);
// 添加一些元素到布隆过滤器中
bloomFilter.add(1);
bloomFilter.add(2);
// 检查元素是否可能在集合中(可能存在误判)
System.out.println(bloomFilter.contains(1)); // true
System.out.println(bloomFilter.contains(3)); // false,除非3也被加入过
}
}
自己用代码实现
网上代码也烂大街了,随便找个,代码:
public class BloomFilter {
private BitSet bitSet;
private int size;
private List<Integer> hashFunctions;
public BloomFilter(int expectedElements, double falsePositiveProbability) {
size = (int) (-expectedElements * Math.log(falsePositiveProbability) / (Math.log(2) * Math.log(2)));
bitSet = new BitSet(size);
int numHashFunctions = (int) (size / expectedElements * Math.log(2));
hashFunctions = IntStream.range(0, numHashFunctions)
.map(i -> i * 5 + 3) // 简单的hash函数示例
.boxed()
.collect(Collectors.toList());
}
public void add(String item) {
hashFunctions.forEach(hashFunc -> {
int index = Math.abs(hashFunc * item.hashCode() % size);
bitSet.set(index);
});
}
public boolean mightContain(String item) {
return hashFunctions.stream()
.allMatch(hashFunc -> {
int index = Math.abs(hashFunc * item.hashCode() % size);
return bitSet.get(index);
});
}
}
优势和劣势
布隆过滤器的优势:
布隆过滤器相对于其他数据结构在时空上有巨大优势,占用内存少,查询和插入元素的时间复杂度都是O(k)
可以准确判断元素不存在于布隆过滤器中的场景
散列函数可以独立设计
布隆过滤器不需要存储元素本身,适用于某些数据敏感和数据严格保密的场景
布隆过滤器的劣势:
不能准确判断元素必定存在于布隆过滤器中的场景,存在误判率,在k和m固定的情况下,添加的元素越多,误判率越高
没有存储全量的元素,对于一些准确查询或者准确统计的场景不适用
原生的布隆过滤器无法安全地删除元素
布隆过滤器如果超过条数限制会怎样 // TODO
例如 10个大小 错误因子0.03
如果第11个进来会怎样?