一 序:
小规模的定向爬取,url管理方式比较多,:
1.直接存库
2.md5后存库
或者保存到hashset都能起到类似效果,但是数据量大了之后,上面的方法就扛不住了。
二 Bloom Filter
详情参考这篇,http://www.cnblogs.com/heaad/archive/2011/01/02/1924195.html
Bloom Filter算法如下:
创建一个m位BitSet,先将所有位初始化为0,然后选择k个不同的哈希函数。第i个哈希函数对字符串str哈希的结果记为h(i,str),且h(i,str)的范围是0到m-1 。
下图是Bloom Filter加入字符串过程
爬虫链接的去重:大的爬虫系统有成千上万的链接需要去爬,而且需要保证爬虫链接不能循环。这样就需要链接列表的去重。把链接Hash后存放在BitSet中,然后在爬取之前判断是否存在。
网站UV统计:一般同一个用户的多次访问是要过滤掉的,一般大型网站的UV是巨大的,这样使用BloomFilter就能较高效的实现。
demo:
package com.daojia.bloomfilter;
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函数,采用简单的加权和hash
public 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;
}
}
public static void main(String[] args) {
// TODO Auto-generated method stub
BloomFilter f = new BloomFilter();
f.add("http://www.baidu.com/");
f.add("http://www.sina.com/");
System.out.println(f.contains("http://www.baidu.com/"));
System.out.println(f.contains("http://www.taobao.com/"));
}
}
输出:
true
false
三 关于分布式:
上面我们是自己基于单节点JDK的filter,我们通常的爬虫会采用分布式多节点多线程来处理的,因为毕竟目标target很多。
所以网上提出了一种改进的策略:结合Redis的BitMap就能够完美的实现这一需求。利用redis的高性能以及通过pipeline将多条bit操作命令批量提交,实现了多机BloomFilter的bit数据共享。
这块我没有去测试,实际项目中使用前应该结合数据去测试下,主要验证下存储数据占用内存及误判率大小等。