前言:

最近被网络爬虫中的去重策略所困扰。使用一些其他的“理想”的去重策略,不过在运行过程中总是会不太听话。不过当我发现了BloomFilter这个东西的时候,的确,这里是我目前找到的最靠谱的一种方法。

如果,你说URL去重嘛,有什么难的。那么你可以看完下面的一些问题再说这句话。

关于BloomFilter:

Bloom filter 是由 Howard Bloom 在 1970 年提出的二进制向量数据结构,它具有很好的空间和时间效率,被用来检测一个元素是不是集合中的一个成员。如果检测结果为是,该元素不一定在集合中;但如果检测结果为否,该元素一定不在集合中。因此Bloom filter具有100%的召回率。这样每个检测请求返回有“在集合内(可能错误)”和“不在集合内(绝对不在集合内)”两种情况,可见 Bloom filter 是牺牲了正确率以节省空间。

以前的去重策略:

1.想到过的URL去重策略

  • 在数据库中创建字段的UNIQUE属性
  • 在数据库中创建一个唯一的索引,在插入数据之前检查待插入的数据是否存在
  • 使用Set或HashSet保存数据,确保唯一
  • 使用Map或是一个定长数组记录某一个URL是否被访问过

2.以上去重策略存在的问题

(1)对于在数据库中创建字段的UNIQUE属性, 的确是可以避免一些重复性操作。不过在多次MySQL报错之后,程序可能会直接崩溃,因此这种方式不可取

(2)如果我们要在每一次插入数据之前都去检查待插入的数据是否存在,这样势必会影响程序的效率

(3)这种方式是我在第一次尝试的时候使用的,放弃继续使用的原因是:OOM。当然,这里并不是程序的内存泄露,而程序中真的有这么多内存需要被占用(因为从待访问队列中解析出来的URL要远比它本身要多得多)

(4)在前几篇博客中,我就有提到使用Map对象来保存URL的访问信息。不过,现在我要否定它。因为,在长时间运行之后,Map也是会占用大量的内存。只不过,会比第3种方式要小一些。下面是使用Map<Integer, Integer>去重,在长时间运行中内存的使用情况:

BloomFilter的使用:

1.一般情况下BloomFilter使用内存的情况:

2.爬虫程序中BloomFilter使用内存的情况(已运行4小时):

3.程序结构图

4.BloomFilter的一般使用

此处关于BloomFilter的Java代码部分,参考于:http://www.cnblogs.com/heaad/archive/2011/01/02/1924195.html

如果你看了上面的文章,相信你已经了解到布隆过滤器的空间复杂度是S(n)=O(n)。关于这一点,相信你已经从上面的内存使用情况中了解到了这一点。那么以下会是一些相关的Java代码展示。而在查重过程也很有效率,时间复杂度是T(n)=O(1)。

BloomFilter.java

import java.util.BitSet;public class BloomFilter {/* BitSet初始分配2^24个bit */private static final int DEFAULT_SIZE = 1 << 25;/* 不同哈希函数的种子,一般应取质数 */private static final int[] seeds = new int[] { 5, 7, 11, 13, 31, 37, 61 };private BitSet bits = new BitSet(DEFAULT_SIZE);/* 哈希函数对象 */private SimpleHash[] func = new SimpleHash[seeds.length];public BloomFilter() {for (int i = 0; i < seeds.length; i++) {func[i] = new SimpleHash(DEFAULT_SIZE, seeds[i]);}}// 将字符串标记到bits中public void add(String value) {for (SimpleHash f : func) {bits.set(f.hash(value), true);}}// 判断字符串是否已经被bits标记public boolean contains(String value) {if (value == null) {return false;}boolean ret = true;for (SimpleHash f : func) {ret = ret && bits.get(f.hash(value));}return ret;}/* 哈希函数类 */public static class SimpleHash {private int cap;private int seed;public SimpleHash(int cap, int seed) {this.cap = cap;this.seed = seed;}// hash函数,采用简单的加权和hashpublic int hash(String value) {int result = 0;int len = value.length();for (int i = 0; i < len; i++) {result = seed * result + value.charAt(i);}return (cap - 1) & result;}}
}

Test.java

public class Test {private final String[] URLS = {"http://www.csdn.net/","http://www.baidu.com/","http://www.google.com.hk","http://www.cnblogs.com/","http://www.zhihu.com/","https://www.shiyanlou.com/","http://www.google.com.hk","https://www.shiyanlou.com/","http://www.csdn.net/"};private void testBloomFilter() {BloomFilter filter = new BloomFilter();for (int i = 0; i < URLS.length; i++) {if (filter.contains(URLS[i])) {System.out.println("contain: " + URLS[i]);continue;}filter.add(URLS[i]);}}public static void main(String[] args) {Test t = new Test();t.testBloomFilter();}
}

5.BloomFilter在爬虫中过滤重复的URL

public class ParserRunner implements Runnable {private SpiderSet mResultSet = null;private WebInfoModel mInfoModel = null;private int mIndex;private final boolean DEBUG = false;private SpiderBloomFilter mFlagBloomFilter = null;public ParserRunner(SpiderSet set, WebInfoModel model, int index, SpiderBloomFilter filter) {mResultSet = set;mInfoModel = model;mIndex = index;mFlagBloomFilter = filter;}@Overridepublic void run() {long t = System.currentTimeMillis();SpiderQueue tmpQueue = new SpiderQueue();PythonUtils.fillAddressQueueByPython(tmpQueue, mInfoModel.getAddress(), mInfoModel.getLevel());WebInfoModel model = null;while (!tmpQueue.isQueueEmpty()) {model = tmpQueue.poll();if (model == null || mFlagBloomFilter.contains(model.getAddress())) {continue;}mResultSet.add(model);mFlagBloomFilter.add(model.getAddress());}tmpQueue = null;model = null;System.err.println("Thread-" + mIndex + ", UsedTime-" + (System.currentTimeMillis() - t) + ", SetSize = " + mResultSet.size());t = 0;}@SuppressWarnings("unused")private void sleep(long millis) {try {Thread.sleep(millis);} catch (InterruptedException e) {e.printStackTrace();}}
}

