【Nutch源代码分析之二】索引的基本流程

一、各个主要类之间的关系

SolrIndexerJob extends IndexerJob

1、IndexerJob:主要完成

2、SolrIndexerJob:主要完成

3、IndexUtil:主要只有一个方法public NutchDocument index(String key, WebPage page),用于根据网页信息,返回一个solr的Document对象。

二、程序调用流程

查看Nutch中的执行脚本--nutch,得到以下信息:

elif [ "$COMMAND" = "solrindex" ] ; then

CLASS=org.apache.nutch.indexer.solr.SolrIndexerJob

因此程序入口位于SolrIndexerJob类中。

(一)org.apache.nutch.indexer.SolrIndexerJob

1、程序入口

  public static void main(String[] args) throws Exception {
    final int res = ToolRunner.run(NutchConfiguration.create(),
        new SolrIndexerJob(), args);
    System.exit(res);
  }

使用了ToolRunner.run()来执行程序,可参考:使用ToolRunner运行Hadoop程序基本原理分析

其中第一个参数主要是加载了nutch相关的参数,主要包括hadoop的core-default.xml、core-site.xml以及nutch的nutch-default.xml、nutch-site.xml。

第二个参数指明了运行SolrIndexerJob的run(String[])方法.

2、执行SolrIndexerJob类的run(String[])方法

  public int run(String[] args) throws Exception {
    if (args.length < 2) {
      System.err.println("Usage: SolrIndexerJob <solr url> (<batchId> | -all | -reindex) [-crawlId <id>]");
      return -1;
    }

    if (args.length == 4 && "-crawlId".equals(args[2])) {
      getConf().set(Nutch.CRAWL_ID_KEY, args[3]);
    }
    try {
      indexSolr(args[0], args[1]);
      return 0;
    } catch (final Exception e) {
      LOG.error("SolrIndexerJob: " + StringUtils.stringifyException(e));
      return -1;
    }
  }

先判断参数的合理性,然后执行执行indexSolr(String,String)方法。

3、执行indexSolr(String,String)方法

public void indexSolr(String solrUrl, String batchId) throws Exception {
    LOG.info("SolrIndexerJob: starting");

    run(ToolUtil.toArgMap(
        Nutch.ARG_SOLR, solrUrl,
        Nutch.ARG_BATCH, batchId));
    // do the commits once and for all the reducers in one go
    getConf().set(SolrConstants.SERVER_URL,solrUrl);
    SolrServer solr = SolrUtils.getCommonsHttpSolrServer(getConf());
    if (getConf().getBoolean(SolrConstants.COMMIT_INDEX, true)) {
      solr.commit();
    }
    LOG.info("SolrIndexerJob: done.");
  }

4、执行run(Map<...>)方法

@Override
  public Map<String,Object> run(Map<String,Object> args) throws Exception {
    String solrUrl = (String)args.get(Nutch.ARG_SOLR);
    String batchId = (String)args.get(Nutch.ARG_BATCH);
    NutchIndexWriterFactory.addClassToConf(getConf(), SolrWriter.class);
    getConf().set(SolrConstants.SERVER_URL, solrUrl);

    currentJob = createIndexJob(getConf(), "solr-index", batchId);

    currentJob.waitForCompletion(true);
    ToolUtil.recordJobStatus(null, currentJob, results);
    return results;
  }

(二)org.apache.nutch.indexer.IndexerJob

1、执行createIndexJob()方法。

  protected Job createIndexJob(Configuration conf, String jobName, String batchId)
  throws IOException, ClassNotFoundException {
    conf.set(GeneratorJob.BATCH_ID, batchId);
    Job job = new NutchJob(conf, jobName);
    // TODO: Figure out why this needs to be here
    job.getConfiguration().setClass("mapred.output.key.comparator.class",
        StringComparator.class, RawComparator.class);

    Collection<WebPage.Field> fields = getFields(job);
    StorageUtils.initMapperJob(job, fields, String.class, NutchDocument.class,
        IndexerMapper.class);
    job.setNumReduceTasks(0);
    job.setOutputFormatClass(IndexerOutputFormat.class);
    return job;
  }
}

