在菜譜抓取過程當中,須要對已抓取的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>