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);
}
目前研究到此,后面的待续。。
相关推荐
在使用Nutch之前,你需要配置Nutch的运行环境,包括安装Java、设置Hadoop(如果需要分布式爬取)、下载和编译Nutch源代码。还需要配置Nutch的`conf/nutch-site.xml`文件,指定抓取策略、存储路径、爬虫范围等参数。 ...
1. 使用Git克隆Nutch 1.2的源代码库: ``` git clone https://github.com/apache/nutch.git -b branch-1.2 ``` **构建Nutch** 1. 进入Nutch源代码目录: ``` cd nutch ``` 2. 使用Maven构建Nutch: ``` mvn...
Nutch的源代码可以通过两种方式获取: - **下载发行版**:从官方网站`http://lucene.apache.org/nutch/release/`下载最新版本的Nutch,然后解压缩到你选择的目录。 - **使用Subversion**:如果你想要获取最新的源...
这将创建一个名为`nutch`的目录,包含了项目的全部源代码。 **步骤四:配置Nutch** 进入`nutch`目录,打开`conf/nutch-site.xml`文件,根据你的需求进行配置。例如,你可以修改抓取间隔、抓取策略等。 **步骤五:...
1. **文档阅读**:深入了解 Nutch 需要阅读官方提供的文档,如 "Introduction to Nutch, Part 1 Crawling" 和 "Introduction to Nutch, Part 2 Searching",以及源代码。Nutch 的源码结构清晰,便于理解和学习。 2....
Nutch插件允许开发者根据特定需求定制和扩展Nutch的功能,如自定义爬虫策略、数据解析方式、索引处理逻辑等。 #### 二、Nutch插件开发详解 Nutch插件的开发涉及到以下几个关键步骤: 1. **创建插件目录结构**:...
安装Nutch涉及到Java环境、Hadoop环境的配置,以及Nutch源代码的编译。初学者需要确保Java版本符合要求,安装并配置好Hadoop,然后从Apache官方网站下载Nutch源代码,通过Maven进行编译和构建。 5. **Nutch配置...
3. **构建Nutch**:在Cygwin终端中,导航到Nutch的源代码目录,然后运行`ant`命令来编译Nutch。这个过程会生成所需的类文件和配置文件。 4. **配置Nutch**:根据你的需求修改Nutch的配置文件,主要是在`conf`目录下...
- **配置 Nutch 创建索引**:下载 Nutch 的源代码并解压,然后通过 Maven 进行编译。配置 Nutch 的 `conf/nutch-site.xml` 文件以设置存储路径、抓取策略等参数。 - **安装 Tomcat**:Tomcat 用于运行 Nutch 的 UI...
- `src`: 源代码目录,包含了所有Nutch的Java源码。 - `conf`: 配置文件,如`nutch-default.xml`和`nutch-site.xml`,需要根据实际需求进行调整。 - `bin`: 包含运行Nutch的各种脚本。 - `build.xml`: Ant构建文件,...
用户可以通过修改Nutch的源代码来定制和优化搜索引擎,以适应特定的需求或环境。 **8.2 插件机制---plugin** Nutch的插件机制允许用户扩展Nutch的功能,例如增加新的抓取协议、改进搜索算法等。插件机制增加了...
例如,可能需要修改分析器(Analyzer)、查询解析器(QueryParser)和索引字段(IndexField)的代码,以确保书名号的正确处理。 在提供的文件列表中,"书名号搜索*.png" 可能是相关流程的截图,展示了一些关键步骤...
3. **构建项目**: 使用Maven或Gradle等构建工具编译源代码,生成可执行的JAR文件。 4. **配置文件**: 修改Nutch的配置文件,如`conf/nutch-site.xml`,设置爬虫的基本参数,如抓取间隔、抓取策略等。 5. **初始化...
这个源码包 "apache-nutch-1.3-src.tar.gz" 和 "nutch-1.3.tar.gz" 包含了 Nutch 1.3 的源代码和编译后的二进制文件,对于开发者和研究者来说是非常有价值的资源。 **Nutch 概述** Nutch 是基于 Java 开发的,遵循 ...
5. `src`:Nutch的源代码目录。 6. `webapps`:包含了基于Tomcat的应用程序包,如`nutch-0.9.war`。 Nutch 的基本使用步骤: 1. 安装准备工作:确保系统安装了Cygwin、JDK(1.4.2以上版本)、Nutch(推荐0.9版本)...
- 将插件的源代码保存在`/src/java/org/apache/nutch/parse/self/`目录下。在这个示例中,我们将实现一个名为`indexingFilter`的插件。 - 需要注意的是,插件的类应该遵循Nutch的命名规范,确保与其他模块兼容。 **...
Nutch 的安装通常包括下载源代码或发行版、解压、配置环境变量以及设置必要的配置文件等步骤。Nutch 的配置文件主要有 `conf/nutch-site.xml` 和 `conf/solrconfig.xml` 等,用于指定索引存储位置、日志级别等参数。...
3. 开放源代码:社区活跃,有大量的插件和教程供开发者参考。 四、实际应用场景 1. 内容管理系统:在企业内部构建信息检索平台,帮助员工快速找到所需资料。 2. 新闻门户:提供新闻内容的即时搜索,提升用户体验。...
对于希望深入了解Nutch内部实现机制的研究人员来说,熟悉这些流程和对应的源代码是至关重要的。此外,随着Web技术的发展,如何更好地处理动态网络数据(例如Web2.0数据)和根据网页质量调整抓取策略等问题也成为了...