Nutch 1.3 学习笔记 8 LinkDb

Nutch 1.3 学习笔记 8 LinkDb
----------------------------
这里主要是分析一下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目录中分析出来的外链接进行反向链接的计算,在下面计算链接分数的时候会用到这些反向链接。

你可能感兴趣的:(Debian,filter,Random,Path,output,代码分析)