Nutch index源代码解析(一)

Nutch index源代码解析(一) 博客分类: 大数据处理研究 Nutch
solrhadoop索引

Nutch集成slor的索引方法介绍

/**

* 建立索引

* @param solrUrl solr的web地址

* @param crawlDb 爬取DB的存放路径:\crawl\crawldb

* @param linkDb 爬取link的存放路径:\crawl\linkdb

* @param segments 元数据存放路径:\crawl\segments

* @param noCommit  是否提交slor服务器跟下slor索引

* @param deleteGone 是否删除过时的文档

* @param solrParams solr的参数

* @param filter 是否启用URL过滤

* @param normalize 是否格式化 URL

* @throws IOException

*/

public void indexSolr(String solrUrl, Path crawlDb, Path linkDb,

List<Path> segments, boolean noCommit, boolean deleteGone, String solrParams,

boolean filter, boolean normalize) throws IOException {

...

IndexerMapReduce.initMRJob(crawlDb, linkDb, segments, job);

...

}

Nutch的索引,是通过一个MR完成的。

map的输入是Nutch爬去目录下的sequenceFile ,key是Nutch爬取下来的URL,value使用的java泛型,将所有nutch自定义的数据类型抽象成一个NutchWritable对象。

Nutchwritable的包含的的数据类型如下源代码:

CLASSES = new Class[] {

org.apache.hadoop.io.NullWritable.class,

org.apache.hadoop.io.BooleanWritable.class,

org.apache.hadoop.io.LongWritable.class,

org.apache.hadoop.io.BytesWritable.class,

org.apache.hadoop.io.FloatWritable.class,

org.apache.hadoop.io.IntWritable.class,

org.apache.hadoop.io.MapWritable.class,

org.apache.hadoop.io.Text.class,

org.apache.hadoop.io.MD5Hash.class,

org.apache.nutch.crawl.CrawlDatum.class,

org.apache.nutch.crawl.Inlink.class,

org.apache.nutch.crawl.Inlinks.class,

org.apache.nutch.fetcher.FetcherOutput.class,

org.apache.nutch.metadata.Metadata.class,

org.apache.nutch.parse.Outlink.class,

org.apache.nutch.parse.ParseText.class,

org.apache.nutch.parse.ParseData.class,

org.apache.nutch.parse.ParseImpl.class,

org.apache.nutch.parse.ParseStatus.class,

org.apache.nutch.protocol.Content.class,

org.apache.nutch.protocol.ProtocolStatus.class,

org.apache.nutch.scoring.webgraph.LinkDatum.class,

};

这些数据类型分别抽象了Nutch在爬取时各个阶段的数据类型。

map阶段不对value进行处理,只对URL进行处理,处理代码如下:

String urlString = filterUrl(normalizeUrl(key.toString()));

调用是对URL根据定义好的过滤规则对URL进行过滤和格式化,当然是否进行这步操作可以通过调用命令时参数设置。

reduce是对所有爬取的数据进行处理,代码注释如下:

/**

* 输出格式:url作为key,索引的action作为value

*/

public void reduce(Text key, Iterator<NutchWritable> values,

OutputCollector<Text, NutchIndexAction> output, Reporter reporter)

