天天看点

Nutch1.3集成Solr网页快照功能实现(一)

Nutch1.3版本以后使用了Solr作为索引功能的提供者,在索引效率、集群功能方面做了很大改进,但与Nutch1.2版本相比,Solr缺失了网页快照的功能,按官方手册中集成配置后,每次查询返回的结果中仅包含解析处理过的HTML正文部分,如下图所示:

<a href="http://blog.51cto.com/attachment/201111/132943217.png" target="_blank"></a>

对于需要原网页快照功能的使用者来说,带来了巨大的麻烦。因此,需要对Nutch1.3做一些改动,使其支持集成后的网页快照功能。

参考Nutch1.2原来的实现方式,其自带的索引功能其实是将整个网页进行了索引,而1.3版本在调用Solr服务之前,Nutch主动将无用的Html标签信息去掉了(其内部机制在此不做探讨),结果Solr中仅获取了网页之中的“正文”部分,也就是上面图片中看到的Content标签中的内容。我们所要做的工作,其核心就是将整个网页的缓存信息也交给Solr,并在查询Solr时作为结果内容返回。

在工程中找到“SolrIndexer”类,中的“indexSolr”方法,如下:

  <b>public</b> <b>void</b> indexSolr(String solrUrl, Path crawlDb, Path linkDb,

      List&lt;Path&gt; segments) <b>throws</b> IOException {

    SimpleDateFormat sdf = <b>new</b> SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    <b>long</b> start = System.currentTimeMillis();

    LOG.info("SolrIndexer: starting at " + sdf.format(start));

    <b>final</b> JobConf job = <b>new</b> NutchJob(getConf());

    job.setJobName("index-solr " + solrUrl);

   <b> IndexerMapReduce.initMRJob(crawlDb, linkDb, segments, job);</b>

    job.set(SolrConstants.SERVER_URL, solrUrl);

    NutchIndexWriterFactory.addClassToConf(job, SolrWriter.<b>class</b>);

    job.setReduceSpeculativeExecution(<b>false</b>);

    <b>final</b> Path tmp = <b>new</b> Path("tmp_" + System.currentTimeMillis() + "-" +

                         <b>new</b> Random().nextInt());

    FileOutputFormat.setOutputPath(job, tmp);

    <b>try</b> {

      JobClient.runJob(job);

      // do the commits once and for all the reducers in one go

      SolrServer solr =  <b>new</b> CommonsHttpSolrServer(solrUrl);

      solr.commit();

      <b>long</b> end = System.currentTimeMillis();

      LOG.info("SolrIndexer: finished at " + sdf.format(end) + ", elapsed: " + TimingUtil.elapsedTime(start, end));

    }

    <b>catch</b> (Exception e){

      LOG.error(e);

    } <b>finally</b> {

      FileSystem.get(job).delete(tmp, <b>true</b>);

  }

Nutch在这里使用了Hadoop的分布式计算机制,我们跳转到:“IndexerMapReduce.initMRJob(crawlDb, linkDb, segments, job)”方法中看一下,如下:

  <b>public</b> <b>static</b> <b>void</b> initMRJob(Path crawlDb, Path linkDb,

                           Collection&lt;Path&gt; segments,

                           JobConf job) {

    LOG.info("IndexerMapReduce: crawldb: " + crawlDb);

    LOG.info("IndexerMapReduce: linkdb: " + linkDb);

    <b>for</b> (<b>final</b> Path segment : segments) {

      LOG.info("IndexerMapReduces: adding segment: " + segment);

      FileInputFormat.addInputPath(job, <b>new</b> Path(segment, CrawlDatum.FETCH_DIR_NAME));

      FileInputFormat.addInputPath(job, <b>new</b> Path(segment, CrawlDatum.PARSE_DIR_NAME));

      <b>FileInputFormat</b><b>.addInputPath(job, new Path(segment, ParseData.DIR_NAME));</b>

<b>      FileInputFormat.addInputPath(job, new Path(segment, ParseText.DIR_NAME));</b>

    FileInputFormat.addInputPath(job, <b>new</b> Path(crawlDb, CrawlDb.CURRENT_NAME));

    FileInputFormat.addInputPath(job, <b>new</b> Path(linkDb, LinkDb.CURRENT_NAME));

    job.setInputFormat(SequenceFileInputFormat.<b>class</b>);

    job.setMapperClass(IndexerMapReduce.<b>class</b>);

    job.setReducerClass(IndexerMapReduce.<b>class</b>);

    job.setOutputFormat(IndexerOutputFormat.<b>class</b>);

    job.setOutputKeyClass(Text.<b>class</b>);

    job.setMapOutputValueClass(NutchWritable.<b>class</b>);

    job.setOutputValueClass(NutchWritable.<b>class</b>);

可以看到,FileInputFormat.addInputPath(job, new Path(segment, ParseText.DIR_NAME));中仅处理了Segment文件夹下“parse_data”与“parse_text”中的内容。

本文转自william_xu 51CTO博客,原文链接:http://blog.51cto.com/williamx/722707,如需转载请自行联系原作者