zoukankan      html  css  js  c++  java
  • [爬虫进阶]使用布隆过滤器去重

    [爬虫进阶]使用布隆过滤器去重

    原文链接: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%)

  • 相关阅读:
    Android10_内容提供者_内容观察者_标题栏
    Android08_广播接受者_服务
    Android09_远程服务_系统服务_aidl
    Android07_多界面_Activity生命周期
    Android06_getpost提交_文件上传_多线程下载
    Android_handler_网络请求_img框架
    Android开发04
    java 正则表达式验证邮箱
    postman 基本用法
    java 微信申请退款的开发
  • 原文地址:https://www.cnblogs.com/blog5277/p/9340637.html
Copyright © 2011-2022 走看看