文章地址php
本次實現分爲兩個部分,第一個部分是利用Lucene構建一個全文的搜索引擎,另一部分則是利用Nutch實現一樣的功能。因爲Lucene並非一個能夠直接運行的程序,且不具有爬蟲和文檔處理的功能,所以在這一部分利用到了Heritrix和HTMLParser這兩個工具分別實現爬蟲與HTML文檔解析的功能。而使用Nutch的時候只須要一些簡單的配置和安裝就能夠直接運行。最後還對這二者進行了一個簡單的對比,說明其各自的特色和適應的範圍。html
因爲Lucene不具有爬蟲的功能,所以這裏使用到了Heritrix這樣的一個工具。咱們利用Heritrix爬取一個指定網站(如:南京大學信息管理學院官方網站)的內容,爲了簡單起見這裏只爬去網頁格式的文檔,而「.doc/.xls/.ppt/.pdf」等格式的文件則直接忽略,所以這裏還須要對爬蟲進行一個簡單的設計。
這裏使用的Heritrix版本爲Heritrix-1.14.4,爬蟲的配置安裝過程以下:
(1)源代碼的導入
因爲這裏須要一些自定義的功能,所以使用的是Heritrix的源代碼版本。爲方便開發,首先咱們須要將其導入Myeclipse。在Myeclipse下創建一個工程名爲「MyHeritrix」。
導入類庫
這一步須要將 Heritrix-1.14.4-src 下的 lib 文件夾拷貝到 MyHeritrix 項目根目錄;方法以下:在 MyHeritrix 工程上右鍵單擊選擇「Build Path Configure Build Path …」,而後選擇 Library 選項卡,單擊「Add JARs …」,在彈出的「JAR Selection」對話框中選擇 MyHeritrix 工程 lib 文件夾下全部的 jar 文件,而後點擊 OK 按鈕。
拷貝源代碼
將 Heritrix-1.14.4-src\src\java 下的 com、org 和 st 三個文件夾拷貝進 MyHeritrix 工程的 src 下。這三個文件夾包含了運行 Heritrix 所必須的核心源代碼;將 Heritrix-1.14.4-src\src\resources\org\archive\util 下的文件 tlds-alpha-by-domain.txt 拷貝到 MyHeritrix\src\org\archive\util 中。該文件是一個頂級域名列表,在 Heritrix 啓動時會被讀取;將 Heritrix-1.14.4-src\src 下 conf 文件夾拷貝至 Heritrix 工程根目錄。它包含了 Heritrix 運行所需的配置文件;將 Heritrix-1.14.4-src\src 中的 webapps 文件夾拷貝至 Heritrix 工程根目錄。該文件夾是用來提供 servlet 引擎的,包含了 Heritrix 的 web UI 文件。
(2)源代碼的修改
因爲咱們須要一個功能:不爬取網頁中的.doc/.xls/.ppt/.pdf等格式的文件,而是自定義須要爬取的網頁文件,所以咱們須要自行修改程序。這裏實現的方法爲擴展 FrontierScheduler 來抓取特定網站內容。
FrontierScheduler 是org.archive.crawler.postprocessor 包中的一個類,它的做用是將在 Extractor 中所分析得出的連接加入到 Frontier 中,以待繼續處理。在該類的 innerProcess(CrawlURI) 函數中,首先檢查當前連接隊列中是否有一些屬於高優先級的連接。若是有,則馬上轉走進行處理;若是沒有,則對全部的連接進行遍歷,而後調用 Frontier 中的 schedule() 方法加入隊列進行處理。這裏咱們自行設計一個類FrontierSchedulerForDaven繼承FrontierScheduler類來修改程序的功能:java
1
2
3
4
5
6
7
8
9
|
public
class
FrontierSchedulerForDaven
extends
FrontierScheduler
而後在該類中重寫schedule函數:
protected
void
schedule(CandidateURI caURI)
…
String uri=caURI.toString();
if
(uri.indexOf(
"dns:"
)!=-
1
){getController().getFrontier().schedule(caURI);}
else
if
(uri.indexOf(「nju.edu.cn
")!=-1)||uri.indexOf("
.html
")!=-1||uri.indexOf("
.php")!=-
1
||uri.indexOf(
".jsp"
)!=-
1
||uri.indexOf(
".asp"
)!=-
1
||uri.indexOf(
".shtml"
)!=-
1
))
…
|
經過這樣的一個布爾表達式實現就能夠實現只爬取後綴名爲html、php、jsp、asp、shtml格式的文件,其餘類型的文件一概忽略。
程序修改完成以後,在修改conf/modules/Processor.options文件,在該文件中添加以下一行:
(3)Heritrix啓動與爬蟲建立
在啓動以前,咱們還須要對Heritrix進行一些簡單的配置,找到conf/Heritrix.properties文件,在文件當中將Heritrix.cmdline.admin(用戶名、密碼)和Heritrix.cmdline.port(端口)兩個參數修改成以下形式:
上面的配置表明,Heritrix啓動時的端口爲9999,用戶名密碼分別爲admin和admin。
完成上面步驟以後,找到org.archive.crawler.Heritrix類,該類是Heritrix的主類入口,直接運行該類就能夠啓動Heritrix。啓動成功以後,控制檯會輸出以下信息:
從上圖能夠看出,Heritrix內置了一個Jetty服務器,在瀏覽其啓動的地址爲:127.0.0.1:9999。在地址欄直接輸入該地址就能夠進入Heritrix的登陸界面。帳戶名和密碼爲上面所設置的admin。
接下來就能夠直接進入爬蟲的建立過程,過程以下:在Job選項卡的create new job中選擇with default即進入爬蟲的建立界面:
上面所表單的第一行爲爬蟲的名稱,第二行爲對爬蟲的描述,下面的文本框中輸入爬蟲的入口地址,例如:http://im.nju.edu.cn/。
(4)爬蟲配置的修改與爬蟲運行
在上面一步的基礎上單擊」modules」按鈕,在相應的頁面爲這次任務設置各個處理模塊,一共有七項可配置的內容:
1)Select Crawl Scope:Crawl Scope 用於配置當前應該在什麼範圍內抓取網頁連接。例如選擇 BroadScope 則表示當前的抓取範圍不受限制,選擇 HostScope 則表示抓取的範圍在當前的 Host 範圍內。在這裏咱們選擇 BroadScope。
2)Select URI Frontier:Frontier 是一個 URL 的處理器,它決定下一個被處理的 URL是什麼。同時,它還會將經由處理器鏈解析出來的 URL 加入到等待處理的隊列中去。
3)Select Pre Processors:這個隊列的處理器是用來對抓取時的一些先決條件進行判斷。好比判斷 robot.txt 信息等,它是整個處理器鏈的入口。
4)Select Fetchers:這個參數用於解析網絡傳輸協議,好比解析 DNS、HTTP 或 FTP 等。
5)Select Extractors:主要是用於解析當前服務器返回的內容,取出頁面中的 URL,等待下次繼續抓取。
6)Select Writers:它主要用於設定將所抓取到的信息以何種形式寫入磁盤。一種是採用壓縮的方式(Arc),還有一種是鏡像方式(Mirror)。這裏咱們選擇簡單直觀的鏡像方式。
7)Select Post Processors:這個參數主要用於抓取解析過程結束後的掃尾工做,好比將 Extrator 解析出來的 URL 有條件地加入到待處理的隊列中去,這裏咱們選擇以前本身定義的類:org.archive.crawler.postprocessor.FrontierSchedulerForDaven
上面的7個參數,除了特別指出來的除外,其餘的幾個採用默認形式便可。
設置完「Modules」後,點擊「Settings」按鈕,這裏只須要設置 user-agent 和 from,其中:「@VERSION@」字符串須要被替換成 Heritrix 的版本信息。「PROJECT_URL_HERE」能夠被替換成任何一個完整的 URL 地址。「from」屬性中不須要設置真實的 E-mail 地址,只要是格式正確的郵件地址就能夠了。
當爬蟲配置完成以後,就能夠運行爬蟲了,選擇console選項卡,點擊start就能夠啓動爬蟲,爬蟲運行過程當中的截圖以下:
爬蟲運行完成以後會在MyHeritrix/jobs文件夾下面生成一個Mirror文件夾,裏面存放了爬去的的文件內容。web
在實際的應用當中,網站內會有大量除了網頁文件以外的文件,例如ms office文件、pdf文件等等。而這些不一樣的文件須要不一樣的工具來進行處理,下面我總結了一些常見格式文檔與其對應的解析工具:
文檔類型 HTML Word Excel PPT RTF PDF
文檔解析器 HTMLParser POI POI POI POI PDFBox
下面對上面所列舉的工具進行一個簡單的介紹:
(1)HTMLParser
HTMLParser是一個專門用來解析HTML格式文檔的開源Java庫,絕不誇張地說,HTMLParser就是目前最好的HTML解析和分析的工具,它的特色是快速健壯。其主要的功能有:
文本信息抽取,例如對HTML進行有效信息搜索
連接提取,用於自動給頁面的連接文本加上連接的標籤
資源提取,例如對一些圖片、聲音的資源的處理
連接檢查,用於檢查HTML中的連接是否有效
頁面內容的監控
連接重寫,用於修改頁面中的全部超連接
網頁內容拷貝,用於將網頁內容保存到本地
內容檢驗,能夠用來過濾網頁上一些使人不愉快的字詞
HTML信息清洗,把原本亂七八糟的HTML信息格式化
轉成XML格式數據
在項目實施過程當中,我利用HTMLParser將一個HTML文檔解析成三行,第一行爲文檔所對應的URL地址,第二行爲文檔的標題,第三行爲文檔的摘要。
第一行:URL
this.page.setURL(getURL(this.filename));
第二行:title
this.page.setTITLE(visitor.getTitle());
第三行:summary
this.page.setCONTEXT(combineNodeText(visitor.getBody().toNodeArray()));
而後將全部解析出來的文檔存入另一個文件夾。該文件夾中的文件能夠直接用於索引的構建。
(2)POI
POI是Apache軟件基金會的開放源碼函式庫,POI提供API給Java程序對Microsoft Office格式文檔讀和寫的功能,它主要有五個模塊,其名稱和功能以下:
模塊 功能
HSSF 提供讀寫Microsoft Excel格式檔案的功能
XSSF 提供讀寫Microsoft Excel OOXML格式檔案的功能
HWPF 提供讀寫Microsoft Word格式檔案的功能
HSLF 提供讀寫Microsoft PowerPoint格式檔案的功能
HDGF 提供讀寫Microsoft Visio格式檔案的功能
因爲這裏不作MS OFFICE文檔的解析,所以再也不詳細解釋其用法。
(3)PDFBox
PDFBox一樣是Apache下的一個開源項目,專門用於PDF文檔的解析。它容許在項目中利用程序設計語言建立PDF文檔、操做多個PDF文檔以及從PDF文檔中解析出內容。
其主要的功能以下:從PDF文檔中解析出內容;合併和分割PDF文檔;PDF問的打印;將PDF文檔轉換爲照片格式;PDF文檔中表格的填充;PDF/A的驗證;PDF文檔的建立;與Lucene的整合開發。算法
索引的構建直接利用Lucene便可完成,索引中利用的分詞工具爲MMAnalyzer極易中文分詞組件,爲了獲得更好的效果咱們可使用中科院的分詞ICTCLAS,可是須要咱們自行編寫分析器Analyzer,這裏爲了簡單起見,利用了現成的中文分詞工具MMAnalyzer。
建立索引的時候,首先須要建立IndexWriter,而後再建立的document,最後建立field來存放不一樣部分的數據。在本實驗中總共建立了4個域(fields),第一個域名稱爲」id」,用於標識一個文件;第二個爲」url」,用於存放該文件所對應的URL;第三個域爲」title」,用於存放該文件的標題,這個標題也被用做在搜索結果中的標題;第四個域爲」context」,用於存放文本的內容,即搜索結果中的摘要部分。
具體的程序代碼以下:apache
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
IndexWriter writer=
new
IndexWriter(path,
new
MMAnalyzer());
//MMAnalyzer極易中文分詞組件
reader=
new
BufferedReader(
new
FileReader(files[i]));
fields[
0
] =
new
Field(
"id"
,String.valueOf(i),Field.Store.YES,Field.Index.NO);
fields[
1
]=
new
Field(
"url"
,reader.readLine(),Field.Store.YES,Field.Index.NO);
fields[
2
]=
new
Field(
"title"
,reader.readLine(),Field.Store.YES,Field.Index.TOKENIZED);
fields[
3
]=
new
Field(
"context"
,getBodyFile(files[i].getAbsolutePath(),reader),Field.Store.YES,Field.Index.TOKENIZED);
//建立Document
Document doc=
new
Document();
//將五個field添加到doc中
for
(
int
j=
0
;j<fields.length;j++)
{doc.add(fields[j]);}
//將Document添加到IndexWriter中
writer.addDocument(doc);
//優化和關閉
writer.optimize();
writer.close();
reader.close()
|
注意在建立完成field以後,經過document的add函數將field添加到document中,完成以後還要利用Indexwriter的addDocument函數將document添加到IndexWriter中。
最後一步不要忘了利用optimize和close函數來優化索引和關閉資源。
索引創建完成以後會在指定索引文件夾中生成四個文件:
_o.cfs/_w.cfs/segments.gen/segements_1f。
接下來就能夠對這些索引文件進行檢索了。數組
Lucene查詢實現的方法主要有兩種,第一種是Query,另一種是Queryparser,二者有明顯的差異。QueryParer類用來轉換用戶的檢索關鍵詞,其做用就是把用戶輸入的非格式化檢索詞轉換爲後臺檢索能夠理解的Query對象。用Queryparser時須要一個參數Analyzer,若是要進行分詞處理的話就可能須要這個參數。
Query類是一個抽象類,須要使用Query的某個子類的構造函數來實例化並以此來表示與用戶檢索有關的內容。具體使用的時候,用戶能夠經過Query的一系列子類,如TermQuery/BooleanQuery/RangeQuery/PrefixQuery/PhraseQuery/MultiPhraseQuery/FuzzyQuery/WildcardQuery/SpanQuery/Regexuery的構造函數來直接生成對應的Query對象。這些檢索方式各有其特色,經過命名大體能夠猜想出它的功能,這裏再也不作詳細的介紹。
爲了方便起見,實驗中用的檢索方式爲TermQuery,這個檢索方式只支持詞的檢索,所以須要在檢索前將問句進行分詞處理,而這裏使用的分詞工具爲ICTCLAS。各個檢索詞之間採用的是布爾運算的「或」運算。瀏覽器
1
2
|
TermQuery[] term=
new
TermQuery[length];
query.add(term[i],BooleanClause.Occur.SHOULD);
//經過後面參數肯定布爾檢索類型
|
在Lucene中布爾檢索中各運算符與其所對應的參數以下表:
運算類型 所對應的參數
AND(與) BooleanClause.Occur.MUST
NOT(非) BooleanClause.Occur.MUST_NOT
OR(或) BooleanClause.Occur.SHOULD
舉例說明布爾或運算的運算規則,若是輸入查詢詞「信息」和「管理」,查詢結果爲包含「信息」與「管理」這兩個詞的文檔與只包含「信息」這個檢索詞的文檔以及只包含「管理」這個詞的文檔。固然在實際的操做中能夠採用徹底不一樣的查詢方式。
下面爲ICTCLAS的分詞過程:tomcat
1
2
3
4
5
6
7
8
9
10
11
|
public
String[] getParserResult(ICTCLAS instance,String sentence){
String result;
result=instance.paragraphProcess(sentence);
String[] res;
res=result.split(
"\\s+"
);
for
(
int
i=
0
;i<res.length;i++){
int
position=res[i].indexOf(
"/"
);
System.out.println(position);
res[i]=res[i].substring(
0
, position);
System.out.println(res[i]); }
return
res;}
|
這裏對上面的程序進行一個簡單的介紹,其中最重要的一行爲:
result=instance.paragraphProcess(sentence);
其中sentence表明輸入的問句,result就是通過分詞獲得的結果,不過輸出結果形式有一個特別之處,例如:句子「信息檢索」其result的結果形式爲「信息/n 檢索/v」,而在實際的過程當中咱們並不須要後面的詞性以及」/」,所以後面的程序代碼都是爲了將分詞結果變成一個字符數組,去掉空格以及後面的」/」和詞性。
分詞完成以後就能夠把分詞結果放入term中進行檢索了。服務器
界面部分須要兩個文件一個index.html文件,一個是search.jsp文件,其中index.html主要做用是查詢主界面的實現。而search.jsp則用戶處理問句、問句檢索以及檢索結果展現。
下面是index.html文件的表單部分代碼:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
<form action=
"search.jsp"
method=
"GET"
>
<input type=
"text"
name=
"keys"
size=
50
height=100px
class
=kw maxlength=
"100"
>
<input type=
"submit"
value=
"search"
class
=sb>
<font size=
"2"
face=
"宋體"
>
能夠看到其表單的內容其實都交給了search.jsp來處理。而search.jsp的部分代碼以下:
<jsp:directive.page
import
=
"com.davenzhang.util.*"
/>
<jsp:directive.page
import
=
"com.xjt.nlp.word.ICTCLAStest"
/>
……
<form action=
"search.jsp"
method=
"get"
>
<input type=
"text"
name=
"keys"
size=
36
maxlength=
"100"
>
<input type=
"submit"
value=
"search"
>
<a href=
"index.html"
>Home</a>
……
out.println(
"<font size=4px color=\"blue\">"
+title+
"</font><br>"
);
out.print(
"摘要:"
+summary);
|
前面的import部分,是導入一些java包,方便在jsp代碼中直接使用其功能,com.davenzhang.util.*主要包含了Lucene的查詢函數,而com.xjt.nlp.word.ICTCLAStest包則包含分詞所用到的函數。後面的out.println()則用於查詢結果的展現
與Lucene不一樣,Nutch是一個能夠直接運行的程序,基本上不須要本身編寫任何代碼就能實現簡單的全文搜索引擎的功能。下面介紹Nutch的安裝和配置過程。
(1) 安裝JDK/Tomcat/Cygwin,這些軟件的安裝都有詳細的教程,這裏再也不贅述。
(2) 修改環境變量
變量名 NUTCH_JAVA_HOME
變量值 %JAVA_HOME%
運行cygwin,輸入命令cd /cygdrive/d/ Nutch-1.2,再輸入bin/Nutch,若是出現Nutch的命令行介紹就表明Nutch安裝成功。
(3) 爬蟲設置
與Lucene不一樣,Nutch自帶了爬蟲的功能,可是須要進行一些配置,下面對這個過程作一個詳細的介紹。
設置須要抓取的網站主域名
在Nutch-1.2的安裝目錄下創建一個名爲urls的文件夾,並在文件夾下創建url.txt文件,在文件中寫入口地址http://im.nju.edu.cn/
設置網站過濾規則
編輯conf/crawl-urlfilter.txt文件,修改MY.DOMAIN.NAME部分。將
# accept hosts in MY.DOMAIN.NAME
+^http://([a-z0-9]*\.)*MY.DOMAIN.NAME/
改成:
# accept hosts in MY.DOMAIN.NAME
+^http://([a-z0-9]*\.)*nju.edu.cn/
修改conf/Nutch-site.xml代理信息
在和之間添加以下文件:
http.agent.name
http://im.nju.edu.cn/value> http.agent.url
http://im.nju.edu.cn/value> http.robots.agents
http://im.nju.edu.cn/ 設置代理名
編輯Nutch-1.2\conf\Nutch-default.xml文件,找http.agent.name,而後隨便設置Value值。例如:
http.agent.name
test
執行Nutch抓取url數據
在Cygwin命令行窗口中輸入:cd /cygdrive/d/Nutch-1.2
再輸入bin/Nutch crawl urls –dir crawl –depth 3 –threads 4 –topN 30 >& crawl.log
命令說明:
crawl:是Nutch檢索數據命令,後面跟上要檢索的URL文件。urls就是第一部分部份建立的文件;
-di:是檢索後的結果存放目錄參數,後面跟上結果存放地址。若是咱們存放到Nutch目錄下的crawl目錄,注意此目錄當前是不存在的。檢索完後Nutch會建立出來。-threads 抓取時的線程數參數
-depth:抓取時的深度參數
-topN:抓取時每頁的最大抓取連接
最後把執行信息寫入crawl.log日誌文件中,方便查找錯誤。
爬蟲執行完成以後會在Nutch的目錄下生成一個crawl文件夾,裏面包含五個子文件夾,分別爲:crawldb/index/indexes/linkdb/segments。
部署到Tomcat
將Nutch-1.2目錄下的Nutch-1.2.war複製到Tomcat目錄webapp下面
修改配置文件WEB-INF\classes\Nutch-site.xml爲以下形式,其中的value值就是剛纔爬蟲爬取得信息。
而後重啓tomcat就能夠完成Nutch的安裝於配置的所有過程。
在瀏覽器中輸入http://localhost:8080/Nutch-1.2/zh/,便可進入Nutch主頁面,輸入檢索詞「南京大學」所獲得的檢索結果以下圖所示:
下面是Nucth的一些特性:
默認把詞語分紅單個詞來查詢,例如,「計算機」會以「計」、「算」、「機」來作查詢。
Nutch中全部的parsing(分析)、indexing(索引)和searching(查詢)都是經過不一樣的插件來實現的。Nutch把本身能夠提供的Plugin接口用一個xml文檔來描述。
自定義插件時,只須要自行設計一些符合自身功能需求的類(繼承Nutch提供的父類或者實現一些接口),而後修改配置文件就好了。
Lucene實際上是一個提供全文文本搜索的函數庫,它不是一個應用軟件。它提供不少API函數讓你能夠運用到各類實際應用程序中。如今,它已經成爲Apache的一個項目並被普遍應用着。Lucene無論是爬蟲的設計,仍是文檔的預處理,仍是索引的創建,仍是系統的分詞等等,都須要用戶編寫代碼,實現功能。Lucene給用戶提供了很是強大的功能,但要享受這些功能的則必須具有編寫複雜代碼的能力。不管是在爬蟲的選擇、搜索的優化、排序算法的設計等等用戶都須要自行決定。
Nutch是一個創建在Lucene核心之上的Web搜索的實現,它是一個真正的應用程序。也就是說,你能夠直接下載下來拿過來用。它在Lucene的基礎上加了網絡爬蟲和一些和Web相關的東西。其目的就是想從一個簡單的站內索引和搜索推廣到全球網絡的搜索上。Nutch主要分爲兩個部分:爬蟲crawler和查詢searcher。Crawler主要用於從網絡上抓取網頁併爲這些網頁創建索引。Searcher主要利用這些索引檢索用戶的查找關鍵詞來產生查找結果。二者之間的接口是索引,因此除去索引部分,二者之間的耦合度很低。Crawler和Searcher兩部分儘可能分開的目的主要是爲了使兩部分能夠分佈式配置在硬件平臺上,例如將Crawler和Searcher分別放在兩個主機上,這樣能夠提高性能。
另外,還有一個和Lucene相似的工具Solr。Solr是Lucene的服務器化,內嵌了jetty,用戶能夠直接post數據給Solr,而後由Solr進行索引。Solr不包含下載系統,用戶須要負責下載,轉成Solr所須要的格式。Nutch和Solr都是基於Lucene的,兩者都是可直接運行的應用程序。 通常可使用Nutch作crawler,而使用Solr作indexer和查詢接口。
參考文獻:
[1]. Otis Gospodnetic;Erik Hatcher(著). lucene in action(中文版).譚鴻;黎俊鴻等譯.北京:電子工業出版社, 2007
[2]. 羅剛.解密搜索引擎技術實戰:Lucene&Java精華版. 北京:電子工業出版社,2011
[3]. 袁津生, 李羣主編.搜索引擎基礎教程.北京:清華大學出版社, 2010
[4]. 高凱,郭立煒,許雲峯編著.網絡信息檢索技術及搜索引擎系統開發.北京:科學出版社, 2010
[5]. http://lucene.apache.org/
[6]. http://nutch.apache.org/
[7]. http://crawler.archive.org/index.html
[8]. http://sourceforge.net/p/htmlparser/wiki/Home/
[9]. http://pdfbox.apache.org/
[10]. poi