NUTCH源代码分析文档格式.docx
《NUTCH源代码分析文档格式.docx》由会员分享,可在线阅读,更多相关《NUTCH源代码分析文档格式.docx(53页珍藏版)》请在冰豆网上搜索。
inject操作分析
inject操作调用的是nutch的核心包之一crawl包中的类org.apache.nutch.crawl.Injector。
它执行的结果是:
crawldb数据库内容得到更新,包括URL及其状态。
inject操作主要作用可以从下面3方面来说明:
(1)将URL集合进行格式化和过滤,消除其中的非法URL,并设定URL状态(UNFETCHED),按照一定方法进行初始化分值;
(2)将URL进行合并,消除重复的URL入口;
(3)将URL及其状态、分值存入crawldb数据库,与原数据库中重复的则删除旧的,更换新的。
generate操作分析
generate操作调用的是crawl包中的类org.apache.nutch.crawl.Generator。
创建了抓取列表,存放于segments目录下,以时间为文件夹名称。
循环抓取多少次,segments文件夹下就会有多少个以时间为名称的文件夹。
generate操作主要作用可以从下面3方面来说明:
(1)从crawldb数据库中将URL取出并进行过滤;
(2)对URL进行排序,通过域名、链接数和一种hash算法综合进行降序排列;
(3)将排列列表写入segments目录中。
fetch操作分析
fetch操作调用的是fetcher包中的类org.apache.nutch.fetcher.Fetcher。
将页面内容抓取下来,存于segment目录下。
fetch操作主要作用可以从下面4方面来说明:
(1)执行抓取,按照segments目录下的抓取列表进行;
(2)抓取过程中,页面的URL地址可能因为链接发生改变,从而需要更新URL地址;
(3)抓取采用多线程方式进行,以提高抓取速度;
(4)fetch操作过程中调用了parse操作。
parse操作分析
parse操作调用的是parse包中的类org.apache.nutch.parse.ParseSegment。
将fetch得到的页面解析为text和data,存于segments目录下。
parse操作主要作用可以从下面3方面来说明:
(1)解析segment中由fetch得到的页面,并进行整理,将页面分成为parse-date和parse-text;
(2)parse-date中保存的是页面的题名、作者、日期、链接等内容;
(3)parse-text中保存的是页面的文本内容。
例如,我只执行一次抓取任务,就执行了上述的一些操作,操作的结果直接反映在segments目录中。
可以看到在home\SHIYANJUN\nutch-0.9\mydir\segments目录下面创建了20081004102407这个目录,该目录中包含6个目录:
content、crawl_fetch、crawl_generate、crawl_parse、parse_data、parse_text,从目录名称就可以大致知道该目录存取的相关内容信息。
updatedb操作分析
updatedb操作调用的是crawl包中的类org.apache.nutch.crawl.CrawlDb。
更新了crawldb数据库,为下一轮抓取做准备。
updatedb操作主要作用如下:
根据segments目录下fetch目录和parse目录中的内容,对crawldb进行更新,增加新的URL,更换旧的URL。
invertlinks操作分析
invertlinks操作用来更新linkDB,为建立索引的工作提供准备。
index过程分析
index过程,即索引过程,包括:
将数据转换成文本、分析文本、将分析过的文本保存到数据库中这三个操作。
(1)转换成文本
在索引数据之前,首先必须将数据转换成nutch能够处理的格式――纯文本字符流。
但是,在现实世界中,信息多以富媒体(richmedia)文档格式呈现:
PDF、WORD、EXCEL、HTML、XML等。
为此,nutch采用了插件机制(plugin),通过各种各样的文档解析器,将富媒体转换成纯文字字符流。
文档解析器种类繁多,开发人员可以根据需要进行选择,同时还可以自己修改或编写,非常灵活方便。
(2)分析文本
在对数据进行索引前,还需要进行预处理,对数据进行分析使之更加适合被索引。
分析数据时,先将文本数据切分成一些大块或者语汇单元(tokens),然后对它们执行一些可选的操作,例如:
在索引之前将这些语汇单元转换成小写,使得搜索对大小写不敏感;
最有代表性的是要从输入中去掉一些使用很频繁但却没有实际意义的词,比如英文文本中的一些停止词(a、an、the、in、on等)。
同样的,我们也需要分析输入的语汇单元,以便从词语中去掉一些不必要的字母以找到它们的词干。
这一处理过程称为分析(analyze)。
分析技术在索引和搜索时都会用到,比较重要。
(3)将分析过的文本保存到数据库中
对输入的数据分析处理完成之后,就可以将结果写入到索引文件中。
Nutch采用的是Lucene的索引格式,可以参考关于Lucene的索引机制。
Lucene采用“倒排索引”的数据结果来存储索引的。
搜索程序分析
Nutch的搜索程序执行过程,可以从下面的步骤了解:
(1)HTTP服务器接收用户发送过来的请求。
对应到nutch的运行代码中就是一个servlet,称为查询处理器(QueryHandler)。
查询处理器负责响应用户的请求,并将相应的HTML结果页面返回给用户。
(2)查询处理器对查询语句做一些微小的处理并将搜索的项(terms)转发到一组运行索引搜索器的机器上。
Nutch的查询系统似乎比lucene简单的多,这主要是因为搜索引擎的用户对他自己所要执行的查询内容有非常清晰的思路。
然而,lucene的系统结构非常灵活,且提供了多种不同的查询方式。
看似简单的nutch查询最终被转换为特定的lucene查询类型。
每个索引搜索器并行工作且返回一组有序的文档ID列表。
(3)现在存在这大量从查询处理器返回过来的搜索结果数据流。
查询处理器对这些结果集进行比较,从所有的结果查找出匹配最好的那些。
如果其中任何一个索引搜索器在1~2秒之后返回结果失败,该搜索器的结果将被忽略。
因此,最后列表由操作成功的搜索器返回的结果组成。
关于查询处理器
查询处理器对查询作了一些细微的处理,例如删除停止词(例如the、of等)。
接着nutch需要执行一些操作以便于它在大规模的数据环境下能更好的工作。
一个索引搜索器涉及搜索的文档集数目非常庞大,所以nutch需要同时与很多索引搜索器交互来提高搜索速率。
实际运行环境中,为了保证系统级别的稳定性,文档集的段文件会被复制到多个不同主机上。
因为对于文档集中的每个段,查询处理器会随机的与其中一个可搜索到自身的索引搜索器相交互。
如果发现一个索引搜索器不能交互,查询处理器会通知之后的搜索操作不使用该搜索器,但是查询处理器每隔一段时间会回头检查一次搜索器的状态,以防该主机上的搜索器再次可用。
关于分析器
Nutch使用自己的分析器,对应于analysis包。
Nutch把索引时进行分析所使用的二元语法技术(bigram)与查询过程中对短语的优化技术结合在一起,通过二元语法技术可以把两个连续的词组合成一个语汇单元。
这就可以大大减少搜索时需要考虑的文档范围,例如,包含词组thequick的文档比包含the的文档要少的多。
分析器对分析操作进行了封装。
分析器通过执行若干操作,将文本语汇单元化,这些操作可能包括提取单词、去除标点符号、去掉语汇单元上的音调符号、将字母转化为小写(也称为规格化)、移除常用词、将单词转换为词干形式(词干还原),或者将单词转换为基本形等。
这个过程也称为语汇单元化过程。
分析操作发生在两个阶段:
建立索引和进行查询时。
nutch的其他一些特性
●为了获取小数量的文档(通常是10个左右),查询处理器会对每个索引搜索器进行查询。
因为最后的结果是从多个索引搜索器中合并得到的,所以就没有必要从一个数据源中获取过多的文档结果,尤其是在用户很少去查看第一页之后的结果的情况下。
●实际上,在每个用户查询被处理之前,它会被扩展为十分复杂的lucene查询。
每个索引过的文档都包含了三个域:
网页自身的内容,网页的URL文本值,以及由所有关键(anchor)文本所组成的合成文档,这些关键文本可在导航网页的超链接中找到。
每个域对应一个不同的权重值。
Nutch的查询处理器生成一个lucene布尔查询,其中在三个域中都包含了搜索引擎用户所输入的文本。
●Nutch也会特别的把那些在web上出现的非常频繁的关键字组作为一个整体来索引(其中的许多关键字是与HTTP相关的词组)。
这些关键字序列出现的非常频繁,所以无需花费精力去对这些词序中的每个组成部分单独搜索,也不必查找出这些搜索结果中是否有交集的部分。
我们不用把这些项划分为单独的单词对来搜索文档,而是把它们作为一个单元,当然前提是nutch在索引期间必须检测到它们是作为一个整体而存在的。
另外,在与索引搜索器交互之前,查询处理器会查找出用户输入的字符串中单词的任意组合。
如果这样一个词序确实存在,它的单词成员就会整合成一个特殊的搜索项。
●在使用lucene执行索引操作之前,nutch的内容获取器/索引器需要预处理HTML文档。
它使用NekoHTML解析器剥离HTML中的内容,并索引其中的非标记文本。
对于从HTML文档提取标题文本,NekoHTML是很有建树的。
●Nutch进程间通信层(IPC)保持了查询处理器与索引搜索器间长时间的连接。
查询处理器端可能存在多个并发的线程,对于给定的地址,任一线程都可以向远程服务器发送调用请求。
服务器每接受一个请求之后,就会根据给定字符串尝试去查找对应的注册服务(运行在自己线程上)。
客户端的请求线程会一直阻塞其他事件,直到服务器端响应的IPC代码到达后,消息通知请求线程为止。
如果服务器的响应花费的时间超过了IPC规定的时限,IPC的代码就会宣布此服务器不可用,并抛出一个异常。
●另外,nutch的排序算法是仿照google的PageRank算法,关于PageRank算法的资料有很多,推荐《Google的秘密PageRank彻底解说中文版》。
NUTCH二
在没有学习研究Nutch的源代码之前,我认为还是有必要对Nutch的工作流程有一个感性的认识和了解。
通过对Nutch工作流程的学习认识,先有一个整体的印象,然后可以很好地指导我们去阅读学习它的源代码,从而更加深入理解Nutch。
当然,也不是唯一的,在阅读一个框架的源代码的时候,只要你选择了一个好的突破口,然后按照基于深度遍历的特性来学习理解,也能起到一定效果。
但是,这种方式有点像是对着一个黑盒进行研究,对一个有机体没有一个整体的把握,也就是说没有整体概念,或者整体概念有点模糊。
Nutch工作流程
先展示一个相当生动的图片,它描述了Nutch的工作流程,如图所示:
其实,只要你沿着图中的数字标号的顺序就可以简单地了解一下Nutch的工作流程。
这里,涉及到一些比较重要的目录,比如crawldb、index、indexes、linkdb、segments,这些目录是在你使用Nutch抓取程序执行抓取任务的过程中,在文件系统中生成的,在文章
$sh./bin/nutchcrawlurls-dirmydir-depth2-threads4-topN50>
&
./logs/mynutchlog.log
之后,可以在mydir目录下面看到上面列举出的5个目录,简单介绍如下:
crawdb,linkdb
是weblink目录,存放url及url的互联关系,作为爬行与重新爬行的依据,页面默认30天过期。
segments
是主目录,存放抓回来的网页。
页面内容有bytes[]的rawcontent和parsedtext的形式。
nutch以广度优先的原则来爬行,因此每爬完一轮会生成一个segment目录。
index
是lucene的索引目录,是indexes目录里所有index合并后的完整索引,注意索引文件只对页面内容进行索引,没有进行存储,因此查询时要去访问segments目录才能获得页面内容。
如果你研究过Lucene,相信index和indexes目录中的文件会非常熟悉的,他们是索引文件,使用不同扩展名的文件来存储不同的内容,比如,.nrm文件是存储标准化因子信息的,.fnm文件是存储文件名字信息的,.prx文件是存储Term的词频信息的,等等。
因为在上面的工作流程图中出现了上面的这些目录,对理解Nutch的工作流程很重要。
下面,根据图中的流程将Nutch的工作流程分为两个部分进行综述。
以index为分隔线,因为第一部分,在左侧,是抓取网页并分析处理;
第二部分是基于index索引库提供检索功能。
第一部分流程综述:
1.)injectstarturls
注入抓取URL。
因为Nutch的抓取程序要抓取网页,而定位到某个(或者某些)网页需要指定一个URL,在此基础上,Nutch按照广度遍历策略进行抓取,会根据一开始指定的URL(可以是一个URL集合:
URLs),以此为基础进行抓取工作。
2.)generatesegment
生成segment。
Nutch抓取程序需要抓取到很多的页面,那么具体是哪些页面的?
当然,在互联网上是通过URL来定位的。
这一步骤主要是对上一步提交的URL集合进行分析,确定抓取任务的详细信息。
fetchlist
分析提交的URL集合之后,建立一个抓取任务列表。
在以后的抓取工作中就可以根据预处理的此列表进行工作了。
www
这是通过访问万维网(www),实现抓取工作。
3.)fetchcontent
开始根据前面生成的抓取任务列表中指定的URL对应的页面,这时候开始抓取工作了。
fetchedcontent
需要将抓取到的这些页面文件存放到指定的位置,这些页面文件可以是经过简单预处理以后而被存储到文件系统中,也可以是原生的网页文件,以备后继流程基于这些文件来进一步处理,比如分词,建立索引。
contentparser
内容解析器。
抓取到的页面文件被提交到这里,实现对页面文件的处理,包括页面文件的分析和处理。
4.)parsecontent
当然,我们抓取的数据是结构和内容非常复杂的数据,而我们感兴趣的主要是文件的内容,因为基于关键字检索的搜索引擎的实现,都是根据文本内容来实现的。
parsedtext&
data
通过contentparser解析器,最终获取到的就是文本内容和其它一些可能需要用到的数据。
有了这些可以识别的文本内容和数据,就可以基于此来建立索引库,而且需要将本次抓取任务的详细信息登录到crawlDB,为下次抓取任务提供有用的信息(比如:
避免重复抓取相同的URL指定的页面)。
因此接下来分为两个方向:
一个是索引,一个是更新crawlDB并继续执行抓取任务:
indexing
这是一个索引的过程,对分析处理完成并提交的文本及其数据建立索引,通过索引文件就可以实现信息的检索功能了。
建立索引过程中,由于是基于Lucene的,所以用到了Analyzer分析器,对预处理的文件进行分析、过滤、分词等等,最后将写入到索引库,供搜索程序工作使用。
updatecrawlDBwithnewextractedurls
根据网页分析处理获取到的信息,更新crawlDB(爬行数据库),并根据提取到的抓取任务已经注入的URLs循环执行抓取任务。
第二部分流程综述:
这部分比较简单了,就是启动WEB服务器,为用户提供检索服务。
这里,用户可以直接通过输入检索关键字,使用Lucene对用户检索关键字进行处理调用Nutch的搜索程序,基于索引库中存储的信息,来提取满足用户检索需求的信息。
Nutch工作流程总结
上面的流程已经分析地非常透彻了,参考一些资料做个总结吧。
通过下面总结的工作流程,理清思路,很有帮助的,如下所示,Nutch的工作流程描述:
抓取程序工作流程
(1.)建立初始URL集
(2.)将URL集注入crawldb数据库---inject
这一步骤,上面的图中没有涉及到。
既然需要维护一个crawlDB,那么在任何时候只要与抓取任务有关的而且是有用的信息都会被写入crawlDB的
(3.)根据crawldb数据库创建抓取列表---generate
(4.)执行抓取,获取网页信息---fetch
(5.)更新数据库,把获取到的页面信息存入数据库中---updatedb
(6.)重复进行3~5的步骤,直到预先设定的抓取深度。
---这个循环过程被称为“产生/抓取/更新”循环
(7.)根据sengments的内容更新linkdb数据库---invertlinks
(8.)建立索引---index
搜索程序工作流程
(1.)用户通过用户接口进行查询操作
(2.)将用户查询转化为lucene查询
(3.)从索引库中提取满足用户检索需求的结果集
(4.)返回结果
NUTCH三
之前对nutch进行些分析,打算在基础上进行一些应用,不过最近忙着,也没弄出个所以然,先把阅读心得贴出来,里边可能有不少理解上的错误,仅供参考用,万一突然有人转载了,请保留blog出处
。
也希望能认识跟多对此话题感兴趣的朋友。
主要类分析:
一、org.apache.nutch.crawl.Injector:
1,注入url.txt
2,url标准化
3,拦截url,进行正则校验(regex-urlfilter.txt)
4,对符URL标准的url进行map对构造<
url,CrawlDatum>
,在构造过程中给CrawlDatum初始化得分,分数可影响urlhost的搜索排序,和采集优先级!
5,reduce只做一件事,判断url是不是在crawldb中已经存在,如果存在则直接读取原来CrawlDatum,如果是新host,则把相应状态存储到里边(STATUS_DB_UNFETCHED(状态意思为没有采集过))
二、org.apache.nutch.crawl.Generator:
1,过滤不及格url(使用url过滤插件)
2,检测URL是否在有效更新时间里
3,获取URLmetaData,metaData记录了url上次更新时间
4,对url进行打分
5,将url载入相应任务组(以host为分组)
6,计算urlhash值
7,收集url,直至到达topN指定量
三、org.apache.nutch.crawl.Fetcher:
1,从segment中读取<
,将它放入相应的队列中,队列以queueId为分类,而queueId是由协议:
//ip组成,在放入队列过程中,
如果不存在队列则创建(比如javaeye的所有地址都属于这个队列:
http:
//221.130.184.141)
-->
queues.addFetchItem(url,datum);
2,检查机器人协议是否允许该url被爬行(robots.txt)-->
protocol.getRobotRules(fit.url,fit.datum);
3,检查url是否在有效的更新时间里-->
if(rules.getCrawlDelay()>
0)
4,针对不同协议采用不同的协议采用不同机器人,可以是http、ftp、file,这地方已经将内容保存下来(Content)。
protocol.getProtocolOutput(fit.url,fit.datum);
5,成功取回Content后,在次对HTTP状态进行识别(如200、404)。
-->
caseProtocolStatus.SUCCESS:
6,内容成功保存,进入ProtocolStatus.SUCCESS区域,在这区域里,系统对输出内容进行构造。
output(fit.url,fit.datum,content,status,CrawlDatum.STATUS_FETCH_SUCCESS);
7,在内容构造过程中,