2、执行map相关的方法,包括setup(),map(),cleanup()

  public static class IndexerMapper
      extends GoraMapper<String, WebPage, String, NutchDocument> {
    public IndexUtil indexUtil;
    public DataStore<String, WebPage> store;

    protected Utf8 batchId;

    @Override
    public void setup(Context context) throws IOException {
      Configuration conf = context.getConfiguration();
      batchId = new Utf8(conf.get(GeneratorJob.BATCH_ID, Nutch.ALL_BATCH_ID_STR));
      indexUtil = new IndexUtil(conf);
      try {
        store = StorageUtils.createWebStore(conf, String.class, WebPage.class);
      } catch (ClassNotFoundException e) {
        throw new IOException(e);
      }
    }

    protected void cleanup(Context context) throws IOException ,InterruptedException {
      store.close();
    };

    @Override
    public void map(String key, WebPage page, Context context)
    throws IOException, InterruptedException {
      ParseStatus pstatus = page.getParseStatus();
      if (pstatus == null || !ParseStatusUtils.isSuccess(pstatus)
          || pstatus.getMinorCode() == ParseStatusCodes.SUCCESS_REDIRECT) {
        return; // filter urls not parsed
      }

      Utf8 mark = Mark.UPDATEDB_MARK.checkMark(page);
      if (!batchId.equals(REINDEX)) {
        if (!NutchJob.shouldProcess(mark, batchId)) {
          if (LOG.isDebugEnabled()) {
            LOG.debug("Skipping " + TableUtil.unreverseUrl(key) + "; different batch id (" + mark + ")");
          }
          return;
        }
      }

      NutchDocument doc = indexUtil.index(key, page);
      if (doc == null) {
        return;
      }
      if (mark != null) {
        Mark.INDEX_MARK.putMark(page, Mark.UPDATEDB_MARK.checkMark(page));
        store.put(key, page);
      }
      context.write(key, doc);
    }
  }

3、调用context.write()

由于  job.setOutputFormatClass(IndexerOutputFormat.class);

所以写入index??

(三)public class IndexUtil

1、调用index()方法

  public NutchDocument index(String key, WebPage page) {
    NutchDocument doc = new NutchDocument();
    doc.add("id", key);
    doc.add("digest", StringUtil.toHexString(page.getSignature()));
    if (page.getBatchId() != null) {
      doc.add("batchId", page.getBatchId().toString());
    }

    String url = TableUtil.unreverseUrl(key);

    if (LOG.isDebugEnabled()) {
      LOG.debug("Indexing URL: " + url);
    }

    try {
      doc = filters.filter(doc, url, page);
    } catch (IndexingException e) {
      LOG.warn("Error indexing "+key+": "+e);
      return null;
    }

    // skip documents discarded by indexing filters
    if (doc == null) return null;

    float boost = 1.0f;
    // run scoring filters
    try {
      boost = scoringFilters.indexerScore(url, doc, page, boost);
    } catch (final ScoringFilterException e) {
      LOG.warn("Error calculating score " + key + ": " + e);
      return null;
    }

    doc.setScore(boost);
    // store boost for use by explain and dedup
    doc.add("boost", Float.toString(boost));

    return doc;
  }

三、plugin中的字段索引

1、关于basic字段的索引在public class BasicIndexingFilter implements IndexingFilter 中

时间: 2024-11-13 04:11:01

【Nutch源代码分析之二】索引的基本流程的相关文章

Zepto源代码分析之二~三个API

