常用url消重算法:
1 基于hash算法的存储
对于每个给定的url,都是用一个已经建立好的hash算法把它映射到某个物理地址上,当我们要检验某个url是否存在时只要将这个url进行hash映射,如果映射后的地址已经存在,则说明当前这个url已经存在。否则将url和它所映射的地址作为键值对放入一个hash表中,这就需要我们设计的hash函数很好,不然在映射的过程中发生较多的冲突就会对结果照成影响。另一方面,我们将url作为键,而url的字符串也浪费了比较大的空间,显然,对于较多的url消重,这种方法并不适合。
2 基于布隆过滤器算法的消重
布隆过滤器是一个非常好的数据结构,它实际上是一个很长的二进制向量和一系列随即映射函数,它可以用来检测一个元素是否在一个集合中,后来也被用到表示网页的url上。
使用布隆过滤器的优劣:
优点:它的空间效率和查询时间都高于一般的算法。
缺点:有一定的误识别率。(虽然有一定的误识别率,但在大量的信息搜索中,它还是一种比较好的方法)
布隆算法的基本思想:
1 设一个数据集合A={... ...}中有n个元素。
2 用一个长度为m的位向量表示V表示集合中的元素,并初始化为0。
3 写好k个具有均匀分布特性的散列函数。
4 对于元素的加入操作首先通过k个散列函数产生k个随即数h1,h2,h3... ...hk,并将V集合中对应的h1,h2... ... hk的位置置为1。查找操作同理,对于要查找的元素先通过散列函数得到k个随机数,然后判断V集合中这k个位置是否为1,如果为1则说明该元素已经有了。
误判率的计算:
上面已经说了这种算法存在一定的误判率,那该如何将这种误判率降到最小呢?
设m为bit数,n为元素个数,k为散列函数的个数,当k = 0.7 * m/n时算法的误判率最小。(具体证明省略)
基于布隆算法的网页url消重的实现:
import java.util.BitSet;
public class BloomFilterTest {
private BitSet bits;
private int defaultsize = 2 << 24;
private int basicsize = defaultsize - 1;
public BloomFilterTest() {
this.bits = new BitSet(defaultsize);
}
public void add(String url) {
if (url == null) {
return;
}
int pos1 = hash1(url);
int pos2 = hash1(url);
int pos3 = hash1(url);
bits.set(pos1);
bits.set(pos2);
bits.set(pos3);
}
public boolean contains(String url) {
if (url == null) {
return true;
}
int pos1 = hash1(url);
int pos2 = hash1(url);
int pos3 = hash1(url);
if (bits.get(pos1) && bits.get(pos2) && bits.get(pos3)) {
return true;
}
return false;
}
public int hash1(String line) {
int h = 0;
for (int i = 0; i < line.length(); i++) {
h = h * 31 + line.charAt(i);
}
return check(h);
}
public int hash2(String line) {
int h = 0;
for (int i = 0; i < line.length(); i++) {
h = h * 33 + line.charAt(i);
}
return check(h);
}
public int hash3(String line) {
int h = 0;
for (int i = 0; i < line.length(); i++) {
h = h * 37 + line.charAt(i);
}
return check(h);
}
public int check(int h) {
return basicsize & h;
}
public void test() {
String urls[] = { "www.baidu.com", "www.google.com", "www.sina.com",
"www.renren.com", "www.sohu.com" };
for (int i = 0; i < urls.length; i++) {
add(urls[i]);
}
String testUrls[] = { "www.google.com", "www.dangdang.com",
"www.360buy.com", "www.baidu.com" };
for (int i = 0; i < testUrls.length; i++) {
if (contains(testUrls[i])) {
System.out.println("找到匹配的网址: " + testUrls[i]);
} else {
System.out.println("未找到匹配的网址");
}
}
}
}
public class MainBloomFilter {
public static void main(String[] args) {
BloomFilterTest bft = new BloomFilterTest();
bft.test();
}
}
测试结果:
找到匹配的网址: www.google.com
未找到匹配的网址
未找到匹配的网址
找到匹配的网址: www.baidu.com