什么是全文檢索與全文檢索系統(tǒng)?
全文檢索是指計(jì)算機(jī)索引程序通過(guò)掃描文章中的每一個(gè)詞,對(duì)每一個(gè)詞建立一個(gè)索引,指明該詞在文章中出現(xiàn)的次數(shù)和位置,當(dāng)用戶查詢時(shí),檢索程序就根據(jù)事先建立的索引進(jìn)行查找,并將查找的結(jié)果反饋給用戶的檢索方式。這個(gè)過(guò)程類似于通過(guò)字典中的檢索字表查字的過(guò)程。
全文檢索的方法主要分為按字檢索和按詞檢索兩種。按字檢索是指對(duì)于文章中的每一個(gè)字都建立索引,檢索時(shí)將詞分解為字的組合。對(duì)于各種不同的語(yǔ)言而言,字有不同的含義,比如英文中字與詞實(shí)際上是合一的,而中文中字與詞有很大分別。按詞檢索指對(duì)文章中的詞,即語(yǔ)義單位建立索引,檢索時(shí)按詞檢索,并且可以處理同義項(xiàng)等。
全文檢索系統(tǒng)是按照全文檢索理論建立起來(lái)的用于提供全文檢索服務(wù)的軟件系統(tǒng)。一般來(lái)說(shuō),全文檢索需要具備建立索引和提供查詢的基本功能,此外現(xiàn)代的全文檢索系統(tǒng)還需要具有方便的用戶接口、面向WWW[1]的開(kāi)發(fā)接口、二次應(yīng)用開(kāi)發(fā)接口等等。功能上,全文檢索系統(tǒng)核心具有建立索引、處理查詢返回結(jié)果集、增加索引、優(yōu)化索引結(jié)構(gòu)等等功能,外圍則由各種不同應(yīng)用具有的功能組成。結(jié)構(gòu)上,全文檢索系統(tǒng)核心具有索引引擎、查詢引擎、文本分析引擎、對(duì)外接口等等,加上各種外圍應(yīng)用系統(tǒng)等等共同構(gòu)成了全文檢索系統(tǒng)。
什么是Lucene?
Lucene是apache軟件基金會(huì)jakarta項(xiàng)目組的一個(gè)子項(xiàng)目,是一個(gè)開(kāi)放源代碼的全文檢索引擎工具包,即它不是一個(gè)完整的全文檢索引擎,而是一個(gè)全文檢索引擎的架構(gòu),提供了完整的查詢引擎和索引引擎,部分文本分析引擎(英文與德文兩種西方語(yǔ)言)。Lucene的目的是為軟件開(kāi)發(fā)人員提供一個(gè)簡(jiǎn)單易用的工具包,以方便的在目標(biāo)系統(tǒng)中實(shí)現(xiàn)全文檢索的功能,或者是以此為基礎(chǔ)建立起完整的全文檢索引擎。
Lucene的原作者是Doug Cutting,他是一位資深全文索引/檢索專家,曾經(jīng)是V-Twin搜索引擎的主要開(kāi)發(fā)者,后在Excite擔(dān)任高級(jí)系統(tǒng)架構(gòu)設(shè)計(jì)師,目前從事于一些Internet底層架構(gòu)的研究。早先發(fā)布在作者自己的http://www.lucene.com/,后來(lái)發(fā)布在SourceForge,2001年年底成為apache軟件基金會(huì)jakarta的一個(gè)子項(xiàng)目:http://jakarta.apache.org/lucene/。
Lucene作為一個(gè)全文檢索引擎,其具有如下突出的優(yōu)點(diǎn):
(1)索引文件格式獨(dú)立于應(yīng)用平臺(tái)。Lucene定義了一套以8位字節(jié)為基礎(chǔ)的索引文件格式,使得兼容系統(tǒng)或者不同平臺(tái)的應(yīng)用能夠共享建立的索引文件。
(2)在傳統(tǒng)全文檢索引擎的倒排索引的基礎(chǔ)上,實(shí)現(xiàn)了分塊索引,能夠針對(duì)新的文件建立小文件索引,提升索引速度。然后通過(guò)與原有索引的合并,達(dá)到優(yōu)化的目的。
(3)優(yōu)秀的面向?qū)ο蟮南到y(tǒng)架構(gòu),使得對(duì)于Lucene擴(kuò)展的學(xué)習(xí)難度降低,方便擴(kuò)充新功能。
(4)設(shè)計(jì)了獨(dú)立于語(yǔ)言和文件格式的文本分析接口,索引器通過(guò)接受Token流完成索引文件的創(chuàng)立,用戶擴(kuò)展新的語(yǔ)言和文件格式,只需要實(shí)現(xiàn)文本分析的接口。
(5)已經(jīng)默認(rèn)實(shí)現(xiàn)了一套強(qiáng)大的查詢引擎,用戶無(wú)需自己編寫(xiě)代碼即使系統(tǒng)可獲得強(qiáng)大的查詢能力,Lucene的查詢實(shí)現(xiàn)中默認(rèn)實(shí)現(xiàn)了布爾操作、模糊查詢(Fuzzy Search)、分組查詢等等。
面對(duì)已經(jīng)存在的商業(yè)全文檢索引擎,Lucene也具有相當(dāng)?shù)膬?yōu)勢(shì):
首先,它的開(kāi)發(fā)源代碼發(fā)行方式(遵守Apache Software License),在此基礎(chǔ)上程序員不僅僅可以充分的利用Lucene所提供的強(qiáng)大功能,而且可以深入細(xì)致的學(xué)習(xí)到全文檢索引擎制作技術(shù)和面相對(duì)象編程的實(shí)踐,進(jìn)而在此基礎(chǔ)上根據(jù)應(yīng)用的實(shí)際情況編寫(xiě)出更好的更適合當(dāng)前應(yīng)用的全文檢索引擎。在這一點(diǎn)上,商業(yè)軟件的靈活性遠(yuǎn)遠(yuǎn)不及Lucene。
其次,Lucene秉承了開(kāi)放源代碼一貫的架構(gòu)優(yōu)良的優(yōu)勢(shì),設(shè)計(jì)了一個(gè)合理而極具擴(kuò)充能力的面向?qū)ο蠹軜?gòu),程序員可以在Lucene的基礎(chǔ)上擴(kuò)充各種功能,比如擴(kuò)充中文處理能力,從文本擴(kuò)充到HTML、PDF等等文本格式的處理,編寫(xiě)這些擴(kuò)展的功能不僅僅不復(fù)雜,而且由于Lucene恰當(dāng)合理的對(duì)系統(tǒng)設(shè)備做了程序上的抽象,擴(kuò)展的功能也能輕易的達(dá)到跨平臺(tái)的能力。
最后,轉(zhuǎn)移到apache軟件基金會(huì)后,借助于apache軟件基金會(huì)的網(wǎng)絡(luò)平臺(tái),程序員可以方便的和開(kāi)發(fā)者、其它程序員交流,促成資源的共享,甚至直接獲得已經(jīng)編寫(xiě)完備的擴(kuò)充功能。最后,雖然Lucene使用Java語(yǔ)言寫(xiě)成,但是開(kāi)放源代碼社區(qū)的程序員正在不懈的將之使用各種傳統(tǒng)語(yǔ)言實(shí)現(xiàn)(例如.net framework),在遵守Lucene索引文件格式的基礎(chǔ)上,使得Lucene能夠運(yùn)行在各種各樣的平臺(tái)上,系統(tǒng)管理員可以根據(jù)當(dāng)前的平臺(tái)適合的語(yǔ)言來(lái)合理的選。
索引和搜索的關(guān)系
索引是現(xiàn)代搜索引擎的核心,建立索引的過(guò)程就是把源數(shù)據(jù)處理成非常方便查詢的索引文件的過(guò)程。為什么索引這么重要呢,試想你現(xiàn)在要在大量的文檔中搜索含有某個(gè)關(guān)鍵詞的文檔,那么如果不建立索引的話你就需要把這些文檔順序的讀入內(nèi)存,然后檢查這個(gè)文章中是不是含有要查找的關(guān)鍵詞,這樣的話就會(huì)耗費(fèi)非常多的時(shí)間,想想搜索引擎可是在毫秒級(jí)的時(shí)間內(nèi)查找出要搜索的結(jié)果的。這就是由于建立了索引的原因,你可以把索引想象成這樣一種數(shù)據(jù)結(jié)構(gòu),他能夠使你快速的隨機(jī)訪問(wèn)存儲(chǔ)在索引中的關(guān)鍵詞,進(jìn)而找到該關(guān)鍵詞所關(guān)聯(lián)的文檔。Lucene 采用的是一種稱為反向索引(inverted index)的機(jī)制。反向索引就是說(shuō)我們維護(hù)了一個(gè)詞/短語(yǔ)表,對(duì)于這個(gè)表中的每個(gè)詞/短語(yǔ),都有一個(gè)鏈表描述了有哪些文檔包含了這個(gè)詞/短語(yǔ)。這樣在用戶輸入查詢條件的時(shí)候,就能非常快的得到搜索結(jié)果。我們將在本系列文章的第二部分詳細(xì)介紹 Lucene 的索引機(jī)制,由于 Lucene 提供了簡(jiǎn)單易用的 API,所以即使讀者剛開(kāi)始對(duì)全文本進(jìn)行索引的機(jī)制并不太了解,也可以非常容易的使用 Lucene 對(duì)你的文檔實(shí)現(xiàn)索引。
對(duì)文檔建立好索引后,就可以在這些索引上面進(jìn)行搜索了。搜索引擎首先會(huì)對(duì)搜索的關(guān)鍵詞進(jìn)行解析,然后再在建立好的索引上面進(jìn)行查找,最終返回和用戶輸入的關(guān)鍵詞相關(guān)聯(lián)的文檔。
Lucene 軟件包分析
Package: org.apache.lucene.document
這個(gè)包提供了一些為封裝要索引的文檔所需要的類,比如 Document, Field。這樣,每一個(gè)文檔最終被封裝成了一個(gè) Document 對(duì)象。
Package: org.apache.lucene.analysis
這個(gè)包主要功能是對(duì)文檔進(jìn)行分詞,因?yàn)槲臋n在建立索引之前必須要進(jìn)行分詞,所以這個(gè)包的作用可以看成是為建立索引做準(zhǔn)備工作。
Package: org.apache.lucene.index
這個(gè)包提供了一些類來(lái)協(xié)助創(chuàng)建索引以及對(duì)創(chuàng)建好的索引進(jìn)行更新。這里面有兩個(gè)基礎(chǔ)的類:IndexWriter 和 IndexReader,其中 IndexWriter 是用來(lái)創(chuàng)建索引并添加文檔到索引中的,IndexReader 是用來(lái)刪除索引中的文檔的。
Package: org.apache.lucene.search
這個(gè)包提供了對(duì)在建立好的索引上進(jìn)行搜索所需要的類。比如 IndexSearcher 和 Hits, IndexSearcher 定義了在指定的索引上進(jìn)行搜索的方法,Hits 用來(lái)保存搜索得到的結(jié)果
Lucene包結(jié)構(gòu)功能表 |
包名 | 功能 |
org.apache.lucene.analysis | 語(yǔ)言分析器,主要用于的切詞,支持中文主要是擴(kuò)展此類 |
org.apache.lucene.document | 索引存儲(chǔ)時(shí)的文檔結(jié)構(gòu)管理,類似于關(guān)系型數(shù)據(jù)庫(kù)的表結(jié)構(gòu) |
org.apache.lucene.index | 索引管理,包括索引建立、刪除等 |
org.apache.lucene.queryParser | 查詢分析器,實(shí)現(xiàn)查詢關(guān)鍵詞間的運(yùn)算,如與、或、非等 |
org.apache.lucene.search | 檢索管理,根據(jù)查詢條件,檢索得到結(jié)果 |
org.apache.lucene.store | 數(shù)據(jù)存儲(chǔ)管理,主要包括一些底層的I/O操作 |
org.apache.lucene.util | 一些公用類 |
一個(gè)簡(jiǎn)單的搜索應(yīng)用程序
假設(shè)我們的電腦的目錄中含有很多文本文檔,我們需要查找哪些文檔含有某個(gè)關(guān)鍵詞。為了實(shí)現(xiàn)這種功能,我們首先利用
Lucene 對(duì)這個(gè)目錄中的文檔建立索引,然后在建立好的索引中搜索我們所要查找的文檔。通過(guò)這個(gè)例子讀者會(huì)對(duì)如何利用
Lucene 構(gòu)建自己的搜索應(yīng)用程序有個(gè)比較清楚的認(rèn)識(shí)。
建立索引
為了對(duì)文檔進(jìn)行索引,Lucene 提供了五個(gè)基礎(chǔ)的類,他們分別是 Document, Field, IndexWriter, Analyzer, Directory。下面我們分別介紹一下這五個(gè)類的用途:
Document
Document 是用來(lái)描述文檔的,這里的文檔可以指一個(gè) HTML 頁(yè)面,一封電子郵件,或者是一個(gè)文本文件。一個(gè) Document 對(duì)象由多個(gè) Field 對(duì)象組成的。可以把一個(gè) Document 對(duì)象想象成數(shù)據(jù)庫(kù)中的一個(gè)記錄,而每個(gè) Field 對(duì)象就是記錄的一個(gè)字段。
接口名 | 備注 |
add(Field field) | 添加一個(gè)字段(Field)到Document中 |
String get(String name) | 從文檔中獲得一個(gè)字段對(duì)應(yīng)的文本 |
Field getField(String name) | 由字段名獲得字段值 |
Field[] getFields(String name) | 由字段名獲得字段值的集 |
Field
Field 對(duì)象是用來(lái)描述一個(gè)文檔的某個(gè)屬性的,比如一封電子郵件的標(biāo)題和內(nèi)容可以用兩個(gè) Field 對(duì)象分別描述。
即上文所說(shuō)的“字段”,它是Document的片段section。
Field的構(gòu)造函數(shù):
Field(String name, String string, boolean store, boolean index, boolean token)。
Indexed:如果字段是Indexed的,表示這個(gè)字段是可檢索的。
Stored:如果字段是Stored的,表示這個(gè)字段的值可以從檢索結(jié)果中得到。
Tokenized:如果一個(gè)字段是Tokenized的,表示它是有經(jīng)過(guò)Analyzer轉(zhuǎn)變后成為一個(gè)tokens序列,在這個(gè)轉(zhuǎn)變過(guò)程tokenization中,Analyzer提取出需要進(jìn)行索引的文本,而剔除一些冗余的詞句(例如:a,the,they等,詳見(jiàn)org.apache.lucene.analysis.StopAnalyzer.ENGLISH_STOP_WORDS和org.apache.lucene.analysis.standard.StandardAnalyzer(String[] stopWords)的API)。Token是索引時(shí)候的基本單元,代表一個(gè)被索引的詞,例如一個(gè)英文單詞,或者一個(gè)漢字。因此,所有包含中文的文本都必須是Tokenized的。
Analyzer
在一個(gè)文檔被索引之前,首先需要對(duì)文檔內(nèi)容進(jìn)行分詞處理,這部分工作就是由 Analyzer 來(lái)做的。Analyzer 類是一個(gè)抽象類,它有多個(gè)實(shí)現(xiàn)。針對(duì)不同的語(yǔ)言和應(yīng)用需要選擇適合的 Analyzer。Analyzer 把分詞后的內(nèi)容交給 IndexWriter 來(lái)建立索引。
接口名 | 備注 |
addDocument(Document doc) | 索引添加一個(gè)文檔 |
addIndexes(Directory[] dirs) | 將目錄中已存在索引添加到這個(gè)索引 |
addIndexes(IndexReader[] readers) | 將提供的索引添加到這個(gè)索引 |
optimize() | 合并索引并優(yōu)化 |
close() | 關(guān)閉 |
IndexWriter
IndexWriter 是 Lucene 用來(lái)創(chuàng)建索引的一個(gè)核心的類,他的作用是把一個(gè)個(gè)的 Document 對(duì)象加到索引中來(lái)。
Directory
這個(gè)類代表了 Lucene 的索引的存儲(chǔ)的位置,這是一個(gè)抽象類,它目前有兩個(gè)實(shí)現(xiàn),第一個(gè)是 FSDirectory,它表示一個(gè)存儲(chǔ)在文件系統(tǒng)中的索引的位置。第二個(gè)是 RAMDirectory,它表示一個(gè)存儲(chǔ)在內(nèi)存當(dāng)中的索引的位置。
熟悉了建立索引所需要的這些類后,我們就開(kāi)始對(duì)某個(gè)目錄下面的文本文件建立索引了,給出了對(duì)某個(gè)目錄下的文本文件建立索引的源代碼。
public class TextFileIndexer {
public static void main(String[] args) throws Exception {
// fileDir is the directory that contains the text files to be indexed
File fileDir = new File("C:\\index");
// indexDir is the directory that hosts Lucene's index files
File indexDir = new File("C:\\luceneIndex");
Analyzer luceneAnalyzer = new StandardAnalyzer(Version.LUCENE_30);
IndexWriter indexWriter = new IndexWriter(FSDirectory.open(indexDir), luceneAnalyzer, true, IndexWriter.MaxFieldLength.LIMITED);
File[] textFiles = fileDir.listFiles();
long startTime = new Date().getTime();
// Add documents to the index
for (int i = 0; i < textFiles.length; i++) {
if (textFiles[i].isFile() && textFiles[i].getName().endsWith(".txt")) {
System.out.println("File " + textFiles[i].getCanonicalPath() + " is being indexed");
Reader textReader = new FileReader(textFiles[i]);
Document document = new Document();
document.add(new Field("content", textReader));
document.add(new Field("path", textFiles[i].getPath(), Field.Store.YES, Field.Index.ANALYZED_NO_NORMS));
indexWriter.addDocument(document);
}
}
indexWriter.optimize();
indexWriter.close();
long endTime = new Date().getTime();
System.out.println("It took " + (endTime - startTime) + " milliseconds to create an index for the files in the directory " + fileDir.getPath());
}
}
我們注意到類 IndexWriter 的構(gòu)造函數(shù)需要三個(gè)參數(shù),第一個(gè)參數(shù)指定了所創(chuàng)建的索引要存放的位置,他可以是一個(gè) File 對(duì)象,也可以是一個(gè) FSDirectory 對(duì)象或者 RAMDirectory 對(duì)象。第二個(gè)參數(shù)指定了 Analyzer 類的一個(gè)實(shí)現(xiàn),也就是指定這個(gè)索引是用哪個(gè)分詞器對(duì)文擋內(nèi)容進(jìn)行分詞。第三個(gè)參數(shù)是一個(gè)布爾型的變量,如果為 true 的話就代表創(chuàng)建一個(gè)新的索引,為 false 的話就代表在原來(lái)索引的基礎(chǔ)上進(jìn)行操作。接著程序遍歷了目錄下面的所有文本文檔,并為每一個(gè)文本文檔創(chuàng)建了一個(gè) Document 對(duì)象。然后把文本文檔的兩個(gè)屬性:路徑和內(nèi)容加入到了兩個(gè) Field 對(duì)象中,接著在把這兩個(gè) Field 對(duì)象加入到 Document 對(duì)象中,最后把這個(gè)文檔用 IndexWriter 類的 add 方法加入到索引中去。這樣我們便完成了索引的創(chuàng)建。接下來(lái)我們進(jìn)入在建立好的索引上進(jìn)行搜索的部分。
搜索文檔
Query
這是一個(gè)抽象類,他有多個(gè)實(shí)現(xiàn),比如TermQuery, BooleanQuery, PrefixQuery. 這個(gè)類的目的是把用戶輸入的查詢字符串封裝成Lucene能夠識(shí)別的Query。
Term
Term是搜索的基本單位,一個(gè)Term對(duì)象有兩個(gè)String類型的域組成。生成一個(gè)Term對(duì)象可以有如下一條語(yǔ)句來(lái)完成:Term term = new Term(“fieldName”,”queryWord”); 其中第一個(gè)參數(shù)代表了要在文檔的哪一個(gè)Field上進(jìn)行查找,第二個(gè)參數(shù)代表了要查詢的關(guān)鍵詞。
TermQuery
TermQuery是抽象類Query的一個(gè)子類,它同時(shí)也是Lucene支持的最為基本的一個(gè)查詢類。生成一個(gè)TermQuery對(duì)象由如下語(yǔ)句完成: TermQuery termQuery = new TermQuery(new Term(“fieldName”,”queryWord”)); 它的構(gòu)造函數(shù)只接受一個(gè)參數(shù),那就是一個(gè)Term對(duì)象。
IndexSearcher
IndexSearcher是用來(lái)在建立好的索引上進(jìn)行搜索的。它只能以只讀的方式打開(kāi)一個(gè)索引,所以可以有多個(gè)IndexSearcher的實(shí)例在一個(gè)索引上進(jìn)行操作。
Hits
Hits是用來(lái)保存搜索的結(jié)果的。
介紹完這些搜索所必須的類之后,我們就開(kāi)始在之前所建立的索引上進(jìn)行搜索了,清單2給出了完成搜索功能所需要的代碼。
如何添加一個(gè)文檔到索引文
Document document = new Document();
document.add(new Field("content",textReader));
document.add(new Field("path",textFiles[i].getPath(), Field.Store.YES, Field.Index.ANALYZED_NO_NORMS));
indexWriter.addDocument(document);
//最后不要忘記了關(guān)閉
indexWriter.close(); |
首先第一行創(chuàng)建了類 Document 的一個(gè)實(shí)例,它由一個(gè)或者多個(gè)的域(Field)組成。你可以把這個(gè)類想象成代表了一個(gè)實(shí)際的文檔,比如一個(gè) HTML 頁(yè)面,一個(gè) PDF 文檔,或者一個(gè)文本文件。而類 Document 中的域一般就是實(shí)際文檔的一些屬性。比如對(duì)于一個(gè) HTML 頁(yè)面,它的域可能包括標(biāo)題,內(nèi)容,URL 等。我們可以用不同類型的 Field 來(lái)控制文檔的哪些內(nèi)容應(yīng)該索引,哪些內(nèi)容應(yīng)該存儲(chǔ)。如果想獲取更多的關(guān)于 Lucene 的域的信息,可以參考 Lucene 的幫助文檔。代碼的第二行和第三行為文檔添加了兩個(gè)域,每個(gè)域包含兩個(gè)屬性,分別是域的名字和域的內(nèi)容。在我們的例子中兩個(gè)域的名字分別是"content"和"path"。分別存儲(chǔ)了我們需要索引的文本文件的內(nèi)容和路徑。最后一行把準(zhǔn)備好的文檔添加到了索引當(dāng)中。
從索引中刪除文檔
類IndexReader負(fù)責(zé)從一個(gè)已經(jīng)存在的索引中刪除文檔。
File indexDir = new File("C:\\luceneIndex");
IndexReader ir = IndexReader.open(indexDir);
ir.delete(1);
ir.delete(new Term("path","C:\\file_to_index\lucene.txt"));
ir.close(); |
第二行用靜態(tài)方法 IndexReader.open(indexDir) 初始化了類 IndexReader 的一個(gè)實(shí)例,這個(gè)方法的參數(shù)指定了索引的存儲(chǔ)路徑。類 IndexReader 提供了兩種方法去刪除一個(gè)文檔,如程序中的第三行和第四行所示。第三行利用文檔的編號(hào)來(lái)刪除文檔。每個(gè)文檔都有一個(gè)系統(tǒng)自動(dòng)生成的編號(hào)。第四行刪除了路徑為"C:\\file_to_index\lucene.txt"的文檔。你可以通過(guò)指定文件路徑來(lái)方便的刪除一個(gè)文檔。值得注意的是雖然利用上述代碼刪除文檔使得該文檔不能被檢索到,但是并沒(méi)有物理上刪除該文檔。Lucene 只是通過(guò)一個(gè)后綴名為 .delete 的文件來(lái)標(biāo)記哪些文檔已經(jīng)被刪除。既然沒(méi)有物理上刪除,我們可以方便的把這些標(biāo)記為刪除的文檔恢復(fù)過(guò)來(lái),如清單 3 所示,首先打開(kāi)一個(gè)索引,然后調(diào)用方法 ir.undeleteAll() 來(lái)完成恢復(fù)工作。
恢復(fù)已刪除文檔
File indexDir = new File("C:\\luceneIndex");
IndexReader ir = IndexReader.open(indexDir);
ir.undeleteAll();
ir.close(); |
如何物理上刪除文檔
File indexDir = new File("C:\\luceneIndex");
Analyzer luceneAnalyzer = new StandardAnalyzer();
IndexWriter indexWriter = new IndexWriter(indexDir,luceneAnalyzer,false);
indexWriter.optimize();
indexWriter.close(); |
第三行創(chuàng)建了類 IndexWriter 的一個(gè)實(shí)例,并且打開(kāi)了一個(gè)已經(jīng)存在的索引。第 4 行對(duì)索引進(jìn)行清理,清理過(guò)程中將把所有標(biāo)記為刪除的文檔物理刪除。
提高索引性能
利用 Lucene,在創(chuàng)建索引的工程中你可以充分利用機(jī)器的硬件資源來(lái)提高索引的效率。當(dāng)你需要索引大量的文件時(shí),你會(huì)注意到索引過(guò)程的瓶頸是在往磁盤(pán)上寫(xiě)索引文件的過(guò)程中。為了解決這個(gè)問(wèn)題, Lucene 在內(nèi)存中持有一塊緩沖區(qū)。但我們?nèi)绾慰刂?Lucene 的緩沖區(qū)呢?幸運(yùn)的是,Lucene 的類 IndexWriter 提供了三個(gè)參數(shù)用來(lái)調(diào)整緩沖區(qū)的大小以及往磁盤(pán)上寫(xiě)索引文件的頻率。
1.合并因子(mergeFactor)
這個(gè)參數(shù)決定了在 Lucene 的一個(gè)索引塊中可以存放多少文檔以及把磁盤(pán)上的索引塊合并成一個(gè)大的索引塊的頻率。比如,如果合并因子的值是 10,那么當(dāng)內(nèi)存中的文檔數(shù)達(dá)到 10 的時(shí)候所有的文檔都必須寫(xiě)到磁盤(pán)上的一個(gè)新的索引塊中。并且,如果磁盤(pán)上的索引塊的隔數(shù)達(dá)到 10 的話,這 10 個(gè)索引塊會(huì)被合并成一個(gè)新的索引塊。這個(gè)參數(shù)的默認(rèn)值是 10,如果需要索引的文檔數(shù)非常多的話這個(gè)值將是非常不合適的。對(duì)批處理的索引來(lái)講,為這個(gè)參數(shù)賦一個(gè)比較大的值會(huì)得到比較好的索引效果。
2.最小合并文檔數(shù)
這個(gè)參數(shù)也會(huì)影響索引的性能。它決定了內(nèi)存中的文檔數(shù)至少達(dá)到多少才能將它們寫(xiě)回磁盤(pán)。這個(gè)參數(shù)的默認(rèn)值是10,如果你有足夠的內(nèi)存,那么將這個(gè)值盡量設(shè)的比較大一些將會(huì)顯著的提高索引性能。
3.最大合并文檔數(shù)
這個(gè)參數(shù)決定了一個(gè)索引塊中的最大的文檔數(shù)。它的默認(rèn)值是 Integer.MAX_VALUE,將這個(gè)參數(shù)設(shè)置為比較大的值可以提高索引效率和檢索速度,由于該參數(shù)的默認(rèn)值是整型的最大值,所以我們一般不需要改動(dòng)這個(gè)參數(shù)。
int mergeFactor = 10;
int minMergeDocs = 10;
int maxMergeDocs = Integer.MAX_VALUE;
IndexWriter indexWriter = new IndexWriter(indexDir,luceneAnalyzer,true);
indexWriter.mergeFactor = mergeFactor;
indexWriter.minMergeDocs = minMergeDocs;
indexWriter.maxMergeDocs = maxMergeDocs; |
下面我們來(lái)看一下這三個(gè)參數(shù)取不同的值對(duì)索引時(shí)間的影響,注意參數(shù)值的不同和索引之間的關(guān)系。我們?yōu)檫@個(gè)實(shí)驗(yàn)準(zhǔn)備了 10000 個(gè)測(cè)試文檔。表 1 顯示了測(cè)試結(jié)果。
表1:測(cè)試結(jié)果
通過(guò)表 1,你可以清楚地看到三個(gè)參數(shù)對(duì)索引時(shí)間的影響。在實(shí)踐中,你會(huì)經(jīng)常的改變合并因子和最小合并文檔數(shù)的值來(lái)提高索引性能。只要你有足夠大的內(nèi)存,你可以為合并因子和最小合并文檔數(shù)這兩個(gè)參數(shù)賦盡量大的值以提高索引效率,另外我們一般無(wú)需更改最大合并文檔數(shù)這個(gè)參數(shù)的值,因?yàn)橄到y(tǒng)已經(jīng)默認(rèn)將它設(shè)置成了最大。
版權(quán)所有,轉(zhuǎn)載請(qǐng)注明出處 本文出自:
版權(quán)所有,歡迎轉(zhuǎn)載,轉(zhuǎn)載請(qǐng)注明出處,謝謝
posted on 2012-09-05 12:21
hoojo 閱讀(2180)
評(píng)論(0) 編輯 收藏 所屬分類:
JavaEE 、
JavaSE 、
Others 、
SE FTS