當內存是瓶頸時,HashSet的一個替代類

在菜譜抓取過程當中,須要對已抓取的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>
相關文章
相關標籤/搜索