`
yanglingstu
  • 浏览: 20995 次
  • 性别: Icon_minigender_1
  • 来自: 苏州
社区版块
存档分类
最新评论

Nutch中Injector的过程

阅读更多
Injector过程主要分成两个过程,而且这两个过程是两个独立的Map/Reduce任务,前一个任务只有Map,后一个任务是一个完整的Map/Reduce过程。

在详细介绍之前,先看inject()的主调用代码:
代码1:
public void inject(Path crawlDb, Path urlDir) throws IOException {
    if (LOG.isInfoEnabled()) {
      LOG.info("Injector: starting");
      LOG.info("Injector: crawlDb: " + crawlDb);
      LOG.info("Injector: urlDir: " + urlDir);
    }
    Path tempDir =
      new Path(getConf().get("mapred.temp.dir", ".") +
               "/inject-temp-"+
               Integer.toString(new Random().nextInt(Integer.MAX_VALUE)));

    // map text input file to a <url,CrawlDatum> file
    if (LOG.isInfoEnabled()) {
      LOG.info("Injector: Converting injected urls to crawl db entries.");
}

/* 第一个任务 */
    JobConf sortJob = new NutchJob(getConf());
    sortJob.setJobName("inject " + urlDir);
    FileInputFormat.addInputPath(sortJob, urlDir); //设置第一个任务的输入路径
    sortJob.setMapperClass(InjectMapper.class); //设置第一个任务的Map类

    FileOutputFormat.setOutputPath(sortJob, tempDir); //设置第一个任务的输出路径,也是一个临时目录
    sortJob.setOutputFormat(SequenceFileOutputFormat.class);
    sortJob.setOutputKeyClass(Text.class);
    sortJob.setOutputValueClass(CrawlDatum.class);
    sortJob.setLong("injector.current.time", System.currentTimeMillis());
    JobClient.runJob(sortJob); //执行第一个任务
   
    // merge with existing crawl db
    if (LOG.isInfoEnabled()) {
      LOG.info("Injector: Merging injected urls into crawl db.");
}
/* 第二个任务 */
    JobConf mergeJob = CrawlDb.createJob(getConf(), crawlDb); //初始化第二个任务,包括Map类和Reduce类,以及输入,输出路径,注意输出路径也是在这个函数里设置的
    FileInputFormat.addInputPath(mergeJob, tempDir); //为第二个任务添加一个输入路径
mergeJob.setReducerClass(InjectReducer.class); //重置Reducer类,即替换之前在mergeJob初始化时定义的Reducer类
JobClient.runJob(mergeJob);  //执行第二个任务
    CrawlDb.install(mergeJob, crawlDb);

    // clean up
    FileSystem fs = FileSystem.get(getConf());
    fs.delete(tempDir, true);
    if (LOG.isInfoEnabled()) { LOG.info("Injector: done"); }
  }
这个函数初一看,诈似一个Map/Reduce过程,实际上是两个Map/Reduce过程。

第一个任务(其实就一个Map过程,主要是为了从urlDir中读种子url,并对这些url进行初始化处理,并把处理结果保存到临时文件中):
主要过程介绍:在Map之前,先要将把urlDir(保存种子url的文件路径)中的url(一行一个url)一个一个地读出,把然后把url保存为value(value为Text类型对象),key为WritableComparable类型,值为0。然后将<key, value>作为Map过程的输入。
Map过程(Injector.InjectMapper类中定义):这个过程主要和urlDir有关,该过程主要是从的任务是判断输入的<key, value>中,value的值是否是应该爬取的页面的url,如果是,则将url重新加载到value中,然后整合配置信息中的fetch信息到一个新建的CrawlDatum对象datum中,然后将<value, datum>作为键值通过output.collect(value, datum)保存第一个任务的结果临时保存文件tempDir中。
其代码为:
代码2:
public void map(WritableComparable key, Text value,
                    OutputCollector<Text, CrawlDatum> output, Reporter reporter)
      throws IOException {
      String url = value.toString();              // value is line of text
      try {
        url = urlNormalizers.normalize(url, URLNormalizers.SCOPE_INJECT); //url规整化处理
        url = filters.filter(url);             // 对url进行过滤处理
      } catch (Exception e) {
        if (LOG.isWarnEnabled()) { LOG.warn("Skipping " +url+":"+e); }
        url = null;
      }
      if (url != null) {                          // if it passes
        value.set(url);                           //对value重置处理过的url
        CrawlDatum datum = new CrawlDatum(CrawlDatum.STATUS_INJECTED, interval);//添加fetch间隔时间到datum中
        datum.setFetchTime(curTime); //添加当前时间到datum中
        datum.setScore(scoreInjected); //添加分值到datum中
        try {
          scfilters.injectedScore(value, datum); //根据分值进行一些操作
        } catch (ScoringFilterException e) {
          if (LOG.isWarnEnabled()) {
            LOG.warn("Cannot filter injected score for url " + url +
                     ", using default (" + e.getMessage() + ")");
          }
          datum.setScore(scoreInjected); //出现异常时重置分值到datum中
        }
        output.collect(value, datum); //写处理结果到tempDir指定路径的临时文件中
      }
    }
  }
主要的处理过程:
1、对url进行规整化处理;
2、对url进行过滤操作(即判断该url是否是应该爬取的页面的url);
3、分别将爬取间隔时间、当前爬取时间、分值等代入一个CrawlDatum对象中,构建一个datum对象中;4、写这个<value, datum>键值对到tempDir指定路径的文件中。

第二个任务(主要是对一个url的多个crawlDB对象进行过滤操作):
主要过程介绍:这个过程主要和crawlDB有关,其任务主要是从第一个任务产生的tempDir文件和crawlDB中读<url, datum>键值对,并将这些键值对进行url规整化和过滤处理,并按照同一个url为一组的原则组成一个<value,datums>(datums不是datum,datums是CrawlDatum的一个迭代器,其中包含了所有属于url 的datum),然后将从这些对应同一个url的众多CrawlDatum对象中选择一个CrawlDatum对象作为合适的<value, datum>作为输出,输出到crawlDB中。
先看(代码1)中的代码:
JobConf mergeJob = CrawlDb.createJob(getConf(), crawlDb);
该函数初始化了一个完整的Map/Reduce任务mergeJob,包括Map类和reduce类的设置,同时设置输入路径(输入路径为CrawlDB的路径,后面还要添加第一个任务处理后保存的临时文件路径tempDir)和输出路径。只不过这时的mergeJob不符合第二个任务的需要,后面需要做一些修改:
代码3:
public static JobConf createJob(Configuration config, Path crawlDb)
    throws IOException {
    Path newCrawlDb =
      new Path(crawlDb,
               Integer.toString(new Random().nextInt(Integer.MAX_VALUE)));

    JobConf job = new NutchJob(config); //设置配置信息
    job.setJobName("crawldb " + crawlDb);

    Path current = new Path(crawlDb, CURRENT_NAME);  //根据CrawlDB的路径crawlDb处理输入路径
    if (FileSystem.get(job).exists(current)) {
      FileInputFormat.addInputPath(job, current); //添加输入路径
    }
    job.setInputFormat(SequenceFileInputFormat.class);

    job.setMapperClass(CrawlDbFilter.class); //设置Map类
    job.setReducerClass(CrawlDbReducer.class); //设置Reduce类,不过实际不需要这个类,后面会重置它
    FileOutputFormat.setOutputPath(job, newCrawlDb); //设置输出路径
    job.setOutputFormat(MapFileOutputFormat.class);
    job.setOutputKeyClass(Text.class);
    job.setOutputValueClass(CrawlDatum.class);

    return job;
  }
前面提到输入路径需要添加第一个任务处理后保存的临时文件路径tempDir,因为事先不知道种子url是否在CrawlDB中已经存在了,而且如果种子url太多的话,就不能保证它们之中没有重复的url,所以需要结合第一个任务导入的种子url和CrawlDB中包含的url,来对url进行去重。(这里就有一个感觉nutch设计不好的地方,因为每次注入种子url时,其实只要根据种子url和CrawlDB中可能存在的相同的url进行去重就可以了,根本就不需要把整个CrawlDB都去重一次)。所以需要添加临时文件路径tempDir,来一起进行去重。添加路径代码见(代码1)的:
FileInputFormat.addInputPath(mergeJob, tempDir);
又因为CrawlDb.createJob(getConf(), crawlDb);中设置的Reduce类不是inject需要的类,所以需要对其进行重置,重置的代码见(代码1)的:
mergeJob.setReducerClass(InjectReducer.class); //重置ReducerClass
现在再分别介绍Map过程和Reduce过程:
Map过程(CrawlDbFilter类中定义):
先看其map函数的代码,
代码4:
public void map(Text key, CrawlDatum value,
      OutputCollector<Text, CrawlDatum> output,
      Reporter reporter) throws IOException {
  //该函数的作用实际上就是写crawlDB
    String url = key.toString();
    if (urlNormalizers) { //key(url)规整化
      try {
        url = normalizers.normalize(url, scope); // normalize the url  // normalize the url, 为什么这里还要进行url规整化操作
      } catch (Exception e) {
        LOG.warn("Skipping " + url + ":" + e);
        url = null;
      }
    }
    if (url != null && urlFiltering) {//key(url)过滤
      try {
        url = filters.filter(url); // filter the url
      } catch (Exception e) {
        LOG.warn("Skipping " + url + ":" + e);
        url = null;
      }
    }
    if (url != null) { // if it passes
      newKey.set(url); // collect it
      output.collect(newKey, value); //写文件
    }
  }
通过这个函数的代码发现,其实第二个任务的Map过程其实就是一个对url进行规整化和过滤的过程,只不过它不仅对CrawlDB中的url进行规整化和过滤操作,而且它还对tempDir指定路径的文件中的url进行规整化和过滤操作。然后把得到的<url, datum>(这个url是Text类型,Map过程没有对datum做任何处理)通过output.collect(newKey, value);临时保存着,等待紧接着的Reduce过程的处理。
Reduce过程(Injector.InjectReducer类中定义):
这个过程可以先看代码,
代码5:
private CrawlDatum old = new CrawlDatum(); //表示是CrawlDB中的url
private CrawlDatum injected = new CrawlDatum(); //表示是注入的种子url
public void reduce(Text key, Iterator<CrawlDatum> values,
                       OutputCollector<Text, CrawlDatum> output, Reporter reporter)
      throws IOException {
      boolean oldSet = false;
      while (values.hasNext()) { //通过迭代器循环获得所有该url下对应的CrawlDatum对象val
        CrawlDatum val = values.next();
        if (val.getStatus() == CrawlDatum.STATUS_INJECTED) { //如果是先前第一个任务中注入到临时文件tempDir中的种子url的话
          injected.set(val); //保存到injected中
          injected.setStatus(CrawlDatum.STATUS_DB_UNFETCHED); //初始化未爬取的状态
        } else {  //如果是CrawlDB中的url的话
          old.set(val);  //保存到old中
          oldSet = true; // oldSet为true表示crawlDB存在于该url对应的CrawlDatum信息
        }
      }
      CrawlDatum res = null;

      //通过下面这个if-else语句,可以看出返回的结果是优先保存CrawlDB中存在的old,也就是说如果CrawlDB中存在当前url(key)对应的CrawlDatum对象,在爬取时,则优先根据当前url在CrawlDB中存在的CrawlDatum对象信息来对该url进行相关处理(是爬取还是不爬取),即使种子url中也包括当前url。
      if (oldSet) res = old; // don't overwrite existing value
      else res = injected;

      output.collect(key, res);
}
分享到:
评论
2 楼 cuikai314 2012-07-18  
在JobConf mergeJob = CrawlDb.createJob(getConf(), crawlDb);中,
对reducerClass进行了设置,然后你说后面又进行了重置,那为什么要两次呢,直接一次不就好了吗?不知道你能不能很好的回答这个问题
1 楼 leeking888 2010-10-22  
请问一下我如果想获得一个网站的指定的前缀下所有的网页 怎么样使用呢??


我想要爬 163网站中的
http://www.163.com/new/2010/ 这个路径下所有的网页和
http://www.163.com/bbs/2010/  
怎么样配置呢??

注意http://www.163.com/new/2010/不能正确访问 http://www.163.com/new/2010/20101010.html 才是一个正确的网页路径

相关推荐

    nutch中文分词

    nutch应用,nutch中文分词,nutch中文乱码

    Nutch中文分词插件的编写与配置

    Nutch中文分词插件的编写与配置,由于Internet的迅猛发展,使得用户查找信息犹如大海捞针,而搜索引擎则能帮用户很好的解决这个问题。 Nutch是用java语言开发的,基于Lucene的完整的网络搜索引擎,并采用插件机制进行...

    nutch平台的搭建过程

    nutch平台的详细搭建过程 配置环境 抓取 建立索引 查看结果

    Nutch中文教程nutcher.zip

    nutcher 是 Apache Nutch 的中文教程,在github上托管。nutch社区目前缺少教程和文档,而且教程对应版本号较为落后。nutcher致力于为nutch提供一个较新的中文教程和文档,供开发者学习。 github地址: ...

    基于Nutch中文分词的研究与实现

    作为舆情监测系统的一部分,本文的目标是基于Nutch,同时,结合目前最常用中文分词技术,根据不同的中文分词方法,实验并得出不同分词方法在性能以及使用环境上的优缺点,以此为舆情监测系统选择合适的中文分词方法...

    nutch 初学文档教材

    5.2.1 索引主要过程....27 5.2.2 工作流程分析....28 5.2.3 倒排索引(inverted index)....29 5.2.4其它...29 5.3 搜索...29 5.4 分析...30 5.5 nutch的其他一些特性..31 6. nutch分析方法和工具........33 6.1 ...

    nutch 爬虫数据nutch 爬虫数据nutch 爬虫数据nutch 爬虫数据

    nutch 爬虫数据nutch 爬虫数据nutch 爬虫数据nutch 爬虫数据nutch 爬虫数据nutch 爬虫数据nutch 爬虫数据nutch 爬虫数据nutch 爬虫数据

    Apache Nutch v1.15

    在Nutch的进化过程中,产生了Hadoop、Tika、Gora和Crawler Commons四个Java开源项目。如今这四个项目都发展迅速,极其火爆,尤其是Hadoop,其已成为大规模数据处理的事实上的标准。Tika使用多种现有的开源内容解析...

    基于Java的搜索引擎Nutch中文搜索技术研究

    摘要:Nutch是一个优秀的基于Java的开放源码搜索引擎,为了使它能够支持中文搜索,本文在分析了Nutch结构的基础上,采用词表分词技术和前向匹配分词算法对中文信息进行分词,以JavaCC脚本实现上下文相关文法中文分析...

    nutch2.2.1安装步骤.docx

    nutch2.2.1安装步骤,需要自己下载以下软件: apache-ant-1.10.5-bin.tar.gz apache-nutch-2.2.1-src.tar.gz apache-tomcat-8.5.39.tar.gz jdk-8u201-linux-x64.tar.gz solr-4.10.3.zip

    Nutch执行单步执行、中间结果文件分析和插件开发基础

    资源中urls.txt是我nutch单步执行过程的种子文件,里面的ppt主要讲解nutch单步执行流程,并获取每次单步执行的结果文件,对文件进行分析,同时ppt还讲解了nutch的插件的基础知识,不是很详细,但是可以作为参考。...

    Nutch公开课从搜索引擎到网络爬虫

    在Nutch的进化过程中,产生了Hadoop、Tika和Gora三个Java开源项目。如今这三个项目都发展迅速,极其火爆,尤其是Hadoop,其已成为大规模数据处理的事实上的标准。Tika使用多种现有的开源内容解析项目来实现从多种...

    Nutch相关框架视频教程

    资源名称:Nutch相关框架视频教程资源目录:【】Nutch相关框架视频教程1_杨尚川【】Nutch相关框架视频教程2_杨尚川【】Nutch相关框架视频教程3_杨尚川【】Nutch相关框架视频教程4_杨尚川【】Nutch相关框架视频教程5_...

    nutch介绍信息

    一、org.apache.nutch.crawl.Injector: 1,注入url.txt 2,url标准化 3,拦截url,进行正则校验(regex-urlfilter.txt) 4,对符URL标准的url进行map对构造, CrawlDatum&gt;,在构造过程中给CrawlDatum初始化得分...

    基于Nutch的中文搜索引擎的构建

    对自己写搜索引擎的人来说很有帮助,大家一起学习,多多交流,为了赚点分,不好意思要了两分

    eclipse配置nutch,eclipse配置nutch

    eclipse配置nutch,eclipse配置nutch

    如何通过java程序获得Nutch中网页的详细信息

    如何通过java程序获得Nutch中网页的详细信息

    nutch的源码解读和nutch入门

    学习nutch 源码解读 轻松入门 搭建自己的nutch搜索引擎

    Eclipse中编译Nutch-1.0

    Eclipse 中编译 Nutch-1.0 运行源代码

    Linux下Nutch分布式配置和使用

    Linux下Nutch分布式配置 使用:分布式爬虫、索引、Nutch搜索本地数据、Nutch搜索HDFS数据。

Global site tag (gtag.js) - Google Analytics