作者:江南白衣
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用入口地址,地址Regex,搜尋深度三種形式來限制
因為使用了Hadoop(下篇再講),Nutch的代碼都按照Hadoop的模式來編寫以獲得分布式的能力,因此要先瞭解一下Hadoop,明白它Mapper,Rerducer, InputFormat, OutputFormat類的作用才能更好的閱讀。
1.Fetcher類, 在run()裡多線程運行FetcherThread,並調用恰當的Protocol外掛程式(支援http,ftp等協議)擷取內容,調用恰當的Parser將內容分析為文本,然後把內容放到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,最後規約出總的結果。
三是每個網站只顯示分數最高的一頁,如果使用者還想看同站的其他結果,就需要訪問MoreHitsExculde[]。
四是產生Summary,讀取segments目錄,按segments和url 獲得content, 並按一定演算法抽取出包含關鍵字的文檔片斷。
3. 修改源碼或編寫外掛程式
Nutch的源碼很容易修改和重新編譯,注意新編譯的class要壓回nutch-0.8.job(實際是一個jar)才會生效。
Nutch的外掛程式機制及度類似Eclipse, 詳看http://wiki.apache.org/nutch/WritingPluginExample,只要實現某個外掛程式介面,然後在plugins.xml裡定義class,擴充點和依賴的jar,如
<plugin id="index-basic" version="1.0.0" provider-name="nutch.org">
<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 訪談錄 -- 關於搜尋引擎的開發。