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<Path> 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<Path> 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,如需转载请自行联系原作者