郭永利,盧穎穎
基于Lucene對(duì)文件全文檢索的研究與應(yīng)用
郭永利,盧穎穎
分析了Lucene的原理,針對(duì)Lucene的IndexReader、IndexSearcher、IndexWriter、Directory的各種不足,研究了不同優(yōu)化方案,并通過(guò)重寫(xiě)源碼中的QueryParser限制效率低下的通配符查詢及模糊查詢,提高了搜索響應(yīng)速度,最后,文章研究了Lucene的多個(gè)應(yīng)用領(lǐng)域。
搜索引擎;全文搜索;分詞;索引;優(yōu)化
隨著網(wǎng)絡(luò)技術(shù)飛速發(fā)展,產(chǎn)生了大量數(shù)字信息,如何從這浩如煙海的文本信息中快速而又準(zhǔn)確地獲取想要的信息,成為人們關(guān)注的焦點(diǎn),也一直是國(guó)內(nèi)外不斷研究的課題,因此,全文檢索技術(shù)成為國(guó)內(nèi)外學(xué)者研究的熱點(diǎn)。
全文檢索的主要目的是建立索引與快速查詢,以便能使用戶快速?gòu)暮A康男畔⒅兴阉鞒龇蠗l件的信息。當(dāng)前文本檢索有3種建索引方式:倒排索引、下標(biāo)數(shù)組和簽名文件,其中最常用的是倒排索引。雖然國(guó)外的全文檢索軟件研究的較早,技術(shù)較先進(jìn),應(yīng)用也較廣泛,但對(duì)中國(guó)用戶確有很多不適用之處[1]。中文以其獨(dú)特的單字成詞、多字成詞、詞前詞后加字或詞亦能成詞,使得中文分詞的實(shí)現(xiàn)比西文分詞更為復(fù)雜,中文分詞算法成為全文檢索技術(shù)中的一大難題。
目前最流行的全文檢索技術(shù)是Lucene,由于Lucene具有開(kāi)放性及擴(kuò)展性等優(yōu)勢(shì),所以利用Lucene建立電子公文檢索系統(tǒng),一方面可以真正的實(shí)現(xiàn)全文檢索,另一方面也可以在成本比較低的情況下擴(kuò)充其功能。
2.1 分詞概述
不同的語(yǔ)言有不同的分詞,對(duì)于中國(guó)人來(lái)說(shuō)主要關(guān)注的是中文分詞。中文分詞比英文分詞要困難、復(fù)雜的多,具體表現(xiàn)在:
(1)在英文中,因其由單詞構(gòu)成句子,單詞間以空格隔開(kāi),而句子之間又能以標(biāo)點(diǎn)符號(hào)隔開(kāi),因此英文分詞相對(duì)簡(jiǎn)單。
(2)在中文里,由于其特殊的語(yǔ)法,可以單字成詞,多字成詞,單字的左右兩邊分別加上其他的字也可能成詞,因此“詞”和“詞組”邊界模糊。
中文分詞基本算法主要有:基于詞典的方法、基于統(tǒng)計(jì)的方法、基于規(guī)則的方法。其中基于詞典的方法包括正向最大匹配算法、逆向最大匹配、雙向最大匹配[2]。MMSeg中文分詞算法是基于正向最大匹配的算法,算法描述如下:
步驟1:對(duì)文章基于詞典進(jìn)行切割,獲得chunks。
步驟2:使用規(guī)則1過(guò)濾chunks,判斷過(guò)濾后的chunks個(gè)數(shù)是否大于或等于2。是:進(jìn)入步驟3,否:進(jìn)入步驟7。
步驟3:使用規(guī)則2過(guò)濾chunks,判斷過(guò)濾后的chunks個(gè)數(shù)是否大于或等于2。是:進(jìn)入步驟4,否:進(jìn)入步驟7。
步驟4:用規(guī)則3過(guò)濾chunks,判斷過(guò)濾后的chunks個(gè)數(shù)是否大于或等于2。是: 進(jìn)入步驟5,否:進(jìn)入步驟7。
步驟5:用規(guī)則4過(guò)濾chunks,判斷過(guò)濾后的chunks個(gè)數(shù)是否大于或等于2。是: 進(jìn)入步驟6,否:進(jìn)入步驟7。
步驟6:拋出一個(gè)表示歧義的異常。
步驟7:分詞成功。
2.2 Lucene索引
(1)Lucene索引文件分析
Lucene采用文件的方式保存索引的信息,文件格式主要有:segment,.fnm,.fdx,.fdt,.tii,.tis,deletable,cfs等[3-4]。每個(gè)segment代表Lucene的一個(gè)完整索引段。.fnm格式的文件包含了Document中的所有Field名稱。.fdx和.fdt是綜合使用的兩類文件,其中.fdt類型文件用于存儲(chǔ)具有Store.YES屬性的Field數(shù)據(jù)。而.fdx類型文件則是一個(gè)索引,用于存儲(chǔ)Document信息。.tis文件用于存儲(chǔ)分詞后的詞條(Term),而.tii就是它的所有文件,它標(biāo)明了每個(gè).tis文件中詞條的位置。deletable格式用于對(duì)刪除的文件留一條記錄,該記錄被刪除時(shí),才將索引除去。
復(fù)合索引格式用于索引的內(nèi)容可能非常大,文件數(shù)量可能非常多的情況。如果遇到這種情況,系統(tǒng)打開(kāi)文件的數(shù)量巨大將會(huì)極大地耗費(fèi)系統(tǒng)資源。因此,Lucene提供了一個(gè)單文件索引格式(復(fù)合索引格式)。
(2)倒排索引
在日常的檢索中,通常都是按照關(guān)鍵詞進(jìn)行搜索的,所以,倒排索引可以更好地適合這種檢索機(jī)制的需要,這也是倒排索引如今被大規(guī)模使用的原因[5-6]。
倒排索引用到的數(shù)據(jù)結(jié)構(gòu)如下:
class WordInfo
{
int articleId;
int count;
List
}
Map
WordInfo記錄了分詞的位置信息與分詞的個(gè)數(shù),Map中的鍵值表示了分詞內(nèi)容。算法描述:
步驟1:將文章進(jìn)行分詞,并將分詞保存到隊(duì)列中。
步驟2:判斷分詞隊(duì)列是否為空。是: 算法結(jié)束,否:進(jìn)入步驟3。
步驟3:取出隊(duì)首分詞,判斷該分詞是否已經(jīng)被存儲(chǔ)。是:進(jìn)入步驟5,否:進(jìn)入步驟4。
步驟4:創(chuàng)建一個(gè)用于保存此分詞信息的哈希表。進(jìn)入步驟5。
步驟5:判斷該分詞的文章號(hào)是否已經(jīng)被存儲(chǔ)。是:進(jìn)入步驟7,否:進(jìn)入步驟6。步驟6:創(chuàng)建一個(gè)用于保存該文章分詞信息的哈希表。步驟7:保存該分詞在該文章中出現(xiàn)的位置,并將其個(gè)數(shù)加一。
步驟8:返回步驟2。
2.3 Lucene搜索
搜索功能定義:Lucene搜索就是通過(guò)已經(jīng)建立好的索引,根據(jù)用戶要搜索的關(guān)鍵詞,將匹配的信息返回給用戶。
TermQuery對(duì)索引中特定項(xiàng)進(jìn)行搜索,是最基本的搜索方式。Term是最小的索引片段,每個(gè)Term包含了一個(gè)域名和一個(gè)文本值。
Term term = new Term(“content”,”java”);
Query query= new TermQuery(term);
使用這個(gè)TermQuery對(duì)象進(jìn)行搜索,可以返回在content域中包含單詞“java”的所有文件。值得注意的是,該查詢值是區(qū)分大小寫(xiě)的,因此搜索前一定要對(duì)索引后的項(xiàng)的大小寫(xiě)進(jìn)行匹配。TermQuery類在根據(jù)關(guān)鍵詞查詢文件時(shí)顯得特別適用,具體的創(chuàng)建步驟為:
(1)創(chuàng)建Directory
(2)創(chuàng)建IndexReader
(3)創(chuàng)建IndexSearcher
(4)創(chuàng)建Term和TermQuery
(5)根據(jù)TermQuery獲取TopDocs
(6)根據(jù)TopDocs獲取ScoreDoc
(7)根據(jù)ScoreDoc獲取相應(yīng)文件
Lucene中的查詢功能是非常強(qiáng)大的,它包含了項(xiàng)查詢、區(qū)間查詢、條件查詢等各式各樣的查詢功能,并且可以由用戶方便的擴(kuò)展查詢功能。Lucene中自帶的查詢類主要有:TermRangeQuery、NumericRangeQuery、PrefixQuery、BooleanQuery、PhraseQuery、WildcardQuery、FuzzyQuery、Queryparser等。
2.4 Lucene評(píng)分
查詢q相對(duì)于文檔d的分?jǐn)?shù)與在文檔和查詢向量之間的余弦距離或者點(diǎn)乘積有關(guān)系,文檔和查詢向量存于一個(gè)信息檢索(的向量空間模型)之中。一篇文檔的向量與查詢向量越接近,它的得分也越高,如公式(1):
其中tf(t in d) 與term的出現(xiàn)次數(shù)有關(guān)系,term的次數(shù)越多的文檔將獲得越高的分?jǐn)?shù)。缺省的tf(t in d)算法實(shí)現(xiàn)在DefaultSimilarity類中,如公式(2):
idf(t) 代表反轉(zhuǎn)文檔頻率。這個(gè)分?jǐn)?shù)與反轉(zhuǎn)的docFreq有關(guān)系。缺省idf(t in d)算法實(shí)現(xiàn)在DefaultSimilarity類中,如公式(3):
coord(q,d) 是一個(gè)評(píng)分因子,在搜索的時(shí)候起作用,它在Similarity對(duì)象的coord(q,d)函數(shù)中計(jì)算。
queryNorm(q) 是一個(gè)修正因子,用來(lái)使不同查詢間的分?jǐn)?shù)更可比較。缺省queryNorm(q)算法實(shí)現(xiàn)在DefaultSimilarity類中,如公式(4):
sumOfSquaredWeights(查詢的terms)是由查詢Weight對(duì)象計(jì)算的,例如一個(gè)布爾條件查詢的計(jì)算公式如公式(5):
t.getBoost() 是一個(gè)搜索時(shí)的代表查詢q中的term t的boost數(shù)值,查詢里的一個(gè)term的boost值的訪問(wèn)是通過(guò)調(diào)用子查詢的getBoost()方法實(shí)現(xiàn)的。
norm(t,d) 是提煉取得一小部分boost值(在索引時(shí)間)和長(zhǎng)度因子。計(jì)算方法如公式(6):
3.1 IndexReader優(yōu)化
Indexreader不應(yīng)當(dāng)頻繁構(gòu)建,因?yàn)槊繕?gòu)建一個(gè)IndexRe ader實(shí)例,都要對(duì)索引目錄中的索引文件重新加載一遍,不僅增大了服務(wù)器的負(fù)擔(dān),而且大大降低了搜索響應(yīng)時(shí)間。系統(tǒng)中應(yīng)將IndexReader保存為單例,維持一個(gè)IndexReader。并通過(guò)采用IndexReader.openIfChanged(IndexReader oldRea der)的方式來(lái)獲得最新的索引。當(dāng)索引目錄改變時(shí),此方法可以避免加載全部索引,而是只加載更新部分的索引,并且返回最新的索引實(shí)例。系統(tǒng)中如果索引沒(méi)有變化,IndexRe ader.openIfChanged會(huì)返回null。因此相對(duì)于開(kāi)啟新的Index Reader,該方法成本更低。
3.2 IndexSearcher優(yōu)化
用IndexReader做為參數(shù)構(gòu)造IndexSearcher時(shí),把reader設(shè)為只讀,通過(guò)避免并發(fā)檢查,可以提高性能。而盡可能減少I(mǎi)ndexSearcher的創(chuàng)建和對(duì)搜索結(jié)果的前臺(tái)的緩存也是必要的。
3.3 IndexWriter優(yōu)化
對(duì)IndexWriter進(jìn)行緩存,讓程序中只有一個(gè)IndexWriter實(shí)例。因?yàn)镮ndexWriter 是對(duì)索引庫(kù)目錄下的文件進(jìn)行操作,就算在多線程情況下,每次也只會(huì)有一個(gè)線程在訪問(wèn)這個(gè)文件。通過(guò)在查詢中復(fù)用,可以大幅度提高搜索的速度,因?yàn)槊看未蜷_(kāi),都會(huì)進(jìn)行索引的加載,影響了性能,對(duì)它進(jìn)行緩存后等于對(duì)查詢進(jìn)行了預(yù)熱。因此,程序中沒(méi)必要維持多個(gè) IndexWriter實(shí)例。
3.4 Directory優(yōu)化
Directory分為FSDirectory和RAMDirectory。FSDirectory 速度相對(duì)慢,但是 FSDirectory 的優(yōu)點(diǎn)是能夠在磁盤(pán)上持久化數(shù)據(jù)。RAMDirectory 讀寫(xiě)數(shù)據(jù)的速度明顯要快,但是缺點(diǎn)是數(shù)據(jù)在程序退出時(shí)就沒(méi)有了。而且受限制于內(nèi)存的大小。因此可以將兩者進(jìn)行結(jié)合,在程序啟動(dòng)的時(shí)候,將磁盤(pán)上的索引庫(kù)加載到內(nèi)存中來(lái)。在程序退出的時(shí)候或指定一個(gè)時(shí)機(jī),將內(nèi)存中的索引庫(kù)數(shù)據(jù)狀態(tài)同步到硬盤(pán)上。
3.5 自定義QueryParser優(yōu)化
由于某些查詢方式(FuzzyQuery,WildcardQuery)會(huì)降低查詢的性能,所以考慮將這些查詢?nèi)∠?。并且在具體的查詢時(shí),很有可能有這樣一種需求:需要獲取的是一個(gè)數(shù)字的范圍查詢。所以必須擴(kuò)展原有的QueryParser才能進(jìn)行查詢。
實(shí)現(xiàn)思路:繼承QueryParser類,并且重載相應(yīng)方法從而達(dá)到限制性能低的查詢方式及擴(kuò)展居于數(shù)字和日期的查詢的目的。
經(jīng)過(guò)多年的發(fā)展,Lucene全文檢索以其高效的搜索響應(yīng)速度,成功滲透進(jìn)入各行各業(yè),并積累了良好的聲譽(yù)。本文研究了Lucene在Krugle源碼搜索網(wǎng)站中的應(yīng)用、在LinkedIn.com社區(qū)網(wǎng)絡(luò)中的應(yīng)用、在網(wǎng)絡(luò)教學(xué)中的應(yīng)用、在醫(yī)學(xué)知識(shí)搜索系統(tǒng)中的應(yīng)用、Lucene在電子檔案檢索系統(tǒng)中的應(yīng)用及在SIREn中的應(yīng)用,以下詳細(xì)介紹Lucene前四個(gè)方面的應(yīng)用。
4.1 在Krugle源碼搜索網(wǎng)站中的應(yīng)用
Krugle是一個(gè)源代碼搜索引擎,連續(xù)提供了4000多個(gè)開(kāi)源項(xiàng)目[7]。Krugle是在Lucene基礎(chǔ)上搭建的,但由于這里的搜索文件內(nèi)容都是由代碼構(gòu)成的,這樣會(huì)為搜索引擎帶來(lái)一些有趣的挑戰(zhàn)。舉例來(lái)說(shuō),當(dāng)搜索“indexSearcher”時(shí),程序必須匹配源代碼中諸如“IndexSearcher”等語(yǔ)匯單元。諸如“=”和“(”等標(biāo)點(diǎn)符號(hào)的搜索可能會(huì)在其他搜索網(wǎng)站的分析過(guò)程中被忽略,而這里卻必須要進(jìn)行小心處理,以便能搜索到諸如“for(int x=0”等預(yù)期結(jié)果。與自然語(yǔ)言中通常用停用詞來(lái)區(qū)分各個(gè)項(xiàng)所不同的是,Krugle必須保留源代碼中所有這些語(yǔ)匯單元。
4.2 在LinkedIn.com社區(qū)網(wǎng)絡(luò)中的應(yīng)用
LinkedIn.com是世界上最大的專業(yè)社區(qū)網(wǎng)絡(luò),其用戶總數(shù)超過(guò)6000萬(wàn),該社區(qū)的主要功能就是“搜索人”,Lucene加強(qiáng)了LinkedIn的搜索功能。LinkedIn有兩個(gè)強(qiáng)大的Lucene擴(kuò)展,分別為Zoie與Bobo Browse。Zoie是一個(gè)基于Lucene構(gòu)建的實(shí)時(shí)搜索系統(tǒng)。Bobo Browse它能提供分組信息搜索功能,它的開(kāi)源代碼庫(kù)是基于Lucene構(gòu)建的,并能對(duì)任何基于Lucene的項(xiàng)目添加分組功能。它的索引是由簡(jiǎn)單的Lucene索引加上一些有關(guān)如何將域用于支持分組搜索的聲明組成的。這些聲明可以通過(guò)Spring配置文件的形式加入Lucene索引文件目錄,同時(shí)可以使用bobo.spring。這些聲明還可以通過(guò)建立BoboIndexReader類進(jìn)行程序構(gòu)建。這種架構(gòu)上的選擇可以使得Lucene索引在不被重新進(jìn)行構(gòu)建的情況下實(shí)現(xiàn)索引的分組瀏覽。
4.3 在網(wǎng)絡(luò)教學(xué)中的應(yīng)用
針對(duì)網(wǎng)絡(luò)教學(xué)平臺(tái)的教育資源研究并定制一個(gè)全文檢索系統(tǒng)。系統(tǒng)可以采用分詞優(yōu)化組合的分詞方案,即用匹配度和檢索效率更高的詞典/語(yǔ)法切詞與具備較大靈活性的單字切分相結(jié)合的分詞方法,從而達(dá)到透徹地分析用戶輸入的查詢請(qǐng)求,以保證檢索結(jié)果的質(zhì)量和靈活性[8]。系統(tǒng)對(duì)網(wǎng)絡(luò)教學(xué)平臺(tái)中各種格式的教育資源進(jìn)行有針對(duì)性地文本抽取,如對(duì)HTML網(wǎng)頁(yè)、PDF文件、Offiee文檔、Text文件、試題庫(kù)資源等進(jìn)行文本抽取,最終轉(zhuǎn)換成建立索引所需要的固定結(jié)構(gòu),從而支持網(wǎng)絡(luò)教育平臺(tái)中各種資源的全文檢索。另外,為了更好的改善索引的更新策略,系統(tǒng)采用了定時(shí)器啟動(dòng)和手工啟動(dòng)相結(jié)合的方案,使得索引的更新變得更加智能化。
醫(yī)學(xué)知識(shí)搜索系統(tǒng)屬于專業(yè)型數(shù)據(jù)的搜索,因此對(duì)于一般的全文搜索無(wú)法保證搜索結(jié)果的準(zhǔn)確性,因此需要使用特殊的搜索引擎,那就是垂直搜索引擎[9]。Lucene 是一個(gè)支持全文檢索的開(kāi)源工具包,它提供了查詢引擎、索引引擎以及部分語(yǔ)言的分詞器。將搜索引擎應(yīng)用到醫(yī)學(xué)行業(yè),是一個(gè)在 Lucene的基礎(chǔ)上設(shè)計(jì)的專門(mén)針對(duì)醫(yī)學(xué)行業(yè)的專業(yè)模型,并且結(jié)合醫(yī)學(xué)領(lǐng)域特有的需求做了個(gè)性化的排序處理。在Lucene提供的框架的基礎(chǔ)上,可以方便地進(jìn)行二次開(kāi)發(fā),輕易建立完整的桌面或 WEB 全文檢索應(yīng)用。
Lucene是兩千年初的產(chǎn)物,距今已經(jīng)有十多年的歷史了,這些年來(lái),它一直在不斷的更新,其精華不是一朝一夕能研究透的,因此本研究還存在許多遺漏之處。具體表現(xiàn)在:
(1)本文暫時(shí)只能對(duì)txt文檔進(jìn)行搜索時(shí)獲得比較好效果,對(duì)word之類的文檔,由于會(huì)添加許多附加格式,會(huì)有一些不必要的標(biāo)簽,使得創(chuàng)建的索引存在很大的冗余。不過(guò),tika工具已經(jīng)很好的對(duì)各種類型的文檔提取文本內(nèi)容。
(2)由于Lucene的增刪改操作都要進(jìn)行IO操作,因此,若想進(jìn)行及時(shí)搜索,需要對(duì)每一個(gè)剛剛添加的文檔都進(jìn)行索引。盡管本研究在最后對(duì)性能優(yōu)化提出了一些建議,但是,若在頻繁添加文檔的情況下,必將增大服務(wù)器的壓力,降低系統(tǒng)的性能。一個(gè)解決方法就是對(duì)索引的添加進(jìn)行集中操作,在一定時(shí)間或者在服務(wù)器承受壓力較小的某一時(shí)間進(jìn)行添加索引操作。
4.4 在醫(yī)學(xué)知識(shí)搜索系統(tǒng)中的應(yīng)用
(3)本文研究主要以理論為主,加上一些功能實(shí)現(xiàn)代碼,以控制臺(tái)的形式展示測(cè)試結(jié)果,沒(méi)有較好的可視化界面,在某些程度上影響了研究與測(cè)試效率。
[1] Otis Gospodnetic,Erik Hatcher. Lucene In Action中文版(譚鴻,黎俊鴻,周鵬,高承山譯)[M],電子工業(yè)出版社,2007.
[2] 李雪松.中文分詞及其在基于Lucene的全文檢索中的應(yīng)用[D] .廣東:中山大學(xué),2007.
[3] 吳眾欣,沈家立.Lucene分析與應(yīng)用[M].北京:機(jī)械工業(yè)出版社,2008.
[4] 趙汀,孟祥武.基于LUCENE API的中文全文數(shù)據(jù)庫(kù)[D].北京:中國(guó)科學(xué)技術(shù)信息研究所,2002.
[5] 劉興宇.基于倒排索引的全文檢索技術(shù)研究[D].湖北:華中科技大學(xué),2004.
[6] 王麗云,王華,陳剛.基于Lucene的全文檢索系統(tǒng)的設(shè)計(jì)與實(shí)現(xiàn)[J].計(jì)算機(jī)工程與設(shè)計(jì),2007,24(28):5959-5961.
[7] 張蕾.基于Lucene的電子檔案檢索系統(tǒng)的設(shè)計(jì)與實(shí)現(xiàn)[D].陜西:西安電子科技大學(xué),2010.
[8] 陳寧.Lucene全文檢索在網(wǎng)絡(luò)教學(xué)平臺(tái)中的應(yīng)用研究[D].遼寧:大連海事大學(xué),2007.
[9] 張平.基于Lucene的醫(yī)學(xué)知識(shí)搜索系統(tǒng)設(shè)計(jì)與實(shí)現(xiàn)[D].重慶:重慶大學(xué),2008.
Research and Application of Full-text Retrieval Technology for Document Based on Lucene
Guo Yongli, Lu Yingying
(Nanyang Radio and TV University, Nanyang 473000, China)
This paper analyses the principles and application of Lucene, according to the shortage of IndexSearcher, IndexWriter, Directory, it puts forward some methods to optimize them. and forbids WildcardQuery and FuzzyQuery which is inefficient by override the source code of QueryParser to raise the response speed, at last many applications about Lucene are researched in the paper.
Search Engine; Full-text Search; Word Segmentation; Index; Optimize
TP393
A
1007-757X(2014)01-0051-04
2013.12.22)
郭永利(1978-),男,南陽(yáng)電視廣播大學(xué),講師,碩士,研究方向:計(jì)算機(jī)網(wǎng)絡(luò),南陽(yáng),473000盧穎穎(1979-),女,南陽(yáng)電視廣播大學(xué),講師,研究方向:計(jì)算機(jī)網(wǎng)絡(luò),南陽(yáng),473000