Bloom Filter 原理和源码讲解
问题的提出:假设有A,B两个文件,文件里面都是url地址,各有10亿条,如何找出AB两个文件里面都存在的Url。(内存装不下任何一个文件的十分之一)
解决方法:首先在不考虑内存的情况下,我们最传统的方法就是是遍历AB两个文件一个一个的比较,这个方法是能找出结果,但是时间复杂度是o(n2),对于没一个url都要去遍历一遍另外的一个文件。
而Bloom Filter可以解决该问题,同时在时间和空间的开销上都是很小的。原理如下:
1.建立一个byte数组 ,长度为LEN,数组的长度越长发送错误的概率越低
2.读取A的每一个记录,对每一个记录建立一个hash,假设hash值是D
3可以将数组的(LEN-1) & D 位标识值1
4.对于查询是否包含该记录的请求,可以直接查看数组的(LEN-1) & D 的值是否为1,如果为1表示存在
测试代码如下:
import java.util.ArrayList; import java.util.List; /** * 布尔过滤,bit的越大发生的错误的概率越小,哈希的函数和次数也决定啦错误的概率 * * @author zxc * */ public class BoolFilter { private byte[] bits; private int size; public BoolFilter(int size) { this.size = size; bits = new byte[size]; } public void add(String str) { int hash = str.hashCode(); bits[(size - 1) & hash] = 1; } public boolean contain(String str) { return bits[(size - 1) & str.hashCode()] == 1; } /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub BoolFilter filter = new BoolFilter(10000000); List<String> list = new ArrayList<String>(); for (int i = 0; i < 99; i++) { String str = java.util.UUID.randomUUID().toString(); list.add(str); filter.add(str); } for (int i = 0; i < 10; i++) { String str = java.util.UUID.randomUUID().toString(); System.out.println(filter.contain(str)); } System.out .println("----------------------------------------------------------"); for (int i = 0; i < 10; i++) { // String str = java.util.UUID.randomUUID().toString(); System.out.println(filter.contain(list.get(i))); } } }
可能大家会有疑问为什么byte数组搞的那么长10000000,这个该算法的本身有关,如果byte的数组长度为1,那么对于任何的处理都是查询处理存在。
而byte越长,那么出现的hash碰撞的概率就越小,同时hash的次数越多出现的概率也越低,但是都不能保证不发生错误。只是降低了错误的概率。
浙公网安备 33010602011771号