throws IOException {

Inlinks inlinks = null;

CrawlDatum dbDatum = null;

CrawlDatum fetchDatum = null;

ParseData parseData = null;

ParseText parseText = null;

while (values.hasNext()) {

final Writable value = values.next().get(); // unwrap

//如果是URL注入的数据类型

if (value instanceof Inlinks) {

inlinks = (Inlinks)value;

//如果是爬取的数据类型

} else if (value instanceof CrawlDatum) {

final CrawlDatum datum = (CrawlDatum)value;

//如果当前数据处于db注入状态

if (CrawlDatum.hasDbStatus(datum)) {

dbDatum = datum;

}

//如果当前数据处于爬取完成状态。

else if (CrawlDatum.hasFetchStatus(datum)) {

// don't index unmodified (empty) pages

//判断爬去的是否进行了修改

if (datum.getStatus() != CrawlDatum.STATUS_FETCH_NOTMODIFIED) {

fetchDatum = datum;

/**

* Check if we need to delete 404 NOT FOUND and 301 PERMANENT REDIRECT.

*/

//参数中如果设置删除为true则删除错误及过时的页面

if (delete) {

//如果爬取的页面过期,采取删除操作。

if (fetchDatum.getStatus() == CrawlDatum.STATUS_FETCH_GONE) {

reporter.incrCounter("IndexerStatus", "Documents deleted", 1);

NutchIndexAction action = new NutchIndexAction(null, NutchIndexAction.DELETE);

output.collect(key, action);

return;

}

//如果爬去的页面已经重定向到另外一个页面,才去删除操作。

if (fetchDatum.getStatus() == CrawlDatum.STATUS_FETCH_REDIR_PERM) {

reporter.incrCounter("IndexerStatus", "Perm redirects deleted", 1);

NutchIndexAction action = new NutchIndexAction(null, NutchIndexAction.DELETE);

output.collect(key, action);

return;

}

}

}

//URL是通过其他URL被发现的 ||页面的签名||页面的元数据是通过解析器产生的

} else if (CrawlDatum.STATUS_LINKED == datum.getStatus() ||

CrawlDatum.STATUS_SIGNATURE == datum.getStatus() ||

CrawlDatum.STATUS_PARSE_META == datum.getStatus()) {

continue;

} else {

throw new RuntimeException("Unexpected status: "+datum.getStatus());

}

//如果是解析的数据类型

} else if (value instanceof ParseData) {

parseData = (ParseData)value;

// Handle robots meta? https://issues.apache.org/jira/browse/NUTCH-1434

if (deleteRobotsNoIndex) {

// Get the robots meta data

String robotsMeta = parseData.getMeta("robots");

// Has it a noindex for this url?

if (robotsMeta != null && robotsMeta.toLowerCase().indexOf("noindex") != -1) {

// Delete it!

NutchIndexAction action = new NutchIndexAction(null, NutchIndexAction.DELETE);

output.collect(key, action);

return;

}

}

//解析完的Text文件

} else if (value instanceof ParseText) {

parseText = (ParseText)value;

} else if (LOG.isWarnEnabled()) {

LOG.warn("Unrecognized type: "+value.getClass());

}

}

//如果只有链接,没有爬取历史的记录或者爬取数据直接返回

if (fetchDatum == null || dbDatum == null

|| parseText == null || parseData == null) {

return;                                     // only have inlinks

}

// Whether to skip DB_NOTMODIFIED pages

//如果页面被爬取过,但是没有进行修过,在传进来的命令中设置了跳过则跳过。

if (skip && dbDatum.getStatus() == CrawlDatum.STATUS_DB_NOTMODIFIED) {

reporter.incrCounter("IndexerStatus", "Skipped", 1);

return;

}

//页面爬去成功,但是解析失败的,直接返回

if (!parseData.getStatus().isSuccess() ||

fetchDatum.getStatus() != CrawlDatum.STATUS_FETCH_SUCCESS) {

return;

}

NutchDocument doc = new NutchDocument();

//解析完的数据中获取页面的元数据

final Metadata metadata = parseData.getContentMeta();

// add segment, used to map from merged index back to segment files

doc.add("segment", metadata.get(Nutch.SEGMENT_NAME_KEY));

//页面摘要

// add digest, used by dedup

doc.add("digest", metadata.get(Nutch.SIGNATURE_KEY));

final Parse parse = new ParseImpl(parseText, parseData);

try {

// extract information from dbDatum and pass it to

// fetchDatum so that indexing filters can use it

final Text url = (Text) dbDatum.getMetaData().get(Nutch.WRITABLE_REPR_URL_KEY);

if (url != null) {

fetchDatum.getMetaData().put(Nutch.WRITABLE_REPR_URL_KEY, url);

}

// run indexing filters

//执行所有过滤器

doc = this.filters.filter(doc, parse, key, fetchDatum, inlinks);

} catch (final IndexingException e) {

if (LOG.isWarnEnabled()) { LOG.warn("Error indexing "+key+": "+e); }

reporter.incrCounter("IndexerStatus", "Errors", 1);

return;

}

// skip documents discarded by indexing filters

if (doc == null) {

reporter.incrCounter("IndexerStatus", "Skipped by filters", 1);

return;

}

float boost = 1.0f;

// run scoring filters

//执行评分过滤器

try {

boost = this.scfilters.indexerScore(key, doc, dbDatum,

fetchDatum, parse, inlinks, boost);

} catch (final ScoringFilterException e) {

if (LOG.isWarnEnabled()) {

LOG.warn("Error calculating score " + key + ": " + e);

}

return;

}

//将评分作为文档的权重

// apply boost to all indexed fields.

doc.setWeight(boost);

// store boost for use by explain and dedup

doc.add("boost", Float.toString(boost));

reporter.incrCounter("IndexerStatus", "Documents added", 1);

NutchIndexAction action = new NutchIndexAction(doc, NutchIndexAction.ADD);

output.collect(key, action);

}

目前研究到此,后面的待续。。

时间: 2025-01-20 17:16:03

