[爬虫进阶]使用布隆过滤器去重
原文链接: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%)