因为时间关系:本次仅仅对这三个API($.camelCase.$.contains.$.each)方法进行分析 第一个方法变量转驼峰:$.camelCase('hello-world-welcome'); 源代码: var camelize; /** * 字符串替换 * 使用replace第二个參数带回调 */ camelize = function(str) { return str.replace(/-+(.)?/g, function(match, chr) { return chr ?

Android7.0 Phone应用源码分析(二) phone来电流程分析

接上篇博文:Android7.0 Phone应用源码分析(一) phone拨号流程分析 今天我们再来分析下Android7.0 的phone的来电流程 1.1TelephonyFramework 当有来电通知时,首先接收到消息的是Modem层,然后Medoem再上传给RIL层,RIL进程通过sokcet将消息发送给RILJ(framework层的RIL),同样进入RILJ的processResponse方法,根据上一章节去电流程的分析得知,来电属于UnSolicited消息,事件ID是 RIL_

Hadoop 源代码分析(二四)FSNamesystem

下面轮到FSNamesystem 出场了.FSNamesystem.java 一共有4573 行,而整个namenode 目录下所有的Java 程序总共也只有16876行,把FSNamesystem 搞定了,NameNode 也就基本搞定.FSNamesystem 是NameNode 实际记录信息的地方,保存在FSNamesystem 中的数据有:文件名数据块列表(存放在FSImage 和日志中)合法的数据块列表(上面关系的逆关系)数据块DataNode(只保存在内存中,根据DataNode 发

【雷电】源代码分析(二)-- 进入游戏攻击

效果图: 程序分析: 初始化GameLayer场景触摸.背景.音乐.UI及定时间器 bool GameLayer::init() { if (!CCLayer::init()) { return false; } // 开启触摸 this->setTouchEnabled(true); // 创建数组,须要retain一下 play_bullet = CCArray::create(); play_bullet->retain(); enemy_bullet = CCArray::create

Kubernetes1.1源代码分析(二)

3.controller-manager模块 在controller manager模块中有几个重要的结构体,其中包括EndpointController.ReplicationManager.GCController.NodeController.ServiceController.RouteController.ResourceQuotaController,下面会进行介绍.在controller manager模块还有几个处于试验阶段的功能和结构体,这里不会进行介绍. 3.1.Endpoi

Redis源代码分析(二十八)--- object创建和释放redisObject物

今天的学习更有效率.该Rio分析过,学习之间的另一种方式RedisObject文件,只想说RedisObject有些生成和转换.都是很类似的.列出里面长长的API列表: /* ------------ API --------------------- */ robj *createObject(int type, void *ptr) /* 最初的创建robj对象方法,后面的创建方法与此相似 */ robj *createStringObject(char *ptr, size_t len)

opencv源代码分析之二:cvhaartraining.cpp

我使用的是opencv2.4.9.安装后.我的cvboost..cpp文件的路径是........\opencv\sources\apps\haartraining\cvhaartraining.cpp,研究源代码那么多天,有非常多收获.opencv库真是非常强大.当中在这篇博文中我有部分凝视,其它的有关知识请參考我博客http://blog.csdn.net/ding977921830?viewmode=contents.详细内容例如以下: /*M///////////////////////

Redis源代码分析(二十四)--- tool工具类(2)

在上篇文章中初步的分析了一下,Redis工具类文件里的一些使用方法,包含2个随机算法和循环冗余校验算法,今天,继续学习Redis中的其它的一些辅助工具类的使用方法.包含里面的大小端转换算法,sha算法在Redis中的实现和通用工具类算法util.c. 先来看看大小端转换算法,大小端学习过操作系统的人一定知道是什么意思,在不同的操作系统中,高位数字的存储方式存在,高位在前,低位在后,或是高位在后,低位在前,所以这里面就涉及到转换,依据不同的操作系统,有不同的转换方式,所以Redis在这方面就开放了

【草稿】zico源代码分析(二) 数据读取和解析部分

查找数据的过程是:TraceDataService执行searchTraces函数(在searchTraces函数中会将query的条件作为参数传入)并返回一个TraceInfoSearchResult对象,TraceInfoSearchResult中包含一个TraceInfo的List,而一个TraceInfo对象就是最后显示在网页上的一条信息. HostStore中的toTraceInfo方法会将TraceInfoRecord和TraceInfoRecord的信息综合起来形成TraceInf