Nutch index源代码解析(一)的相关文章

Nutch index源代码解析二)

Nutch index源代码解析二) 博客分类: 大数据处理研究 Ntuch solrhadoop爬虫 接着上篇文档~~~~~ 上篇文章写到,Nutch采用一个MR对爬取下来的文档进行清洗和封装成一个action列表. 接下来介绍怎么爬取下来的数据如何推送给solr. ----------------------------------------------------华丽的分割线--------------------------------------------- Ntuch自定义了一个

详细的Android属性动画源代码解析及小结

本文假定你已经对属性动画有了一定的了解,至少使用过属性动画.下面我们就从属性动画最简单的使用开始. ObjectAnimator   .ofInt(target,propName,values[])   .setInterpolator(LinearInterpolator)   .setEvaluator(IntEvaluator)   .setDuration(500)   .start(); 相信这段代码对你一定不陌生,代码中有几个地方是本文中将要重点关注的,setInterpolator

Spring源代码解析(一):IOC容器

在认真学习Rod.Johnson的三部曲之一:< >,顺便也看了看源代码想知道个究竟,抛砖引玉,有兴趣的同志一起讨论研究吧! 以下内容引自博客:http://jiwenke-spring.blogspot.com/,欢迎指导:) 在Spring中,IOC容器的重要地位我们就不多说了,对于Spring的使用者而言,IOC容器实际上是什么呢?我们可以说BeanFactory就是我们看到的IoC容器,当然了Spring为我们准备了许多种IoC容器来使用,这样可以方便我们从不同的层面,不同的资源位置,

Android属性动画源代码解析(超详细)

本文假定你已经对属性动画有了一定的了解,至少使用过属性动画.下面我们就从属性动画最简单的使用开始. ObjectAnimator .ofInt(target,propName,values[]) .setInterpolator(LinearInterpolator) .setEvaluator(IntEvaluator) .setDuration(500) .start(); 相信这段代码对你一定不陌生,代码中有几个地方是本文中将要重点关注的,setInterpolator(...).setE

linux device tree源代码解析【转】

转自:http://blog.csdn.net/Tommy_wxie/article/details/42806457 //Basedon Linux v3.14 source code Linux设备树机制(Device Tree) 一.描述 ARM Device Tree起源于OpenFirmware (OF),在过去的Linux中,arch/arm/plat-xxx和arch/arm/mach-xxx中充斥着大量的垃圾代码,相当多数的代码只是在描述板级细节,而这些板级细节对于内核来讲,不过

Spring源代码解析(九):Spring Acegi框架鉴权的实现

简单分析一下Spring Acegi的源代码实现: Servlet.Filter的实现AuthenticationProcessingFilter启动Web页面的验证过程 - 在AbstractProcessingFilter定义了整个验证过程的模板: Java代码 public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, Servle

ORACLE自带的JDBC源代码解析

oracle|源代码         大凡使用过JDBC连ORACLE的人都会知道这样一个事实:我们需要的库文件classes12.zip存在于$ORACLE_HOME/jdbc/lib目录下(但仍有部分菜鸟每每在论坛上求此库文件,真是辛苦):但很少有人知道ORACLE还为我们准备了使用jdbc的示例,它存在于 $ORACLE_HOME/jdbc/demo/demo.zip 中.        前一段时间,我学习ORACLE的OOP技术,很受触动.当时我想:JDBC中一定存在某些OO技术以支持它

Spring源代码解析(六):Spring声明式事务处理

我们看看Spring中的事务处理的代码,使用Spring管理事务有声明式和编程式两种方 式,声明式事务处理通过AOP的实现把事物管理代码作为方面封装来横向插入到业务代码 中,使得事务管理代码和业务代码解藕.在这种方式我们结合IoC容器和Spirng已有的 FactoryBean来对事务管理进行属性配置,比如传播行为,隔离级别等.其中最简单的方 式就是通过配置TransactionProxyFactoryBean来实现声明式事物: 在整个源代码分析中,我们可以大致可以看到Spring实现声明式事物

Spring源代码解析(二):IOC容器在web容器中的启动

以下引用自博客:http://jiwenke-spring.blogspot.com/ 上面我们分析了IOC容器本身的实现,下面我们看看在典型的web环境中,Spring IOC 容器是怎样被载入和起作用的. 简单的说,在web容器中,通过ServletContext为Spring的IOC容器提供宿主环境,对 应的建立起一个IOC容器的体系.其中,首先需要建立的是根上下文,这个上下文持有的 对象可以有业务对象,数据存取对象,资源,事物管理器等各种中间层对象.在这个上下 文的基础上,和web MV