1、Nutch的配置文件必须放置在CLASSPATH下(补充:也可以放在其他地方,然后修改nutch的启动脚本,让脚 本动态的加载资源)
2、Nutch维护url和md5两个“数据库”是牺牲空间换取时间(补充:我感觉还有更多的作用,但是我想出来)
3、webdb下各文件夹所用的keyClass和valClass
<pagesByURL\data, class org.apache.nutch.io.UTF8, class org.apache.nutch.db.Page>
<pagesByURL\index, class org.apache.nutch.io.UTF8, class org.apache.nutch.io.LongWritable>
<pagesByMD5\data, class org.apache.nutch.db.Page, class org.apache.nutch.io.NullWritable>
<pagesByMD5\index, class org.apache.nutch.db.Page, class org.apache.nutch.io.LongWritable>
<linksByURL\data, class org.apache.nutch.db.Link, class org.apache.nutch.io.NullWritable>
<linksByURL\index, class org.apache.nutch.db.Link, class org.apache.nutch.io.LongWritable>
<linksByMD5\data, class org.apache.nutch.db.Link, class org.apache.nutch.io.NullWritable>
<linksByMD5\index, class org.apache.nutch.db.Link, class org.apache.nutch.io.LongWritable>
4、一个Page的实例
Version: 4
URL: http://www.wintim.com/
ID: 4e2a5053b1568ee29ddae5b8d8b702c7
Next fetch: Wed Jan 24 11:16:34 CST 2007
Retries since fetch: 0
Retry interval: 30 days
Num outlinks: 0
Score: 1.0
NextScore: 1.0
5、WebDBInjector的动作序列
1)将url list中的所有url依次加入到db/webdb.new/tmp/pagesByURL.out中,格式如下:
[length, keylength, <key : PageInstruction, Page>, <value : null>][...]SYNC[...][...]...
2)PagesByURLProcessor.closeDown
2.1 : 将db/webdb.new/tmp/pagesByURL.out中的内容根据key排序,排序结果输出到db/webdb.new/tmp/pagesByURL.out.sorted中
2.2 :将db/webdb.new/tmp/pagesByURL.out.sorted文件更名为db/webdb.new/tmp/pagesByURL.out
2.3 : 将db/webdb/pagesByURL中的<key, value>对与db/webdb.new/tmp/pagesByURL.out中的<key, value>对进行merge sort,
并将结果输出到db/webdb.new/pagesByURL中
(
注意这里的两个key是不同的
db/webdb/pagesByURL中的key为Page,
而db/webdb.new/tmp/pagesByURL.out中的key为<PageInstruction, Page>
但是merge sort是基于Page完成的
)
2.4 : 删除db/webdb.new/tmp/pagesByURL.out文件
3)PagesByMD5Processor.closeDown
......(类似2.1 ~ 2.4)
db/webdb.new/tmp/pagesByMD5.out的格式如下:
[length, keylength, <key : PageInstruction, Page>, <value : null>][...]SYNC[...][...]...
4)linksByMD5Processor.closeDown
......(类似2.1 ~ 2.4)
db/webdb.new/tmp/linksByURL.out的格式如下:
[length, keylength, <key : LinkInstruction, Page>, <value : null>][...]SYNC[...][...]...
5)待完成...
2.1中排序算法:
1、将文件中所有<key, value>对读出,并将每一个<key, value>对的信息记录在starts, pointers, lengths, keyLengths中:
starts : <key, value>对在文件(缓冲区)中的起始位置
pointers : <key, value>对在文件(缓冲区)中的序号
lengths :<key, value>对的长度(字节数)
keyLengths : <key, value>对中key的长度(字节数)
初始时pointers[i] = i
2、根据<key, value>对中的key对进行排序,排序的结果记录在pointers中。
比如文件中存储:a, c, e, b, d, f,初始时pointers为[1, 2, 3, 4, 5, 6]
排序的记过应为:a, b, c, d, e, f,那么结果pointers为[1, 4, 2, 5, 3, 6]
3、for i in pointers:
start = starts[i]
keyStart = start
keyLength = keyLengths[i]
valueStart = keyStart+keyLength
valueLength = lengths[i]-keyLength
key = buffer.read(keyStart, keyLength)
value = buffer.read[valueStart, valueLength)
out.write(length, keyLength, key, value)
6、FetchListTool的动作序列
1) 创建tmp_$date和$date文件夹
2)创建tmp_$date/fetchlist.unsorted文件和tmp_$date/topNSorter.unsorted文件
tmp_$date/fetchlist.unsorted中的<key, value>对为<MD5Hash, FetchListEntry>
3)遍历webdb中的所有page:
3.1 判断该页面是否需要抓取
3.2 调整page中的next fetch值
3.3 将page输出到tmp_$data/topNSorter.unsorted文件中。
文件中的<key, value>对为<SortableScore, FetchListEntry>,其中FetchListEntry为[page,anchors]
4)对tmp_$data/topNSorter.unsorted中的<key, value>对进行排序,结果输出到tmp_$data/topNSorter.sorted中
5)从tmp_$data/topNSorter.sorted文件中取出score最高的n个FetchListEntry,添加到TableSet中
5.1 : 获得每一个FetchListEntry中page中的host信息
5.2 : 对host进行MD5 hash操作
5.3 : 将<MD5 hash, FetchListEntry>对写入到tmp_$date/fetchlist.unsorted中
6)对tmp_$date目录下的所有*.unsorted文件进行排序,生成对应的*.sorted文件
(这是对于emitMultiFetchLists而言,对于emitFetchList,只应该有一个fetchlist.unsorted文件)
7)遍历所有的*.sorted文件,将其中的所有FetchListEntry输出到tmp_$date/fetchlist文件中。
(
fetchlist对应一个ArrayFile,其中的<key, value>对为<long, FetchListEntry>,
特别注意这个long是一个递增的序号数值,与前面的MD5 hash没有任何关系,
MD5 hash只是为了确保fetchlist文件中FetchListEntry的随机性
)
8)因为有一些page要被下载了,所以这些page的next fetch被修改了,将这些修改后的信息需要回馈webdb中
7、Fetcher的动作序列
1) 创建如下的目录结构(注意,fetchlist是FetchListTool的结果)
D:\ECLIPSE\WORKSPACE\NUTCH\CRAWL-20070205102641\segments\20070205102643
├─fetchlist
│ data
│ index
│
├─fetcher
│ data
│ index
│ <key, value>为<long, FetcherOutput>
│
├─content
│ data
│ index
│ <key, value>为<long, Content>
│
├─parse_text
│ data
│ index
│ <key, value>为<long, ParseText>
│
└─parse_data
data
index
<key, value>为<long, ParseData>
2)启动threadCount个线程(FetcherThread),运行每一个线程
2.1 :从segments\$date\fetchlist中读取下一个FetchListEntry对象
2.2 :根据FetchListEntry中的信息获得对应网络协议的具体实现对象
2.3 :通过网络协议的具体实现对象从网络上抓取资源文件
2.4 :根据资源文件的内容类型获得parser
2.5 :通过parser解析资源文件的内容
2.6 :将各种结果写入对应的目录
fetcher -> FetcherOutput [VERSION, FetchListEntry, MD5 hash of content, protocol status, fetch date]
content -> Content [VERSION, url, base, content, contentType, metadata size, metadata]
parse_text -> ParseText [VERSION, text]
parse_data -> ParseData [VERSION, status, title, outlinks length, outlinks, metadata size, metadata]
3)等待所有的FetcherThread结束,将结果写入各个文件夹
8、UpdateSegmentsFromDb的动作序列
1) 创建$root/segUpdates.unsorted文件,其中的<key, value>对为<SegmentPage[url, segment, doc], NullWritable>
2) 遍历$root/segments下的每一个segment(segment是一个目录),在顺序读取segment/fetcher中的每一个FetcherOutput,
根据FetcherOutput对象创建SegmentPage对象,写入$root/segUpdates.unsorted文件
3)将$root/segUpdates.unsorted文件中的<SegmentPage, NullWritable>根据SegmentPage中的url排序,
排序结果输出到$root/segUpdates.sorted文件中
4)删除$root/segUpdates.unsorted文件
5)创建新的$root/segUpdaes.unsorted文件,这次其中的<key, value>对为<SegmentPage, Update[score, anchors]>
6)从$root/segUpdates.sorted文件中读取每一个SegmentPage对象,根据SegmentPage对象构建Update对象,
并将<SegmentPage, Update>对写入到$root/segUpdates.unsorted文件中
7)将$root/segUpdates.unsorted文件中的<SegmentPage, Update>根据SegmentPage中的segment排序,排序结果写入$root/segUpdates.sorted文件中
8)删除$root/segUpdates.unsorted文件
9)遍历$root/segUpdates.sorted中的所有<SegmentPage, Update>对
9.1 : 将$root/segments/下的所有fetcher里的FetcherOutput依次读出
9.2 :如果FetcherOutput与当前SegmentPage匹配,则根据Update中的信息修改FetcherOutput,并写入到$segment/fetcher.new文件中
9.3 :如果不匹配,则将FetcherOuput直接写入到$segment/fetcher.new中
9.4 :最后将$segment/fetcher.new文件更改为$segment/fetcher目录
10)删除$root/segUpdates.sorted文件







