在爬虫系统中,在内存中维护着两个关于URL的队列,ToDo队列和Visited队列,ToDo队列存放的是爬虫从已经爬取的网页中解析出来的即将爬取的URL,但是网页是互联的,很可能解析出来的URL是已经爬取到的,因此需要VIsited队列来存放已经爬取过的URL。当爬虫从ToDo队列中取出一个URL的时候,先和Visited队列中的URL进行对比,确认此URL没有被爬取后就可以下载分析来。否则舍弃此URL,从Todo队列取出下一个URL继续工作。

  然后,我们知道爬虫在爬取网页时,网页的量是比较大的,直接将所有的URL直接放入Visited队列是很浪费空间的。因此引入bloom filter!

(关于使用bloomfilter的原因:

visited队列中url过多,消耗内存空间是一方面。还有一个重要的原因,在从todo队列中取出一个新的URL时,必须和 visited中所有URL比较,确保没有处理过。那么如果直接比较的话,是要比较N(visited中所有url个数)次的,而且这个N相当大,效率明 显不够。采用bloom filter,最多只要比较K(我在文章中写的,相互独立的散列函数的个数)次,因为只要一个散列函数的散列值对应的位是0,就可以确定这个URL没有处 理过。

  我们把bloom filer设置为m个bit,全部初始为0。

  对每一个URL,进行K(K<m)次相互独立的哈希,一共得到K个值,将这K个值在bloom filter中对应的bit位置1。

  经过上述处理的bloom filter实际上构成了我们所说的Visited队列,当我们从ToDo队列中取出一个新的URL时,同样,进行相同的K次哈希,每进行一次哈希,查看bloom filter中对应位,只要发现某位是0,就可以确定这个URL是没有处理过的,可以继续下载处理。

  那么,原理清楚之后,还有几个问题没有解决。

  1、bloom filter是有可能发生错误的,因为不处理碰撞,也就是说,有可能把不属于这个集合的元素误认为属于这个集合

  错误率的计算:

  在n个URL都进行k次散列加入之后,bloomfilter中某位是0的概率

    

  错误率(即一个新的URL恰好k次散列的值对应的位都已经是1的概率)

   

  2、哈希函数个数K的确定

  k = ln2· (m/n)时(具体数学分析见http://blog.csdn.net/jiaomeng/article/details/1495500)

  3、bloomfilter位数M的确定

  我们可以想到,M的大小越大,错误率就会越小,但是数学证明给出了一个下界。即M = log2 e N = 1.44N。

  附上java代码

 /**屈永泉 布隆过滤器 快速确定哪些网页已经被下载过*/

 package crawler;

 import java.util.BitSet;

 public class BloomFilter {
private int defaultSize = << ;
private int basic = defaultSize - ;
private BitSet bits = new BitSet(defaultSize); private int[] lrandom(String key) { // 产生八个随机数并返回
int[] randomsum = new int[];
for (int i = ; i < ; i++)
randomsum[] = hashCode(key, i + );
return randomsum;
} // 将一个URL加入
public synchronized void add(String key) {
int keyCode[] = lrandom(key);
for (int i = ; i < ; i++)
bits.set(keyCode[i]); // 将指定索引处的位设置为 true
}
} // 判断一个URL是否存在
public boolean exist(String key) {
int keyCode[] = lrandom(key);
if (bits.get(keyCode[])
&& bits.get(keyCode[]) // 返回指定索引处的位值。
&& bits.get(keyCode[]) && bits.get(keyCode[])
&& bits.get(keyCode[]) && bits.get(keyCode[])
&& bits.get(keyCode[]) && bits.get(keyCode[])) {
return true;
}
return false;
} private int hashCode(String key, int Q) {
int h = ;
int off = ;
char val[] = key.toCharArray(); // 将此URl转换为一个新的字符数组
int len = key.length();
for (int i = ; i < len; i++) {
h = ( + Q) * h + val[off++];
}
return basic & h;
} /* public static void main(String[] args) { // TODO Auto-generated method
long pre = 0;
long post = 0;
pre = System.nanoTime();
BloomFilter f = new BloomFilter(); //初始化
f.add("http://www.agrilink.cn/"); f.add("http://www.baidu.com/");
System.out.println(f.exist("http://www.baidu.com/"));
System.out.println(f.exist("http://www.baidud.com/"));
post = System.nanoTime();
System.out.println("Time: " + (post - pre)); }
*/ }

爬虫技术之——bloom filter(含java代码)的更多相关文章

  1. golang学习笔记17 爬虫技术路线图,python,java,nodejs,go语言,scrapy主流框架介绍

    golang学习笔记17 爬虫技术路线图,python,java,nodejs,go语言,scrapy主流框架介绍 go语言爬虫框架:gocolly/colly,goquery,colly,chrom ...

  2. 十大经典排序算法最强总结(含JAVA代码实现)(转)

    十大经典排序算法最强总结(含JAVA代码实现)   最近几天在研究排序算法,看了很多博客,发现网上有的文章中对排序算法解释的并不是很透彻,而且有很多代码都是错误的,例如有的文章中在“桶排序”算法中对每 ...

  3. 十大经典排序算法最强总结(含JAVA代码实现)

    最近几天在研究排序算法,看了很多博客,发现网上有的文章中对排序算法解释的并不是很透彻,而且有很多代码都是错误的,例如有的文章中在“桶排序”算法中对每个桶进行排序直接使用了Collection.sort ...

  4. JAVA十大经典排序算法最强总结(含JAVA代码实现)

    十大经典排序算法最强总结(含JAVA代码实现)   最近几天在研究排序算法,看了很多博客,发现网上有的文章中对排序算法解释的并不是很透彻,而且有很多代码都是错误的,例如有的文章中在“桶排序”算法中对每 ...

  5. 百度语音识别REST API用法(含JAVA代码)——不须要集成SDK的方法

    版权声明:本文为博主原创文章,未经博主同意不得转载. https://blog.csdn.net/zpf8861/article/details/32329457 上一篇文章http://blog.c ...

  6. 十大经典排序算法详细总结(含JAVA代码实现)

    原文出处:http://www.cnblogs.com/guoyaohua/p/8600214.html 0.排序算法说明 0.1 排序的定义 对一序列对象根据某个关键字进行排序. 0.2 术语说明 ...

  7. JAVA十大经典排序算法最强总结(含JAVA代码实现)

    0.排序算法说明 0.1 排序的定义 对一序列对象根据某个关键字进行排序. 0.2 术语说明 稳定:如果a原本在b前面,而a=b,排序之后a仍然在b的前面: 不稳定:如果a原本在b的前面,而a=b,排 ...

  8. Bloom Filter:海量数据的HashSet

    Bloom Filter一般用于数据的去重计算,近似于HashSet的功能:但是不同于Bitmap(用于精确计算),其为一种估算的数据结构,存在误判(false positive)的情况. 1. 基本 ...

  9. 十大经典排序算法最强总结(含Java、Python码实现)

    引言 所谓排序,就是使一串记录,按照其中的某个或某些关键字的大小,递增或递减的排列起来的操作.排序算法,就是如何使得记录按照要求排列的方法.排序算法在很多领域得到相当地重视,尤其是在大量数据的处理方面 ...

随机推荐

  1. webServer xampp的安装及使用

    一.下载: 西装xampp1.73版本,其他版本可能会出错,为了你能顺利安装,最好用此版本: 二.安装: 1.安装路径,最好不要放到系统盘去[c:],建议非系统盘都可,尤其是早期的XAMPP版本可能默 ...

  2. 通过从代码层面分析Linux内核启动来探知操作系统的启动过程

    通过从代码层面分析Linux内核启动来探知操作系统的启动过程 前言说明 本篇为网易云课堂Linux内核分析课程的第三周作业,我将围绕Linux 3.18的内核中的start_kernel到init进程 ...

  3. Ubuntu Server搭建svn服务以及迁移方法【转】

    转自:http://www.linuxidc.com/Linux/2013-05/84693.htm Ubuntu Server搭建svn服务以及迁移方法 采用apache+svn,http访问方式. ...

  4. vmware装redhat该光盘无法被挂载

    为了考网工,没办法只能学学linux了,前天在vmware7装redhat 提示该光盘无法被挂载,还以为是光盘错误,换了N个盘,又装了很多次,最后观察到,换了盘之后点确定,里面就提示该光盘无法被挂载, ...

  5. Storm的容错性

    一.简介 如果在消息处理过程中出了一些异常,Storm 会重新安排这个出问题的 topology.Storm 保证一个 topology 永远运行(除非你显式杀掉这个 topology) . 当然,如 ...

  6. CodeIgniter的缓存设置

    数据库缓存 数据库缓存类允许你把数据库查询结果保存在文本文件中以减少数据库访问. 激活缓存需要三步: 在服务器上创建一个可写的目录以便保存缓存文件. 在文件 application/config/da ...

  7. (C#基础) byte[] 之初始化, 赋值,转换。

    byte[] 之初始化赋值 用for loop 赋值当然是最基本的方法,不过在C#里面还有其他的便捷方法. 1. 创建一个长度为10的byte数组,并且其中每个byte的值为0. byte[] myB ...

  8. python练习程序(c100经典例1)

    题目: 有1.2.3.4个数字,能组成多少个互不相同且无重复数字的三位数?都是多少? num=0; for i in range(1,5): for j in range(1,5): for k in ...

  9. (六) 6.1 Neurons Networks Representation

    面对复杂的非线性可分的样本是,使用浅层分类器如Logistic等需要对样本进行复杂的映射,使得样本在映射后的空间是线性可分的,但在原始空间,分类边界可能是复杂的曲线.比如下图的样本只是在2维情形下的示 ...

  10. yaf框架流程三

    路由的原理请看http://yaf.laruence.com/manual/yaf.routes.html这个链接 要点:路由的顺序是堆栈模式的,及最后添加的路由规则最优先.由上两篇可知,定义的第一条 ...