代码测试
package com.nobody; import com.google.common.hash.BloomFilter; import com.google.common.hash.Funnels; /** * @Description * @Author Mr.nobody * @Date 2021/3/6 * @Version 1.0 */ public class GuavaDemo { public static void main(String[] args) { // 假设元素个数为10万 int size = 100000; // 预计元素为10万,误差率为1% BloomFilter<Integer> bloomFilter = BloomFilter.create(Funnels.integerFunnel(), size, 0.01); // 将1至100000这十万个数映射到布隆过滤器中 for (int i = 1; i <= size; i++) { bloomFilter.put(i); } // 检查已在过滤器中的值,是否有匹配不上的 for (int i = 1; i <= size; i++) { if (!bloomFilter.mightContain(i)) { System.out.println("存在不匹配的值:" + i); } } // 检查不在过滤器中的1000个值,是否有匹配上的 int matchCount = 0; for (int i = size + 1; i <= size + 1000; i++) { if (bloomFilter.mightContain(i)) { matchCount++; } } System.out.println("误判个数:" + matchCount); } }结果存在的10万个元素都匹配上了;不存在布隆过滤器中的1千个元素,有10个误判。
误判个数:10当fpp的值改为为0.001,即降低误差率时,误判个数为0个。
误判个数:0分析结果可知,误判率确实跟我们传入的容错率差不多,而且在布隆过滤器中的元素都匹配到了。
源码分析
通过debug创建布隆过滤器的方法,当预计元素为10万个,fpp的值为0.01时,需要位数958505个,hash函数个数为7个。
当预计元素为10万个,fpp的值为0.001时,需要位数1437758个,hash函数个数为10个。
得出结论
容错率越大,所需空间和时间越小,容错率越小,所需空间和时间越大。
理论上存10万个数,一个int是4字节,即32位,需要320万位。如果使用HashMap存储,按HashMap50%的存储效率,需要640万位。而布隆过滤器即使容错率fpp为0.001,也才需要1437758位,可以看出BloomFilter的存储空间很小。
五 扩展知识点假如有一台服务器,内存只有4GB,磁盘上有2个大文件,文件A存储100亿个URL,文件B存储100亿个URL。请问如何模糊找出两个文件的URL交集?如何精致找出两个文件的URL交集。
模糊交集:
借助布隆过滤器思想,先将一个文件的URL通过hash函数映射到bit数组中,这样大大减少了内存存储,再读取另一个文件URL,去bit数组中进行匹配。
精致交集:
对大文件进行hash拆分成小文件,例如拆分成1000个小文件(如果服务器内存更小,则可以拆分更多个更小的文件),比如文件A拆分为A1,A2,A3...An,文件B拆分为B1,B2,B3...Bn。而且通过相同的hash函数,相同的URL一定被映射到相同下标的小文件中,例如A文件的被映射到A1中,那B文件的也一定被映射到B1文件中。最后再通过求相同下标的小文件(例如A1和B1)(A2和B2)的交集即可。
欢迎关注微信公众号:「Java之言」技术文章持续更新,请持续关注......