/ 采用普通过滤器的方式进行词的查询
startTime = System.currentTimeMillis();
nfMap = tool.queryDatasByNF();
endTime = System.currentTimeMillis();
System.out.println("普通遍历查询操作耗时" + (endTime - startTime) + "ms");
boolean isExist;
boolean isExist2;
rightCount = 0;
queryDatas = tool.getQueryDatas();
totalCount = queryDatas.size();
for (String qWord: queryDatas) {
// 以遍历的查询的结果作为标准结果
isExist = nfMap.get(qWord);
isExist2 = bfMap.get(qWord);
if (isExist == isExist2) {
rightCount++;
}else{
System.out.println("预判错误的词语:" + qWord);
}
}
System.out.println(MessageFormat.format(
"Bloom Filter的正确个数为{0},总查询数为{1}个,正确率{2}", rightCount,
totalCount, 1.0 * rightCount / totalCount));
}
}
在算法的测试类中我对于Bloom Filter和普通的遍历搜索方式进行了时间上的性能比较,当数据量比较小的时候,其实是看不出什么差距,甚至有可能布隆过滤器所花的时间可能更长比如我下面的某次测试结果:
?
?
BloomFilter算法耗时2ms
普通遍历查询操作耗时0ms
Bloom Filter的正确个数为11,总查询数为11个,正确率1
但是当我用真实的测试数据进行测试,我把原始数据缓存了一篇标准的文档,然后把查询的结果词语数量进行了翻倍,然后执行同样的程序结果变为了下面这个样子:
?
?
BloomFilter算法耗时16ms
普通遍历查询操作耗时47ms
Bloom Filter的正确个数为2,743,总查询数为2,743个,正确率1
其实这还不足以模拟海量数据的场景,对于这个结果也不难理解,普通的暴力搜寻,是和原始数据的总量相关,时间复杂度为O(n)的,而Bloom Filter,则是常量级别,做一个哈希映射就OK 了,时间复杂度O(l),
?
算法小结
算法在实现的过程中遇到了一些小问题,第一就是在使用哈希函数的时候,因为我是随机的选了3个字符哈希函数,后来发现老是会越界,一越界数值就会变为负的再通过BitSet就会报错,原本在C语言中可以用unsigned int来解决,java中没有这个概念,于是就直接取hash绝对值了。Bloom Filter算法的一个特点是数据可能会出现误判,但是绝对不会漏判,误判就是把不是存在集合中的元素判定成有,理由是哈希冲突可能造成此结果,而漏判指的是存在的元素判定成了不存在集合中,这个是绝对不可能的,因为如果你存在,你所代表的位置就一定会有被哈希映射到,一旦映射到了,在你再去查找就不会漏掉。算法的应用范围其实挺多的,典型的比如垃圾邮箱地址的过滤。
?