来源:百度文库 编辑:九乡新闻网 时间:2024/07/14 02:08:04
对isURLVisited和politeness的分析
分析isURLVisited
这主要是在Frontier里实现的,当一个链接要进入等待队列时需要先判断是否已经被抓取过,如果已经抓取过则不进入,否则进入。
分析isURLVisited就要从分析存储已抓取url的结构说起。Heritrix在内部使用了BerkeleyDB(Database)。BerkeleyDB就是一个HashTable,它能够按“key/value”方式来保存数据。它是一套开放源代码的嵌入式数据库,为应用程序提供可伸缩的、高性能的、有事务保护功能的数据管理服务。BerkeleyDB就是一个Hash Table,它能够按“key/value”方式来保存数据。使用BerkeleyDB时,数据库和应用程序在相同的地址空间中运行,所以数据库操作不需要进程间的通讯。另外,BerkeleyDB中的所有操作都使用一组API接口。因此,不需要对某种查询语言(比如SQL)进行解析,也不用生成执行计划,这就大大提高了运行效率。解决了多线程访问、超大容量的问题。
Heritrix中涉及存储url的主要的类有UriUniqFilter、FPMergeUriUniqFilte、SetBasedUriUniqFilter、BdbUriUniqFilter、BloomUriUniqFilter、emFPMergeUriUniqFilter和DiskFPMergeUriUniqFilter。
用户可以在创建一个爬取任务时选择BdbUriUniqFilter, BloomUriUniqFilter,emFPMergeUriUniqFilter和DiskFPMergeUriUniqFilter中的一种。默认是BdbUriUniqFilter。而且这也是在Heritrix抓取过程中使用的唯一一种方式。
Heritrix中涉及存储url的主要的类分布在org.archive.crawler.util包下,之间的继承关系如下图:
![](http://image36.360doc.cn/DownloadImg/2011/09/0518/17089818_1)
这里存储已经处理过的url的数据结构是Berkeley Database,叫做alreadySeen。
Java代码:
protected transientDatabase alreadySeen = null;
为了节省存储空间,alreadySeenUrl中存储的并不是url,而是url的fingerprint(64位)。为了不破坏url的局部性,分别对url的主机名和整个url计算fingerprint,然后把24位的主机名fingerprint和40位的url的fingerprint连接起来得到最后的64位的fingerprint。计算fingerprint是在createKey函数中实现。代码如下:
publicstatic long createKey(CharSequence uri) {
String url = uri.toString();
int index = url.indexOf(COLON_SLASH_SLASH);
if (index > 0) {
index = url.indexOf('/', index + COLON_SLASH_SLASH.length());
}
CharSequence hostPlusScheme = (index == -1)? url:url.subSequence(0, index);
long tmp = FPGenerator.std24.fp(hostPlusScheme);
return tmp | (FPGenerator.std40.fp(url)>>> 24);
}
setAdd函数把uri加入到数据库中,如果已经存在,则返回false,否则返回true。关键代码如下:(根据自己的理解加入了注释)
Java代码
protected boolean setAdd(CharSequence uri) {
DatabaseEntry key = new DatabaseEntry();
LongBinding.longToEntry(createKey(uri),key);//将uri的fingerprint从long类型转换成DatabaseEntry类型,以便于Database进行存储。
long started = 0;
OperationStatus status = null;
try {
if (logger.isLoggable(Level.INFO)) {
started = System.currentTimeMillis();
}
status = alreadySeen.putNoOverwrite(null, key,ZERO_LENGTH_ENTRY);//检查是否已经被抓取过,并返回状态给status
if (logger.isLoggable(Level.INFO)) {
aggregatedLookupTime +=
(System.currentTimeMillis() - started);
}
} catch (DatabaseException e) {
logger.severe(e.getMessage());
}
if (status == OperationStatus.SUCCESS) {
count++;
if (logger.isLoggable(Level.INFO)) {
final int logAt = 10000;
if (count > 0 &&((count % logAt) == 0)) {