如果你看过我之前的博客,那么上面的这一段代码相信你会比较熟悉。

这段代码的功能是:生产者。从待访问队列中消费一个model,然后调用Python生产链接的列表Queue,并将生成的列表Queue offer到结果SpiderSet中。

网络爬虫:URL去重策略之布隆过滤器(BloomFilter)的使用相关推荐

  1. 海量数据去重hash与布隆过滤器

    海量数据去重hash与布隆过滤器 背景 缓存穿透 需求 set和map unordered_map 总结 布隆过滤器 代码 背景 在使⽤word⽂档时,word如何判断某个单词是 否拼写正确? ⽹络爬 ...

  2. Flink 结合 布隆过滤器(BloomFilter) 实现去重

    本文开头附:Flink 学习路线系列 ^ _ ^ 1.实时系统去重方案 使用Redis,将实时系统每条数据都去和 Redis 进行判断: 使用 HashSet,因为 HashSet 本身就是无序不重复 ...

  3. 布隆过滤器(BloomFilter)原理 实现和性能测试

    目录 BloomFilter的原理 如何确定最优的m和k? guava中的BloomFilter 使用案例 和HashSet对比 测试环境 测试方式 BloomFilter vs HashSet 在不 ...

  4. 布隆过滤器 - Redis 布隆过滤器,Guava 布隆过滤器 BloomFilter

    文章目录 布隆过滤器 - Redis 布隆过滤器,Guava 布隆过滤器 BloomFilter 1.布隆过滤器的起源,用途 2.布隆过滤器的概念 3.布隆过滤器的优缺点 1.优点 2.缺点 4.应用 ...

  5. 04 布隆过滤器BloomFilter

    是什么 布隆过滤器(英语:Bloom Filter)是 1970 年由布隆提出的. 它实际上是一个很长的二进制数组+一系列随机hash算法映射函数,主要用于判断一个元素是否在集合中. 通常我们会遇到很 ...

  6. scrapy去重原理,scrapy_redis去重原理和布隆过滤器的使用

    1.去重的应用场景: 如果你只是做一些简单的爬虫,可能不会遇到这种问题,可是如果你正在做一个大型的全站爬虫,或是一个持久化的爬虫,那你一定会遇到这样的问题:刚开始爬虫速度还可以,随着待爬取的队列达到数 ...

  7. 一道腾讯面试题:如何快速判断某 URL 是否在 20 亿的网址 URL 集合中?布隆过滤器...

    何为布隆过滤器 还是以上面的例子为例: 判断逻辑: 多次哈希: Guava的BloomFilter 创建BloomFilter 最终还是调用: 使用: 算法特点 使用场景 假设遇到这样一个问题:一个网 ...

  8. Hbase 解析(四) 布隆过滤器(BloomFilter)

    1.简介 1.1 介绍 Bloom filter是1970年引入的一种数据结构,在过去的十年中,由于它为网络主机之间的组成员信息传输提供了带宽效率,因此被网络研究界采用.发送者将信息编码成一个比特向量 ...

  9. 布隆过滤器-BloomFilter

    目录 一.概述 二.详解 三.实现 四.适用业务场景 一.概述 简单讲布隆过滤器就是判断一个列表中是否存在某个元素.一般在JAVA判断是否存在,我们可以Map,Set等容器.但是当数据量特别大的时候, ...

最新文章

  1. 基于SSM选课信息管理系统
  2. windows10下编译dllib报错: ERROR: Failed building wheel for dlib
  3. csdn博客如何更改图片大小
  4. asp.net中获取当前url的方法
  5. 类和对象:一些相关的BIF - 零基础入门学习Python040
  6. android生成png图片,Android 中将 base64图片 解码为.png图片
  7. 她,既是一个风华绝代的演员,更是WiFi之母...
  8. 感想篇:4)越来越精简的机械设计
  9. 每天进步一点点《ML - KNN》
  10. 避免eclipse下启动run就进入debug模式
  11. Odin学习1 属性框标签
  12. 案例:神经网络建模 + 可视化分析 = 提效增质的利器!
  13. swift野梦抄袭 taylor_断眉质疑Taylor Swift新歌抄袭《Next to Me》,双方粉丝掀起骂战...
  14. 如何系统学习计算机编程?自学还是培训?怎么选?
  15. 数据库应用系统的生命周期
  16. 注意力机制Effective Approaches to Attention-based Neural Machine Translation
  17. python与金融工程的区别_科研进阶 | 纽约大学 | 金融工程、量化金融、商业分析:Python金融工程分析...
  18. Sublime Plugin - Python PEP8 Autoformat
  19. delta和gamma中性_Delta中性
  20. python下载包失败,下载python包失败

热门文章

  1. C++ Primer 5th笔记(2)chapter 2变量和基本类型:constexpr 、auto、类型别名、decltype
  2. buu old-fashion
  3. [register]-TCR(Translation Control Register)寄存器详解
  4. python:将一个文件转换为二进制文件(binary)
  5. 两种方法设置html表格的宽高
  6. 虎符杯——虚拟机逆向
  7. 如何使用ThreadStackSpoofer隐藏Shellcode的内存分配行为
  8. 服务器指纹识别之 DNS TXT
  9. Windows进程与线程学习笔记(一)—— 进程结构体
  10. MySQL创建索引(CREATE INDEX)