在菜谱抓取过程当中,须要对已抓取的url进行去重,一开始使用的HashSet来去重,但占用内存较大。因而改用BloomFilter(goolge guava jar包中的一个工具类)来去重。java
下面是对HashSet与BloomFilter的内存占用与误报率(明明不在集合中,却被当作已存在)的比较。maven
比较内存占用:工具
分别插入90万个由六位数字字符组成的字符串到HashSet与BloomFilter中。google
Set<String> set = new HashSet<>(); for(int i=10_0000; i<100_0000; i++) set.add(""+i);
//第一个参数表示将字符串插入到集合中 第二个参数表示预期插入数量 第三个表示能够接受的误报率 BloomFilter<CharSequence> bf = BloomFilter.create(Funnels.stringFunnel(Charset.defaultCharset()), 100_0000, 0.001); for(int i=10_0000; i<100_0000; i++) bf.put(i+"");
经过一个工具类计算获得它们内存占用量分别为:url
set memory: 87,588,704 (约为87M)
bloom filter memory: 1,797,624 (约为1M)spa
再比较误报率:.net
int falseHitCount = 0; Set<String> set = new HashSet<>(); for(int i=10_0000; i<100_0000; i++){ if(set.contains(i+"")) //插入set中以前 先判断是否存在 falseHitCount ++ ; set.add(i+""); }
int falseHitCount = 0; BloomFilter<CharSequence> bf = BloomFilter.create(Funnels.stringFunnel(Charset.defaultCharset()), 100_0000, 0.001); for(int i=10_0000; i<100_0000; i++){ if(bf.mightContain(i+"")) // 插入bloom filter中以前 先判断是否存在 falseHitCount++; bf.put(i+""); }
hashset flase hit count: 0
bloom filter false hit count : 54code
即HashSet不存在误报的状况, 而构造BloomFilter时第三个参数指定了误报率为千分之一,而实际的误报率为54 / 90_0000.orm
总结:xml
若业务能够容忍个别的误报(如漏抓个别菜谱)的话, 能够考虑使用BloomFilter来代替HashSet。
补充:
计算对象大小,能够参考此篇博文:
http://blog.csdn.net/xieyuooo/article/details/7068216
Guava maven坐标:
<dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> <version>15.0</version> </dependency>