同一个网页链接有可能被包含在多个页面中,这就会导致爬虫在爬取的过程中,重复爬取相同的网页。如果你是一名负责爬虫的工程师,你会如何避免这些重复的爬取呢?
假设每个URL64字节,10亿个URL大概需要60G内存,如果是散列表存储,因为装载因子和存储链表指针等,可能需要100G以上。另外散列表的查询时间复杂度是O(1), 但是大O时间复杂度表示法会忽略掉常数、系数和低阶,实际查询时间可能不低。
由此,思考有没有占用内存更少,查询更快的数据存储结构和算法?
有1千万个整数,整数的范围在1到1亿之间。如何快速查找某个整数是否在这1千万个整数中呢?
public class BitMap {
private char[] bytes;
private int nbits;
public BitMap(int nbits) {
this.nbits = nbits;
this.bytes = new char[nbits/8+1];
}
public void set(int k) {
if (k > nbits) return;
int byteIndex = k / 8;
int bitIndex = k % 8;
bytes[byteIndex] |= (1 << bitIndex);
}
public boolean get(int k) {
if (k > nbits) return false;
int byteIndex = k / 8;
int bitIndex = k % 8;
return (bytes[byteIndex] & (1 << bitIndex)) != 0;
}
}
优点:访问效率高,如果数据范围不大,非常节省内存。
对位图的改进。
简单点讲:多个哈希函数一起定位一个数据。
插入过程: 使用K个哈希函数,对同一个数字进行求哈希值,得到K个不同的哈希值,分别记作 X 1 X_{1} X1, X 2 X_{2} X2, X 3 X_{3} X3,…, X K X_{K} XK。我们把这K个数字作为位图中的下标,将对应的BitMap[ X 1 X_{1} X1],BitMap[ X 2 X_{2} X2],BitMap[ X 3 X_{3} X3],…,BitMap[ X K X_{K} XK]都设置成true,也就是说,用K个二进制位,来表示一个数字的存在。
查询过程: 同样的K个哈希函数,对这个数字求哈希值,分别得到 Y 1 Y_{1} Y1, Y 2 Y_{2} Y2, Y 3 Y_{3} Y3,…, Y K Y_{K} YK。看这K个哈希值,对应位图中的数值是否都为true,如果都是true,则说明,这个数字存在,如果有其中任意一个不为true,那就说明这个数字不存在。

k个哈希函数降低哈希冲突,但带来误判问题。
