Nutch是一个基于Lucene,类似Google的完整网络搜索引擎解决方案,基于Hadoop的分布式处理模型保证了系统的性能,类似Eclipse的插件机制保证了系统的可客户化,而且很容易集成到自己的应用之中。
Nutch 0.8 完全使用Hadoop重写了骨干代码,另有很多地方作了合理化修正,非常值得升级。
1.Nutch 0.8 的安装与运行
nutch 0.7.2的中文安装文档满街都是,nutch 0.8的安装文档见Tutorial (0.8) , 要注意两点:
一是 crawl命令里的urls参数从指定文件变为了指定目录, 即原来的urls 要改存到urls/foo 里。
二是 nutch-default.xml里http.agent.name属性默认为空,必须在nutch-site.xml中为该属性设值,否则会出错。
注意nutch 爬行时的信息用log4j输出在/logs 目录下了,默认不再直接输出到屏幕,除非你在配置文件里设fetcher.verbose为true。
Luke(http://www.getopt.org/luke) 是一个必备的索引阅读工具。
另外,nutch需要在unix下奔跑,如果要装在windows上,大家可以先装个cygwin。(下载它的setup.exe 在线安装很快装完)。
最后,nutch 0.8的recawl 脚本也不同了。
2.Nutch You should know
2.1 一份文档
nutch的文档不多,而且多是安装文档,要深入nutch,就必须一字不漏的阅读:
Introduction to Nutch, Part 1 Crawling 和 Introduction to Nutch, Part 2 Searching
然后就是看源码了,好在nutch的源码非常均匀,简短,没有花哨的技巧,很容易把事情看明白。
2.2 三个目录
首先理解nutch的三个数据目录:
1.crawdb,linkdb 是web link目录,存放url 及url的互联关系,作为爬行与重新爬行的依据,页面默认30天过期。
2.segments 是主目录,存放抓回来的网页。页面内容有bytes[]的raw content 和 parsed text的形式。nutch以广度优先的原则来爬行,因此每爬完一轮会生成一个segment目录。
3.index 是lucene的索引目录,是indexs里所有index合并后的完整索引,注意索引文件只对页面内容进行索引,没有进行存储,因此查询时要去访问segments目录才能获得页面内容。
2.3 爬行过程
爬行过程在Introduction to Nutch, Part 1 Crawling 里已有详细说明,或许直接看Crawl类来理解爬行的过程。
这里有一幅更直观的图:
Nutch用入口地址,地址正则表达式,搜索深度三种形式来限制。
因为使用了Hadoop(下篇再讲),Nutch的代码都按照Hadoop的模式来编写以获得分布式的能力,因此要先了解一下Hadoop,明白它Mapper,Reducer, InputFormat, OutputFormat类的作用才能更好的阅读。
1.Fetcher类, 在run()里多线程运行FetcherThread,并调用恰当的Protocol插件(支持http,ftp等协议)获取内容,调用恰当的 Parser将内容(html,pdf,excel)分析为文本,然后把内容放到FetcherOutput类里,最后由 FetcherOutputFormat类定义写盘到segments的过程。
2.Indexer类,使用hadoop遍历所有segments 目录,将parseData文件序列化成ParseData类,从中获得各种资料然后调用插件进行索引,最后仍然由ouputFormat类完成写入索引的工作。
注意,如果你仅想使用Nutch的爬虫,而不是其索引功能,可以仿照Indexer重写自己的实现,比如把segments内容直接搬进数据库。
3.Nutch 每条索引记录的字段
url: 作为唯一标标识值,由BasicIndexingFilter类产生。
segment: 由Indexer类产生。Nutch抓回来的页面内容放在segments目录,lucene只会索引,不会store原文内容,因此在查询时要以 segment与url作为外键,由FetchedSegments类根据hitsDetail从segments目录获得content。
boost:优先级,由Indexer类调用插件计算产生。
title:显示标题,在BasicIndexingFilter插件中被索引和存储。
content: 主要的被搜索项,在BasicIndexingFilter插件中被索引。
2.4 搜索过程
Nutch提供了一个Fascade的NutchBean类供我们使用,一段典型的代码如下
NutchBean bean = new NutchBean();
Query query = Query.parse(args[0]);
Hits hits = bean.search(query, NUM_HITS,"title",true);
for (int i = 0; i < hits.getLength(); i++) {
Hit hit = hits.getHit(i);
HitDetails details = bean.getDetails(hit);
String title = details.getValue("title");
String url = details.getValue("url");
String summary =bean.getSummary(details, query);
}
这里NutchBean为我们做了几样事情:
一是按Title field来排序。
二是支持分布式查询,如果有配置servers,就会使用hadoop的IPC系统,调用所有server上的nutchBeans,最后规约出总的结果。
三是每个站点像Google一样只显示分数最高的一页,如果用户还想看同站的其他结果,就需要进一步调用API访问。
四是生成Summary,从segments目录按segments和url 获得content, 并按一定算法抽取出像Google一样的包含关键字的文档片断。
3. 修改源码或编写插件
Nutch的源码很容易修改和重新编译,注意新编译的class要压回nutch-0.8.job(实际是一个jar)才能生效。
Nutch的插件机制及度类似Eclipse, 详看http://wiki.apache.org/nutch/WritingPluginExample,只要实现某个插件接口,然后在plugins.xml里定义class,扩展点和依赖的jar,如
<runtime>
<library name="index-basic.jar">
<export name="*"/>
</library>
</runtime>
<requires>
<import plugin="nutch-extensionpoints"/>
</requires>
<extension id="org.apache.nutch.indexer.basic"
name="Nutch Basic Indexing Filter"
point="org.apache.nutch.indexer.IndexingFilter">
<implementation id="BasicIndexingFilter" class="org.apache.nutch.indexer.basic.BasicIndexingFilter"/>
</extension>
</plugin>
最后是八卦,Dedian同志翻译的Doug Cutting 访谈录 -- 关于搜索引擎的开发。
最最后,感谢创造 "C++ 必知必会" 这个短语的译者:)
作者:江南白衣
http://www.wujianrong.com/mt-tb.cgi/4342
评论 (1)
Windows 下免CYGWIN 运行Nutch
将以下文本内容存放入NUTCH_HOME\bin 目录下 , 命名随便,设置以下JAVA_HOME 和 NUTCH_HOME,然后在命令行运行 %NUTCH_HOME%\bin\nutch
@echo off
set JAVA_HEAP_MAX="-Xmx512M"
if not "%1"=="" goto INIT else goto echoMSG
:echoMSG
echo Title:欢迎使用北京线点科技 Nutch 运行脚本
echo Author:jaddy0302 mail:jaddy0302@126.com QQ:5622928
echo Site:http://www.xd-tech.com.cn 线点科技 专业垂直搜索引擎产品
echo Nutch Version: 0.7.2
echo Usage: nutch COMMAND
echo where COMMAND is one of:
echo crawl one-step crawler for intranets
echo admin database administration, including creation
echo inject inject new urls into the database
echo generate generate new segments to fetch
echo fetchlist print the fetchlist of a segment
echo fetch fetch a segment's pages
echo parse parse a segment's pages
echo index run the indexer on a segment's fetcher output
echo merge merge several segment indexes
echo dedup remove duplicates from a set of segment indexes
echo updatedb update db from segments after fetching
echo updatesegs update segments with link data from the db
echo mergesegs merge multiple segments into a single segment
echo readdb examine arbitrary fields of the database
echo analyze adjust database link-analysis scoring
echo prune prune segment index(es) of unwanted content
echo segread read, fix and dump segment data
echo segslice append, join and slice segment data
echo server run a search server
echo namenode run the NDFS namenode
echo datanode run an NDFS datanode
echo ndfs run an NDFS admin client
echo jobtracker run the MapReduce job Tracker node
echo tasktracker run a MapReduce task Tracker node
echo or
echo CLASSNAME run the class named CLASSNAME
echo Most commands print help when invoked w/o parameters.
goto end;
:INIT
if not "%NUTCH_HOME%"=="" else set NUTCH_HOME=..
set CLASSPATH=%NUTCH_HOME%\conf;%NUTCH_HOME%\plugin
@echo @echo off>setclasspath.bat
for %%i in (C:\Downloads\nutch-0.7.2\nutch-0.7.2\nutch-*.jar) do @echo set CLASSPATH=%%CLASSPATH%%;%%i>>setclasspath.bat;& for %%i in (C:\Downloads\nutch-0.7.2\nutch-0.7.2\lib\*.jar) do @echo set CLASSPATH=%%CLASSPATH%%;%%i>>setclasspath.bat;
goto EXEC
:EXEC
call setclasspath
if "%1" == "crawl" set CLASS=org.apache.nutch.tools.CrawlTool
if "%1" == "admin" set CLASS=org.apache.nutch.tools.WebDBAdminTool
if "%1" == "inject" set CLASS=org.apache.nutch.db.WebDBInjector
if "%1" == "generate" set CLASS=org.apache.nutch.tools.FetchListTool
if "%1" == "fetchlist" set CLASS=org.apache.nutch.pagedb.FetchListEntry
if "%1" == "fetch" set CLASS=org.apache.nutch.fetcher.Fetcher
if "%1" == "parse" set CLASS=org.apache.nutch.tools.ParseSegment
if "%1" == "index" set CLASS=org.apache.nutch.indexer.IndexSegment
if "%1" == "merge" set CLASS=org.apache.nutch.indexer.IndexMerger
if "%1" == "dedup" set CLASS=org.apache.nutch.indexer.DeleteDuplicates
if "%1" == "updatedb" set CLASS=org.apache.nutch.tools.UpdateDatabaseTool
if "%1" == "updatesegs" set CLASS=org.apache.nutch.tools.UpdateSegmentsFromDb
if "%1" == "mergesegs" set CLASS=org.apache.nutch.tools.SegmentMergeTool
if "%1" == "readdb" set CLASS=org.apache.nutch.db.WebDBReader
if "%1" == "prune" set CLASS=org.apache.nutch.tools.PruneIndexTool
if "%1" == "segread" set CLASS=org.apache.nutch.segment.SegmentReader
if "%1" == "segslice" set CLASS=org.apache.nutch.segment.SegmentSlicer
if "%1" == "analyze" set CLASS=org.apache.nutch.tools.LinkAnalysisTool
if "%1" == "server" set CLASS=org.apache.nutch.searcher.DistributedSearch$Server
if "%1" == "namenode" set CLASS=org.apache.nutch.ndfs.NDFS$NameNode
if "%1" == "datanode" set CLASS=org.apache.nutch.ndfs.NDFS$DataNode
if "%1" == "ndfs" set CLASS=org.apache.nutch.fs.TestClient
if "%1" == "jobtracker" set CLASS=org.apache.nutch.mapReduce.JobTracker
if "%1" == "tasktracker" set CLASS=org.apache.nutch.mapReduce.TaskTracker
call %JAVA_HOME%\bin\java %JAVA_HEAP_MAX% -classpath "%CLASSPATH%" %CLASS% %2 %3 %4 %5 %6 %7 %8 %9
:end
Posted by jaddy | July 25, 2007 10:25 PM