关闭

Nutch 源码分析 (1)

标签: nutch源码
638人阅读 评论(0) 收藏 举报
分类:

org.apache.nutch.crawl.Crawl类的主函数如下所示:

   // 应该知道,Nutch查找文件系统是基于Linux系统的机制的,所以提供启动的命令与Linux的Shell命令很相似。

   public static void main(String args[]) throws Exception {
    if (args.length < 1) {
// 检查命令行参数是否合法,如果小于1个参数,则给出提示。
      System.out.println
        ("Usage: Crawl <urlDir> [-dir d] [-threads n] [-depth i] [-topN N]");
      return;
    }

    Configuration conf = NutchConfiguration.create(); // 使用静态类NutchConfiguration创建一个org.apache.hadoop.conf.Configuration实例,可以在Hadoop的源代码中查看到该类的定义(读取hadoop-site.xml配置文件)
    conf.addDefaultResource("crawl-tool.xml");
// 读取并设置抓取工具的配置文件,可以在nutch-0.9\conf目录下找到crawl-tool.xml文件
    JobConf job = new NutchJob(conf);
// 抓取任务配置实例的创建

    Path rootUrlDir = null; // 初始URLs文件所在的目录,使用Hadoop的org.apache.hadoop.fs.Path类创建目录
    Path dir = new Path("crawl-" getDate()); // 设置默认抓取到网页的存放目录。如果命令行中没有指定-dir 的值就会使用默认的值:crawl-时间。
    int threads = job.getInt("fetcher.threads.fetch", 10);
// 设置默认抓取工作启动线程数目,默认值为10。
    int depth = 5;
// 默认抓取工作遍历深度,默认值为5。
    int topN = Integer.MAX_VALUE;
// 抓取任务抓取网页的数量,默认为最大值。

    for (int i = 0; i < args.length; i ) { // 根据读取的命令行,设置抓取工作配置信息。
      if ("-dir".equals(args[i])) {
        dir = new Path(args[i 1]);
        i ;
      } else if ("-threads".equals(args[i])) {
        threads = Integer.parseInt(args[i 1]);
        i ;
      } else if ("-depth".equals(args[i])) {
        depth = Integer.parseInt(args[i 1]);
        i ;
      } else if ("-topN".equals(args[i])) {
        topN = Integer.parseInt(args[i 1]);
        i ;
      } else if (args[i] != null) {
        rootUrlDir = new Path(args[i]);
      }
    }

    FileSystem fs = FileSystem.get(job); // 根据抓取工作配置JobConf创建一个用来存放抓取到的网页的目录。
    if (fs.exists(dir)) {
      throw new RuntimeException(dir " already exists.");
// 如果该目录已经存在,则发生运行时异常。
    }

    if (LOG.isInfoEnabled()) { // 登录日志信息
      LOG.info("crawl started in: " dir);
      LOG.info("rootUrlDir = " rootUrlDir);
      LOG.info("threads = " threads);
      LOG.info("depth = " depth);
      if (topN != Integer.MAX_VALUE)
        LOG.info("topN = " topN);
    }

    // 在目录dir下面创建下面5个目录,用来存放,抓取工作过程中不同操作生成的文件或者目录。
    
    Path crawlDb = new Path(dir "/crawldb");
    Path linkDb = new Path(dir "/linkdb");
    Path segments = new Path(dir "/segments");
    Path indexes = new Path(dir "/indexes");
    Path index = new Path(dir "/index");

    Path tmpDir = job.getLocalPath("crawl" Path.SEPARATOR getDate());
    Injector injector = new Injector(conf);
// 根据Configuration conf创建一个Injector实例
    Generator generator = new Generator(conf); // 根据Configuration conf创建一个Generator实例
    Fetcher fetcher = new Fetcher(conf);
// 根据Configuration conf创建一个Fetcher实例
    ParseSegment parseSegment = new ParseSegment(conf);
// 根据Configuration conf创建一个ParseSegment实例
    CrawlDb crawlDbTool = new CrawlDb(conf);
// 根据Configuration conf创建一个CrawlDb实例
    LinkDb linkDbTool = new LinkDb(conf);
// 根据Configuration conf创建一个LinkDb实
    Indexer indexer = new Indexer(conf);
// 根据Configuration conf创建一个Indexer实例
    DeleteDuplicates dedup = new DeleteDuplicates(conf);
// 根据Configuration conf创建一个DeleteDuplicates实
    IndexMerger merger = new IndexMerger(conf);
// 根据Configuration conf创建一个IndexMerger实例
      
   
// 初始化crawlDb
    injector.inject(crawlDb, rootUrlDir);
// 从rootUrlDir目录中读取初始化URLs,将URLs注入到CrawlDb实体中去
    int i;
    for (i = 0; i < depth; i ) {            
// 在segment文件中生成抓取工作列表
      Path segment = generator.generate(crawlDb, segments, -1, topN, System
          .currentTimeMillis(), false, false);
      if (segment == null) {
        LOG.info("Stopping at depth=" i " - no more URLs to fetch.");
        break;
      }
      fetcher.fetch(segment, threads);
// 根据配置的线程数开始抓取网页文件
      if (!Fetcher.isParsing(job)) {
        parseSegment.parse(segment);   
// 解析网页文件
      }
      crawlDbTool.update(crawlDb, new Path[]{segment}, true, true);
// 更新CrawlDb
    }
    if (i > 0) {
      linkDbTool.invert(linkDb, segments, true, true, false); // invert links

    indexer.index(indexes, crawlDb, linkDb, fs.listPaths(segments)); // 索引过程
      dedup.dedup(new Path[] { indexes });
// 复制索引文件
      merger.merge(fs.listPaths(indexes), index, tmpDir); // 将索引目录index中的索引文件合并后写入到indexes目录中
    } else {
      LOG.warn("No URLs to fetch - check your seed list URL filters.");
    }
    if (LOG.isInfoEnabled()) { LOG.info("crawl finished: " dir); }
}

通过上面的源代码的整体分析,总结一下具体都在这里做了哪些工作:

1、读取命令行参数,合法以后才继续初始化配置实例;

2、通过读取hadoop-site.xml配置文件,初始化一个Configuration实例,并根据crawl-tool.xml文件内容设置抓取工作配置;

3、设置一些默认抓取工作参数,如果命令行中没有指定就会按照默认的参数值进行抓取工作的执行,比如,抓取工作抓取到的网页文件存放目录rootUrlDir、启动的抓取工作进程数threads、抓取深度depth、抓取网页数量topN;

4、创建抓取工作抓取到的网页文件的存放目录,及其子目录(crawldb、linkdb、segments、indexes、index),这些子目录有的是用来存放原生网页,有的是预处理网页文件,有的是网页解析出的文本内容及其其它相关数据等等;

5、在抓取工作及其索引过程中,要进行很多操作来对网页文件或数据进行处理,这通过初始化一些实现了这些操作的类的实例来完成的,例如:Injector、Generator、Fetcher、ParseSegment、CrawlDb、LinkDb、Indexer、DeleteDuplicates、IndexMerger。这些类中,有的是作为实体类,像CrawlDb、LinkDb,它们需要在抓取工作执行过程中及时更新,保持数据状态的处于良好正确状态。

6、最后,就开始执行相关操作了,包括初始化CrawlDb、生成抓取工作列表、抓取网页文件、更新CrawlDb、倒排Links、建立索引、复制索引文件、合并索引文件。


0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:297467次
    • 积分:3654
    • 等级:
    • 排名:第10101名
    • 原创:94篇
    • 转载:137篇
    • 译文:2篇
    • 评论:53条
    最新评论