这里主要是分析一下org.apache.nutch.crawl.LinkDb,它主要是用计算反向链接。
1. 运行命令 bin/nutch invertlinks
帮助参数说明:- Usage: LinkDb <linkdb> (-dir <segmentsDir> | <seg1> <seg2> ...) [-force] [-noNormalize] [-noFilter]
- linkdb output LinkDb to create or update
- -dir segmentsDir parent directory of several segments, OR
- seg1 seg2 ... list of segment directories
- -force force update even if LinkDb appears to be locked (CAUTION advised)
- -noNormalize don't normalize link URLs
- -noFilter don't apply URLFilters to link URLs
本地的运行结果为:
- lemo@debian:~/Workspace/java/Apache/Nutch/nutch-1.3$ bin/nutch invertlinks db/linkdb/ db/segments/20110822105243/
- LinkDb: starting at 2011-08-29 09:21:36
- LinkDb: linkdb: db/linkdb
- LinkDb: URL normalize: true
- LinkDb: URL filter: true
- LinkDb: adding segment: db/segments/20110822105243 // 加入新的segment库
- LinkDb: merging with existing linkdb: db/linkdb // 与原因的库进行合并
- LinkDb: finished at 2011-08-29 09:21:40, elapsed: 00:00:03
2. LinkDb主要源代码分析
在LinkDb主要是调用一个invert方法,这个方法做了两件事,+ 分析新输入的segment目录,产生新的反向链接库
+ 把新产生的反向链接库与原来的库进行合并
2.1 分析新输入的segment目录,主要代码如下:
- // 新建立一个MP任务
- JobConf job = LinkDb.createJob(getConf(), linkDb, normalize, filter);
- // 添加目录到输入路径,这里可能有多个输入路径, parse_data
- for (int i = 0; i < segments.length; i++) {
- if (LOG.isInfoEnabled()) {
- LOG.info("LinkDb: adding segment: " + segments[i]);
- }
- FileInputFormat.addInputPath(job, new Path(segments[i], ParseData.DIR_NAME));
- }
- // 提交MP任务
- try {
- JobClient.runJob(job);
- } catch (IOException e) {
- LockUtil.removeLockFile(fs, lock);
- throw e;
- }
下面来看一下createJob都做了些什么:
- private static JobConf createJob(Configuration config, Path linkDb, boolean normalize, boolean filter) {
- // 新成一个临时的目录
- Path newLinkDb =
- new Path("linkdb-" +
- Integer.toString(new Random().nextInt(Integer.MAX_VALUE)));
- JobConf job = new NutchJob(config);
- job.setJobName("linkdb " + linkDb);
- // 设置输出格式
- job.setInputFormat(SequenceFileInputFormat.class);
- // 配置Map,Combiner,Reducer方法
- job.setMapperClass(LinkDb.class);
- job.setCombinerClass(LinkDbMerger.class);
- // 如果配置了过滤或者规格化,并且没有找到老的linkdb目录,好就以filter和normalize进行配置
- // if we don't run the mergeJob, perform normalization/filtering now
- if (normalize || filter) {
- try {
- FileSystem fs = FileSystem.get(config);
- if (!fs.exists(linkDb)) {
- job.setBoolean(LinkDbFilter.URL_FILTERING, filter);
- job.setBoolean(LinkDbFilter.URL_NORMALIZING, normalize);
- }
- } catch (Exception e) {
- LOG.warn("LinkDb createJob: " + e);
- }
- }
- job.setReducerClass(LinkDbMerger.class);
- // 配置MP输出路径
- FileOutputFormat.setOutputPath(job, newLinkDb);
- // 配置输出格式
- job.setOutputFormat(MapFileOutputFormat.class);
- // 对map输出使用压缩,以减少Reducer的输入压力
- job.setBoolean("mapred.output.compress", true);
- // 配置<key,value>的输出类型
- job.setOutputKeyClass(Text.class);
- job.setOutputValueClass(Inlinks.class);
- return job;
- }
下面来看一下LinkDb中的map做了些什么,这个方法主要是从toUrl=>fromUrl建立一个对应关系,这个有点像倒排索引中的TermId=>DocId
而LinkDbMerger这个类实现了reducer接口,主要是收集指定个数的同一个toUrl的fromUrl,这个指定的个数可能通过设置db.max.inlinks来设定。
2.2 把新产生的反向链接库与老的库进行合并,主要代码如下:
- if (fs.exists(currentLinkDb)) { // 如果存在老的反向链接库,就进行合并
- if (LOG.isInfoEnabled()) {
- LOG.info("LinkDb: merging with existing linkdb: " + linkDb);
- }
- // try to merge
- //
- Path newLinkDb = FileOutputFormat.getOutputPath(job);
- job = LinkDbMerger.createMergeJob(getConf(), linkDb, normalize, filter);
- // 加入输入路径
- FileInputFormat.addInputPath(job, currentLinkDb);
- FileInputFormat.addInputPath(job, newLinkDb);
- try {
- JobClient.runJob(job);
- } catch (IOException e) {
- LockUtil.removeLockFile(fs, lock);
- fs.delete(newLinkDb, true);
- throw e;
- }
- fs.delete(newLinkDb, true);
- }
- LinkDb.install(job, linkDb); // 安装新生成的反向链接库
我们再看一下createMergeJob做了些什么:
- public static JobConf createMergeJob(Configuration config, Path linkDb, boolean normalize, boolean filter) {
- // 生成一个临时目录
- Path newLinkDb =
- new Path("linkdb-merge-" +
- Integer.toString(new Random().nextInt(Integer.MAX_VALUE)));
- JobConf job = new NutchJob(config);
- job.setJobName("linkdb merge " + linkDb);
- // 配置个输出格式
- job.setInputFormat(SequenceFileInputFormat.class);
- // 配置Map与Reducer方法,这里的Reducer方法与上面的一样,用于对相同key(toUrl)的values进行聚合
- // 然后输出指定个数的value,而这里的LinkDbFilter应该是对key与value所对应的url进行过滤与正规化
- job.setMapperClass(LinkDbFilter.class);
- job.setBoolean(LinkDbFilter.URL_NORMALIZING, normalize);
- job.setBoolean(LinkDbFilter.URL_FILTERING, filter);
- job.setReducerClass(LinkDbMerger.class);
- // 配置输出路径
- FileOutputFormat.setOutputPath(job, newLinkDb);
- job.setOutputFormat(MapFileOutputFormat.class);
- job.setBoolean("mapred.output.compress", true);
- job.setOutputKeyClass(Text.class);
- job.setOutputValueClass(Inlinks.class);
- return job;
- }
3. bin/nutch readlinkdb 分析
主要是用于下载linkdb的内容到指定的目录,帮助如下:
- Usage: LinkDbReader <linkdb> {-dump <out_dir> | -url <url>)
- -dump <out_dir> dump whole link db to a text file in <out_dir>
- -url <url> print information about <url> to System.out
下面是本机运行的结果:
- lemo@debian:~/Workspace/java/Apache/Nutch/nutch-1.3$ bin/nutch readlinkdb db/linkdb/ -dump output2
- LinkDb dump: starting at 2011-08-29 09:54:08
- LinkDb dump: db: db/linkdb/
- LinkDb dump: finished at 2011-08-29 09:54:09, elapsed: 00:00:01
下面是输出output2目录中文件的部分内容,可以看到,这里一个<key,value>对,key是toUrl,value是fromUrl
- lemo@debian:~/Workspace/java/Apache/Nutch/nutch-1.3$ head output2/part-00000
- http://baike.baidu.com/ Inlinks:
- fromUrl: http://www.baidu.com/ anchor: 百科
- http://hi.baidu.com/ Inlinks:
- fromUrl: http://www.baidu.com/ anchor: 空间
- http://hi.baidu.com/baidu/ Inlinks:
- fromUrl: http://www.baidu.com/ anchor:
- http://home.baidu.com/ Inlinks:
这个readlinkdb也是用了一个MP任务,输入格式为SequenceFileInputFormat,输出格式为TextOutput,Map-Reducer都是用的默认的。
4. bin/nutch mergelinkdb 分析
主要是用来合并个不同的linkdb数据库的
- Usage: LinkDbMerger <output_linkdb> <linkdb1> [<linkdb2> <linkdb3> ...] [-normalize] [-filter]
- output_linkdb output LinkDb
- linkdb1 ... input LinkDb-s (single input LinkDb is ok)
- -normalize use URLNormalizer on both fromUrls and toUrls in linkdb(s) (usually not needed)
- -filter use URLFilters on both fromUrls and toUrls in linkdb(s)
其实这里的合并就是调用上面分析的LinkDbMerger中的createMergeJob方法
5. 总结
这里主要是对于parse_data目录中分析出来的外链接进行反向链接的计算,在下面计算链接分数的时候会用到这些反向链接。