[爬蟲進階]使用布隆過濾器去重
原文鏈接:https://www.cnblogs.com/blog5277/p/9340637.html
原文作者:博客園--曲高終和寡
*******************如果你看到這一行,說明爬蟲在本人還沒有發布完成的時候就抓走了我的文章,導致內容不完整,請去上述的原文鏈接查看原文****************
寫爬蟲的人,一定會遇到很多問題
尤其是寫分布式,大規模爬蟲的時候,
這一條數據是否已經在數據庫里了?
是否已經在本機的內存里了?
是否已經在別的服務器的內存里了?
解決的辦法有很多,不同場景要用不同的解決方案.但是有一點,去重終歸是要拿這條數據和一個數據集作比較的.
那這個數據集越大,比較就越耗費資源(內存,時間),那有沒有什么業內通用的解決辦法呢?自然是有的,兩個:
bitmap和布隆過濾器
bitmap有一個缺點:它占用的空間會隨着這個數據集里面最大的空間變大而線性變大.(解決方案是可以hash一下,不過這樣的話又增加了錯誤率)
布隆過濾器的缺點就是:會有一定的錯誤率.
具體的研究請參考:
https://blog.csdn.net/zdxiq000/article/details/57626464
https://blog.csdn.net/tianyaleixiaowu/article/details/74721877
這兩篇文章,詳細的講解了bitmap和布隆過濾器的原理
其實知道了原理,絕大多數人也寫不出來代碼實現,寫出來了,也不一定能比大神寫的更好更優雅,說不定會有隱藏的BUG坑.那么有沒有現成的工具使用呢?自然是有的,Google公司出品的工具包里面就有.去搜索"guava maven",招待最新的版本,現在是這個:
<!-- https://mvnrepository.com/artifact/com.google.guava/guava --> <dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> <version>25.1-jre</version> </dependency>
然后寫一個測試類:
public static void main(String[] args) { try { int size = 1000000; BloomFilter<Integer> bloomFilter = BloomFilter.create(Funnels.integerFunnel(), size); Instant now0 = Instant.now(); for (int i = 0; i < size; i++) { bloomFilter.put(i); } Instant now1 = Instant.now(); System.out.println("錄入" + size + "條數據共耗時:" + (now1.toEpochMilli() - now0.toEpochMilli())); Instant now2 = Instant.now(); for (int i = 0; i < size; i++) { if (!bloomFilter.mightContain(i)) { System.out.println("有漏掉的"); } } Instant now3 = Instant.now(); System.out.println("判斷" + size + "條在過濾器中的數據共耗時:" + (now3.toEpochMilli() - now2.toEpochMilli())); Instant now4 = Instant.now(); List<Integer> list = new ArrayList<Integer>(1000); for (int i = size + size / 10; i < size + (size * 2) / 10; i++) { if (bloomFilter.mightContain(i)) { list.add(i); } } Instant now5 = Instant.now(); System.out.println("判斷" + size / 10 + "條不在過濾器中的數據共耗時:" + (now5.toEpochMilli() - now4.toEpochMilli())); System.out.println("有誤判的數量:" + list.size()); } catch (Exception e) { e.printStackTrace(); } }
執行測試就知道了,速度非常快,占空間非常低.
不過記得,谷歌的方法默認誤判率是3%,你可以控制這個的大小,如下圖所示:
但是這樣的話,占用的空間就變大了.可以自己衡量.
(我是傾向於默認的3%的,因為這個誤判,是100%不會放過重復數據的,不過會把一些要抓的東西漏抓了而已.大規模的爬蟲,爬的數據何止千千萬,也不差這3%)