日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

lucene,lucene.net学习教程

發(fā)布時間:2023/12/10 编程问答 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 lucene,lucene.net学习教程 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

lucene學(xué)習(xí)教程

?

1.1 什么是lucene

??? Lucene是一個全文搜索框架,而不是應(yīng)用產(chǎn)品。因此它并不像www.baidu.com 或者google Desktop那么拿來就能用,它只是提供了一種工具讓你能實(shí)現(xiàn)這些產(chǎn)品。

?

2 lucene的工作方式?
??? lucene提供的服務(wù)實(shí)際包含兩部分:一入一出。所謂入是寫入,即將你提供的源(本質(zhì)是字符串)寫入索引或者將其從索引中刪除;所謂出是讀出,即向用戶提供全文搜索服務(wù),讓用戶可以通過關(guān)鍵詞定位源。?
2.1寫入流程?
??? 源字符串首先經(jīng)過analyzer處理,包括:分詞,分成一個個單詞;去除stopword(可選)。?
將源中需要的信息加入Document的各個Field中,并把需要索引的Field索引起來,把需要存儲的Field存儲起來。?
??? 將索引寫入存儲器,存儲器可以是內(nèi)存或磁盤。?
2.2讀出流程?
??? 用戶提供搜索關(guān)鍵詞,經(jīng)過analyzer處理。?
對處理后的關(guān)鍵詞搜索索引找出對應(yīng)的Document。?
用戶根據(jù)需要從找到的Document中提取需要的Field。

??????
3 一些需要知道的概念?
3.1 analyzer?
??? Analyzer是分析器,它的作用是把一個字符串按某種規(guī)則劃分成一個個詞語,并去除其中的無效詞語,這里說的無效詞語是指英文中的“of”、“the”,中文中的“的”、“地”等詞語,這些詞語在文章中大量出現(xiàn),但是本身不包含什么關(guān)鍵信息,去掉有利于縮小索引文件、提高效率、提高命中率。?
  分詞的規(guī)則千變?nèi)f化,但目的只有一個:按語義劃分。這點(diǎn)在英文中比較容易實(shí)現(xiàn),因為英文本身就是以單詞為單位的,已經(jīng)用空格分開;而中文則必須以某種方法將連成一片的句子劃分成一個個詞語。具體劃分方法下面再詳細(xì)介紹,這里只需了解分析器的概念即可。?
3.2 document?
  用戶提供的源是一條條記錄,它們可以是文本文件、字符串或者數(shù)據(jù)庫表的一條記錄等等。一條記錄經(jīng)過索引之后,就是以一個Document的形式存儲在索引文件中的。用戶進(jìn)行搜索,也是以Document列表的形式返回。?
3.3 field?
??? 一個Document可以包含多個信息域,例如一篇文章可以包含“標(biāo)題”、“正文”、“最后修改時間”等信息域,這些信息域就是通過Field在Document中存儲的。?
??? Field有兩個屬性可選:存儲和索引。通過存儲屬性你可以控制是否對這個Field進(jìn)行存儲;通過索引屬性你可以控制是否對該Field進(jìn)行索引。這看起來似乎有些廢話,事實(shí)上對這兩個屬性的正確組合很重要,下面舉例說明:還是以剛才的文章為例子,我們需要對標(biāo)題和正文進(jìn)行全文搜索,所以我們要把索引屬性設(shè)置為真,同時我們希望能直接從搜索結(jié)果中提取文章標(biāo)題,所以我們把標(biāo)題域的存儲屬性設(shè)置為真,但是由于正文域太大了,我們?yōu)榱丝s小索引文件大小,將正文域的存儲屬性設(shè)置為假,當(dāng)需要時再直接讀取文件;我們只是希望能從搜索解果中提取最后修改時間,不需要對它進(jìn)行搜索,所以我們把最后修改時間域的存儲屬性設(shè)置為真,索引屬性設(shè)置為假。上面的三個域涵蓋了兩個屬性的三種組合,還有一種全為假的沒有用到,事實(shí)上Field不允許你那么設(shè)置,因為既不存儲又不索引的域是沒有意義的。?
3.4 term?
  term是搜索的最小單位,它表示文檔的一個詞語,term由兩部分組成:它表示的詞語和這個詞語所出現(xiàn)的field。?
3.5 tocken?
??? tocken是term的一次出現(xiàn),它包含trem文本和相應(yīng)的起止偏移,以及一個類型字符串。一句話中可以出現(xiàn)多次相同的詞語,它們都用同一個term表示,但是用不同的tocken,每個tocken標(biāo)記該詞語出現(xiàn)的地方。?
3.6 segment?
??? 添加索引時并不是每個document都馬上添加到同一個索引文件,它們首先被寫入到不同的小文件,然后再合并成一個大索引文件,這里每個小文件都是一個segment。

?

4 lucene的結(jié)構(gòu)?
lucene包括core和sandbox兩部分,其中core是lucene穩(wěn)定的核心部分,sandbox包含了一些附加功能,例如highlighter、各種分析器。?
Lucene core有七個包:analysis,document,index,queryParser,search,store,util。?
4.1 analysis?
Analysis包含一些內(nèi)建的分析器,例如按空白字符分詞的WhitespaceAnalyzer,添加了stopwrod過濾的StopAnalyzer,最常用的StandardAnalyzer。?
4.2 document?
Document包含文檔的數(shù)據(jù)結(jié)構(gòu),例如Document類定義了存儲文檔的數(shù)據(jù)結(jié)構(gòu),Field類定義了Document的一個域。?
4.3 index?
Index包含了索引的讀寫類,例如對索引文件的segment進(jìn)行寫、合并、優(yōu)化的IndexWriter類和對索引進(jìn)行讀取和刪除操作的 IndexReader類,這里要注意的是不要被IndexReader這個名字誤導(dǎo),以為它是索引文件的讀取類,實(shí)際上刪除索引也是由它完成, IndexWriter只關(guān)心如何將索引寫入一個個segment,并將它們合并優(yōu)化;IndexReader則關(guān)注索引文件中各個文檔的組織形式。?
4.4 queryParser?
QueryParser包含了解析查詢語句的類,lucene的查詢語句和sql語句有點(diǎn)類似,有各種保留字,按照一定的語法可以組成各種查詢。 Lucene有很多種Query類,它們都繼承自Query,執(zhí)行各種特殊的查詢,QueryParser的作用就是解析查詢語句,按順序調(diào)用各種 Query類查找出結(jié)果。?
4.5 search?
Search包含了從索引中搜索結(jié)果的各種類,例如剛才說的各種Query類,包括TermQuery、BooleanQuery等就在這個包里。?
4.6 store?
Store包含了索引的存儲類,例如Directory定義了索引文件的存儲結(jié)構(gòu),FSDirectory為存儲在文件中的索引,RAMDirectory為存儲在內(nèi)存中的索引,MmapDirectory為使用內(nèi)存映射的索引。?
4.7 util?
Util包含一些公共工具類,例如時間和字符串之間的轉(zhuǎn)換工具。?

5 如何建索引?
5.1 最簡單的能完成索引的代碼片斷?

Java代碼?
IndexWriter writer = new IndexWriter(“/data/index/”, new StandardAnalyzer(), true);???
Document doc = new Document();???
doc.add(new Field("title", "lucene introduction", Field.Store.YES, Field.Index.TOKENIZED));???
doc.add(new Field("content", "lucene works well", Field.Store.YES, Field.Index.TOKENIZED));???
writer.addDocument(doc);???
writer.optimize();???
writer.close();??

下面我們分析一下這段代碼。?
首先我們創(chuàng)建了一個writer,并指定存放索引的目錄為“/data/index”,使用的分析器為StandardAnalyzer,第三個參數(shù)說明如果已經(jīng)有索引文件在索引目錄下,我們將覆蓋它們。?
然后我們新建一個document。?
我們向document添加一個field,名字是“title”,內(nèi)容是“l(fā)ucene introduction”,對它進(jìn)行存儲并索引。?
再添加一個名字是“content”的field,內(nèi)容是“l(fā)ucene works well”,也是存儲并索引。?
然后我們將這個文檔添加到索引中,如果有多個文檔,可以重復(fù)上面的操作,創(chuàng)建document并添加。?
添加完所有document,我們對索引進(jìn)行優(yōu)化,優(yōu)化主要是將多個segment合并到一個,有利于提高索引速度。?
隨后將writer關(guān)閉,這點(diǎn)很重要。?

對,創(chuàng)建索引就這么簡單!?
當(dāng)然你可能修改上面的代碼獲得更具個性化的服務(wù)。?

5.2 將索引直接寫在內(nèi)存?
你需要首先創(chuàng)建一個RAMDirectory,并將其傳給writer,代碼如下:?

Java代碼?
Directory dir = new RAMDirectory();???
IndexWriter writer = new IndexWriter(dir, new StandardAnalyzer(), true);???
Document doc = new Document();???
doc.add(new Field("title", "lucene introduction", Field.Store.YES, Field.Index.TOKENIZED));???
doc.add(new Field("content", "lucene works well", Field.Store.YES, Field.Index.TOKENIZED));???
writer.addDocument(doc);???
writer.optimize();???
writer.close();??

5.3 索引文本文件?
如果你想把純文本文件索引起來,而不想自己將它們讀入字符串創(chuàng)建field,你可以用下面的代碼創(chuàng)建field:?

Field field = new Field("content", new FileReader(file));?

這里的file就是該文本文件。該構(gòu)造函數(shù)實(shí)際上是讀去文件內(nèi)容,并對其進(jìn)行索引,但不存儲。?

6 如何維護(hù)索引?
索引的維護(hù)操作都是由IndexReader類提供。?

6.1 如何刪除索引?
lucene提供了兩種從索引中刪除document的方法,一種是?

void deleteDocument(int docNum)?

這種方法是根據(jù)document在索引中的編號來刪除,每個document加進(jìn)索引后都會有個唯一編號,所以根據(jù)編號刪除是一種精確刪除,但是這個編號是索引的內(nèi)部結(jié)構(gòu),一般我們不會知道某個文件的編號到底是幾,所以用處不大。另一種是?

void deleteDocuments(Term term)?

這種方法實(shí)際上是首先根據(jù)參數(shù)term執(zhí)行一個搜索操作,然后把搜索到的結(jié)果批量刪除了。我們可以通過這個方法提供一個嚴(yán)格的查詢條件,達(dá)到刪除指定document的目的。?
下面給出一個例子:?

Java代碼?
Directory dir = FSDirectory.getDirectory(PATH, false);???
IndexReader reader = IndexReader.open(dir);???
Term term = new Term(field, key);???
reader.deleteDocuments(term);???
reader.close();??

6.2 如何更新索引?
lucene并沒有提供專門的索引更新方法,我們需要先將相應(yīng)的document刪除,然后再將新的document加入索引。例如:?

Java代碼?
Directory dir = FSDirectory.getDirectory(PATH, false);???
IndexReader reader = IndexReader.open(dir);???
Term term = new Term(“title”, “l(fā)ucene introduction”);???
reader.deleteDocuments(term);???
reader.close();???
??
IndexWriter writer = new IndexWriter(dir, new StandardAnalyzer(), true);???
Document doc = new Document();???
doc.add(new Field("title", "lucene introduction", Field.Store.YES, Field.Index.TOKENIZED));???
doc.add(new Field("content", "lucene is funny", Field.Store.YES, Field.Index.TOKENIZED));???
writer.addDocument(doc);???
writer.optimize();???
writer.close();??

7 如何搜索?
lucene的搜索相當(dāng)強(qiáng)大,它提供了很多輔助查詢類,每個類都繼承自Query類,各自完成一種特殊的查詢,你可以像搭積木一樣將它們?nèi)我饨M合使用,完成一些復(fù)雜操作;另外lucene還提供了Sort類對結(jié)果進(jìn)行排序,提供了Filter類對查詢條件進(jìn)行限制。你或許會不自覺地拿它跟SQL語句進(jìn)行比較:“l(fā)ucene能執(zhí)行and、or、order by、where、like ‘%xx%’操作嗎?”回答是:“當(dāng)然沒問題!”?

7.1 各種各樣的Query?
下面我們看看lucene到底允許我們進(jìn)行哪些查詢操作:?

7.1.1 TermQuery?
首先介紹最基本的查詢,如果你想執(zhí)行一個這樣的查詢:“在content域中包含‘lucene’的document”,那么你可以用TermQuery:?

Term t = new Term("content", " lucene";?
Query query = new TermQuery(t);?

7.1.2 BooleanQuery?
如果你想這么查詢:“在content域中包含java或perl的document”,那么你可以建立兩個TermQuery并把它們用BooleanQuery連接起來:?

Java代碼?
TermQuery termQuery1 = new TermQuery(new Term("content", "java");???
TermQuery termQuery 2 = new TermQuery(new Term("content", "perl");???
BooleanQuery booleanQuery = new BooleanQuery();???
booleanQuery.add(termQuery 1, BooleanClause.Occur.SHOULD);???
booleanQuery.add(termQuery 2, BooleanClause.Occur.SHOULD);??

7.1.3 WildcardQuery?
如果你想對某單詞進(jìn)行通配符查詢,你可以用WildcardQuery,通配符包括’?’匹配一個任意字符和’*’匹配零個或多個任意字符,例如你搜索’use*’,你可能找到’useful’或者’useless’:?

Java代碼?
Query query = new WildcardQuery(new Term("content", "use*");???

7.1.4 PhraseQuery?
你可能對中日關(guān)系比較感興趣,想查找‘中’和‘日’挨得比較近(5個字的距離內(nèi))的文章,超過這個距離的不予考慮,你可以:?

Java代碼?
PhraseQuery query = new PhraseQuery();???
query.setSlop(5);???
query.add(new Term("content ", “中”));???
query.add(new Term(“content”, “日”));??

那么它可能搜到“中日合作……”、“中方和日方……”,但是搜不到“中國某高層領(lǐng)導(dǎo)說日本欠扁”。?

7.1.5 PrefixQuery?
如果你想搜以‘中’開頭的詞語,你可以用PrefixQuery:?

Java代碼?
PrefixQuery query = new PrefixQuery(new Term("content ", "中");??

7.1.6 FuzzyQuery?
FuzzyQuery用來搜索相似的term,使用Levenshtein算法。假設(shè)你想搜索跟‘wuzza’相似的詞語,你可以:?

Java代碼?
Query query = new FuzzyQuery(new Term("content", "wuzza");??
你可能得到‘fuzzy’和‘wuzzy’。?

7.1.7 RangeQuery?
另一個常用的Query是RangeQuery,你也許想搜索時間域從20060101到20060130之間的document,你可以用RangeQuery:?

Java代碼?
RangeQuery query = new RangeQuery(new Term(“time”, “20060101”), new Term(“time”, “20060130”), true);??

最后的true表示用閉合區(qū)間。?

7.2 QueryParser?
看了這么多Query,你可能會問:“不會讓我自己組合各種Query吧,太麻煩了!”當(dāng)然不會,lucene提供了一種類似于SQL語句的查詢語句,我們姑且叫它lucene語句,通過它,你可以把各種查詢一句話搞定,lucene會自動把它們查分成小塊交給相應(yīng)Query執(zhí)行。下面我們對應(yīng)每種Query演示一下:?
TermQuery可以用“field:key”方式,例如“content:lucene”。?
BooleanQuery中‘與’用‘+’,‘或’用‘ ’,例如“content:java contenterl”。?
WildcardQuery仍然用‘?’和‘*’,例如“content:use*”。?
PhraseQuery用‘~’,例如“content:"中日"~5”。?
PrefixQuery用‘*’,例如“中*”。?
FuzzyQuery用‘~’,例如“content: wuzza ~”。?
RangeQuery用‘[]’或‘{}’,前者表示閉區(qū)間,后者表示開區(qū)間,例如“time:[20060101 TO 20060130]”,注意TO區(qū)分大小寫。?
你可以任意組合query string,完成復(fù)雜操作,例如“標(biāo)題或正文包括lucene,并且時間在20060101到20060130之間的文章”可以表示為:“+ (title:lucene content:lucene) +time:[20060101 TO 20060130]”。代碼如下:?

Java代碼?
Directory dir = FSDirectory.getDirectory(PATH, false);???
IndexSearcher is = new IndexSearcher(dir);???
QueryParser parser = new QueryParser("content", new StandardAnalyzer());???
Query query = parser.parse("+(title:lucene content:lucene) +time:[20060101 TO 20060130]";???
Hits hits = is.search(query);???
for (int i = 0; i < hits.length(); i++)???
{???
Document doc = hits.doc(i);???
System.out.println(doc.get("title");???
}???
is.close();??

首先我們創(chuàng)建一個在指定文件目錄上的IndexSearcher。?
然后創(chuàng)建一個使用StandardAnalyzer作為分析器的QueryParser,它默認(rèn)搜索的域是content。?
接著我們用QueryParser來parse查詢字串,生成一個Query。?
然后利用這個Query去查找結(jié)果,結(jié)果以Hits的形式返回。?
這個Hits對象包含一個列表,我們挨個把它的內(nèi)容顯示出來。?

7.3 Filter?
filter的作用就是限制只查詢索引的某個子集,它的作用有點(diǎn)像SQL語句里的where,但又有區(qū)別,它不是正規(guī)查詢的一部分,只是對數(shù)據(jù)源進(jìn)行預(yù)處理,然后交給查詢語句。注意它執(zhí)行的是預(yù)處理,而不是對查詢結(jié)果進(jìn)行過濾,所以使用filter的代價是很大的,它可能會使一次查詢耗時提高一百倍。?
最常用的filter是RangeFilter和QueryFilter。RangeFilter是設(shè)定只搜索指定范圍內(nèi)的索引;QueryFilter是在上次查詢的結(jié)果中搜索。?
Filter的使用非常簡單,你只需創(chuàng)建一個filter實(shí)例,然后把它傳給searcher。繼續(xù)上面的例子,查詢“時間在20060101到20060130之間的文章”除了將限制寫在query string中,你還可以寫在RangeFilter中:?

Java代碼?
Directory dir = FSDirectory.getDirectory(PATH, false);???
IndexSearcher is = new IndexSearcher(dir);???
QueryParser parser = new QueryParser("content", new StandardAnalyzer());???
Query query = parser.parse("title:lucene content:lucene";???
RangeFilter filter = new RangeFilter("time", "20060101", "20060230", true, true);???
Hits hits = is.search(query, filter);???
for (int i = 0; i < hits.length(); i++)???
{???
Document doc = hits.doc(i);???
System.out.println(doc.get("title");???
}???
is.close();??

7.4 Sort?
有時你想要一個排好序的結(jié)果集,就像SQL語句的“order by”,lucene能做到:通過Sort。?
Sort sort = new Sort(“time”); //相當(dāng)于SQL的“order by time”?
Sort sort = new Sort(“time”, true); // 相當(dāng)于SQL的“order by time desc”?
下面是一個完整的例子:?

Java代碼?
Directory dir = FSDirectory.getDirectory(PATH, false);???
IndexSearcher is = new IndexSearcher(dir);???
QueryParser parser = new QueryParser("content", new StandardAnalyzer());???
Query query = parser.parse("title:lucene content:lucene";???
RangeFilter filter = new RangeFilter("time", "20060101", "20060230", true, true);???
Sort sort = new Sort(“time”);???
Hits hits = is.search(query, filter, sort);???
for (int i = 0; i < hits.length(); i++)???
{???
Document doc = hits.doc(i);???
System.out.println(doc.get("title");???
}???
is.close();??

8 分析器?
在前面的概念介紹中我們已經(jīng)知道了分析器的作用,就是把句子按照語義切分成一個個詞語。英文切分已經(jīng)有了很成熟的分析器: StandardAnalyzer,很多情況下StandardAnalyzer是個不錯的選擇。甚至你會發(fā)現(xiàn)StandardAnalyzer也能對中文進(jìn)行分詞。?
但是我們的焦點(diǎn)是中文分詞,StandardAnalyzer能支持中文分詞嗎?實(shí)踐證明是可以的,但是效果并不好,搜索“如果”會把“牛奶不如果汁好喝”也搜索出來,而且索引文件很大。那么我們手頭上還有什么分析器可以使用呢?core里面沒有,我們可以在sandbox里面找到兩個: ChineseAnalyzer和CJKAnalyzer。但是它們同樣都有分詞不準(zhǔn)的問題。相比之下用StandardAnalyzer和 ChineseAnalyzer建立索引時間差不多,索引文件大小也差不多,CJKAnalyzer表現(xiàn)會差些,索引文件大且耗時比較長。?
要解決問題,首先分析一下這三個分析器的分詞方式。StandardAnalyzer和ChineseAnalyzer都是把句子按單個字切分,也就是說 “牛奶不如果汁好喝”會被它們切分成“牛 奶 不 如 果 汁 好 喝”;而CJKAnalyzer則會切分成“牛奶 奶不 不如 如果 果汁 汁好好喝”。這也就解釋了為什么搜索“果汁”都能匹配這個句子。?
以上分詞的缺點(diǎn)至少有兩個:匹配不準(zhǔn)確和索引文件大。我們的目標(biāo)是將上面的句子分解成“牛奶 不如 果汁好喝”。這里的關(guān)鍵就是語義識別,我們?nèi)绾巫R別“牛奶”是一個詞而“奶不”不是詞語?我們很自然會想到基于詞庫的分詞法,也就是我們先得到一個詞庫,里面列舉了大部分詞語,我們把句子按某種方式切分,當(dāng)?shù)玫降脑~語與詞庫中的項匹配時,我們就認(rèn)為這種切分是正確的。這樣切詞的過程就轉(zhuǎn)變成匹配的過程,而匹配的方式最簡單的有正向最大匹配和逆向最大匹配兩種,說白了就是一個從句子開頭向后進(jìn)行匹配,一個從句子末尾向前進(jìn)行匹配。基于詞庫的分詞詞庫非常重要,詞庫的容量直接影響搜索結(jié)果,在相同詞庫的前提下,據(jù)說逆向最大匹配優(yōu)于正向最大匹配。?
當(dāng)然還有別的分詞方法,這本身就是一個學(xué)科,我這里也沒有深入研究。回到具體應(yīng)用,我們的目標(biāo)是能找到成熟的、現(xiàn)成的分詞工具,避免重新發(fā)明車輪。經(jīng)過網(wǎng)上搜索,用的比較多的是中科院的ICTCLAS和一個不開放源碼但是免費(fèi)的JE-Analysis。ICTCLAS有個問題是它是一個動態(tài)鏈接庫, java調(diào)用需要本地方法調(diào)用,不方便也有安全隱患,而且口碑也確實(shí)不大好。JE-Analysis效果還不錯,當(dāng)然也會有分詞不準(zhǔn)的地方,相比比較方便放心。


9 性能優(yōu)化?
一直到這里,我們還是在討論怎么樣使lucene跑起來,完成指定任務(wù)。利用前面說的也確實(shí)能完成大部分功能。但是測試表明lucene的性能并不是很好,在大數(shù)據(jù)量大并發(fā)的條件下甚至?xí)邪敕昼姺祷氐那闆r。另外大數(shù)據(jù)量的數(shù)據(jù)初始化建立索引也是一個十分耗時的過程。那么如何提高lucene的性能呢?下面從優(yōu)化創(chuàng)建索引性能和優(yōu)化搜索性能兩方面介紹。?

9.1 優(yōu)化創(chuàng)建索引性能?
這方面的優(yōu)化途徑比較有限,IndexWriter提供了一些接口可以控制建立索引的操作,另外我們可以先將索引寫入RAMDirectory,再批量寫入FSDirectory,不管怎樣,目的都是盡量少的文件IO,因為創(chuàng)建索引的最大瓶頸在于磁盤IO。另外選擇一個較好的分析器也能提高一些性能。?

9.1.1 通過設(shè)置IndexWriter的參數(shù)優(yōu)化索引建立?
setMaxBufferedDocs(int maxBufferedDocs)?
控制寫入一個新的segment前內(nèi)存中保存的document的數(shù)目,設(shè)置較大的數(shù)目可以加快建索引速度,默認(rèn)為10。?
setMaxMergeDocs(int maxMergeDocs)?
控制一個segment中可以保存的最大document數(shù)目,值較小有利于追加索引的速度,默認(rèn)Integer.MAX_VALUE,無需修改。?
setMergeFactor(int mergeFactor)?
控制多個segment合并的頻率,值較大時建立索引速度較快,默認(rèn)是10,可以在建立索引時設(shè)置為100。?

9.1.2 通過RAMDirectory緩寫提高性能?
我們可以先把索引寫入RAMDirectory,達(dá)到一定數(shù)量時再批量寫進(jìn)FSDirectory,減少磁盤IO次數(shù)。?

Java代碼?
FSDirectory fsDir = FSDirectory.getDirectory("/data/index", true);???
RAMDirectory ramDir = new RAMDirectory();???
IndexWriter fsWriter = new IndexWriter(fsDir, new StandardAnalyzer(), true);???
IndexWriter ramWriter = new IndexWriter(ramDir, new StandardAnalyzer(), true);???
while (there are documents to index)???
{???
... create Document ...???
ramWriter.addDocument(doc);???
if (condition for flushing memory to disk has been met)???
{???
fsWriter.addIndexes(new Directory[] { ramDir });???
ramWriter.close();???
ramWriter = new IndexWriter(ramDir, new StandardAnalyzer(), true);???
}???
}??

9.1.3 選擇較好的分析器?
這個優(yōu)化主要是對磁盤空間的優(yōu)化,可以將索引文件減小將近一半,相同測試數(shù)據(jù)下由600M減少到380M。但是對時間并沒有什么幫助,甚至?xí)枰L時間,因為較好的分析器需要匹配詞庫,會消耗更多cpu,測試數(shù)據(jù)用StandardAnalyzer耗時133分鐘;用MMAnalyzer耗時150分鐘。?

9.2 優(yōu)化搜索性能?
雖然建立索引的操作非常耗時,但是那畢竟只在最初創(chuàng)建時才需要,平時只是少量的維護(hù)操作,更何況這些可以放到一個后臺進(jìn)程處理,并不影響用戶搜索。我們創(chuàng)建索引的目的就是給用戶搜索,所以搜索的性能才是我們最關(guān)心的。下面就來探討一下如何提高搜索性能。?

9.2.1 將索引放入內(nèi)存?
這是一個最直觀的想法,因為內(nèi)存比磁盤快很多。Lucene提供了RAMDirectory可以在內(nèi)存中容納索引:?

Java代碼?
Directory fsDir = FSDirectory.getDirectory(“/data/index/”, false);???
Directory ramDir = new RAMDirectory(fsDir);???
Searcher searcher = new IndexSearcher(ramDir);??

但是實(shí)踐證明RAMDirectory和FSDirectory速度差不多,當(dāng)數(shù)據(jù)量很小時兩者都非常快,當(dāng)數(shù)據(jù)量較大時(索引文件400M)RAMDirectory甚至比FSDirectory還要慢一點(diǎn),這確實(shí)讓人出乎意料。?
而且lucene的搜索非常耗內(nèi)存,即使將400M的索引文件載入內(nèi)存,在運(yùn)行一段時間后都會out of memory,所以個人認(rèn)為載入內(nèi)存的作用并不大。?

9.2.2 優(yōu)化時間范圍限制?
既然載入內(nèi)存并不能提高效率,一定有其它瓶頸,經(jīng)過測試發(fā)現(xiàn)最大的瓶頸居然是時間范圍限制,那么我們可以怎樣使時間范圍限制的代價最小呢??
當(dāng)需要搜索指定時間范圍內(nèi)的結(jié)果時,可以:?
1、用RangeQuery,設(shè)置范圍,但是RangeQuery的實(shí)現(xiàn)實(shí)際上是將時間范圍內(nèi)的時間點(diǎn)展開,組成一個個BooleanClause加入到 BooleanQuery中查詢,因此時間范圍不可能設(shè)置太大,經(jīng)測試,范圍超過一個月就會拋BooleanQuery.TooManyClauses,可以通過設(shè)置 BooleanQuery.setMaxClauseCount(int maxClauseCount)擴(kuò)大,但是擴(kuò)大也是有限的,并且隨著maxClauseCount擴(kuò)大,占用內(nèi)存也擴(kuò)大?
2、用RangeFilter代替RangeQuery,經(jīng)測試速度不會比RangeQuery慢,但是仍然有性能瓶頸,查詢的90%以上時間耗費(fèi)在 RangeFilter,研究其源碼發(fā)現(xiàn)RangeFilter實(shí)際上是首先遍歷所有索引,生成一個BitSet,標(biāo)記每個document,在時間范圍內(nèi)的標(biāo)記為true,不在的標(biāo)記為false,然后將結(jié)果傳遞給Searcher查找,這是十分耗時的。?
3、進(jìn)一步提高性能,這個又有兩個思路:?
a、緩存Filter結(jié)果。既然RangeFilter的執(zhí)行是在搜索之前,那么它的輸入都是一定的,就是IndexReader,而 IndexReader是由Directory決定的,所以可以認(rèn)為RangeFilter的結(jié)果是由范圍的上下限決定的,也就是由具體的 RangeFilter對象決定,所以我們只要以RangeFilter對象為鍵,將filter結(jié)果BitSet緩存起來即可。lucene API已經(jīng)提供了一個CachingWrapperFilter類封裝了Filter及其結(jié)果,所以具體實(shí)施起來我們可以cache CachingWrapperFilter對象,需要注意的是,不要被CachingWrapperFilter的名字及其說明誤導(dǎo), CachingWrapperFilter看起來是有緩存功能,但的緩存是針對同一個filter的,也就是在你用同一個filter過濾不同 IndexReader時,它可以幫你緩存不同IndexReader的結(jié)果,而我們的需求恰恰相反,我們是用不同filter過濾同一個 IndexReader,所以只能把它作為一個封裝類。?
b、降低時間精度。研究Filter的工作原理可以看出,它每次工作都是遍歷整個索引的,所以時間粒度越大,對比越快,搜索時間越短,在不影響功能的情況下,時間精度越低越好,有時甚至犧牲一點(diǎn)精度也值得,當(dāng)然最好的情況是根本不作時間限制。?
下面針對上面的兩個思路演示一下優(yōu)化結(jié)果(都采用800線程隨機(jī)關(guān)鍵詞隨即時間范圍):?
第一組,時間精度為秒:?
方式 直接用RangeFilter 使用cache 不用filter?
平均每個線程耗時 10s 1s 300ms?

第二組,時間精度為天?
方式 直接用RangeFilter 使用cache 不用filter?
平均每個線程耗時 900ms 360ms 300ms?

由以上數(shù)據(jù)可以得出結(jié)論:?
1、 盡量降低時間精度,將精度由秒換成天帶來的性能提高甚至比使用cache還好,最好不使用filter。?
2、 在不能降低時間精度的情況下,使用cache能帶了10倍左右的性能提高。?

9.2.3 使用更好的分析器?
這個跟創(chuàng)建索引優(yōu)化道理差不多,索引文件小了搜索自然會加快。當(dāng)然這個提高也是有限的。較好的分析器相對于最差的分析器對性能的提升在20%以下。?

10 一些經(jīng)驗?
10.1關(guān)鍵詞區(qū)分大小寫?
or AND TO等關(guān)鍵詞是區(qū)分大小寫的,lucene只認(rèn)大寫的,小寫的當(dāng)做普通單詞。?

10.2 讀寫互斥性?
同一時刻只能有一個對索引的寫操作,在寫的同時可以進(jìn)行搜索?

10.3 文件鎖?
在寫索引的過程中強(qiáng)行退出將在tmp目錄留下一個lock文件,使以后的寫操作無法進(jìn)行,可以將其手工刪除?

10.4 時間格式?
lucene只支持一種時間格式y(tǒng)yMMddHHmmss,所以你傳一個yy-MM-dd HH:mm:ss的時間給lucene它是不會當(dāng)作時間來處理的?

10.5 設(shè)置boost?
有些時候在搜索時某個字段的權(quán)重需要大一些,例如你可能認(rèn)為標(biāo)題中出現(xiàn)關(guān)鍵詞的文章比正文中出現(xiàn)關(guān)鍵詞的文章更有價值,你可以把標(biāo)題的boost設(shè)置的更大,那么搜索結(jié)果會優(yōu)先顯示標(biāo)題中出現(xiàn)關(guān)鍵詞的文章(沒有使用排序的前題下)。使用方法:?
Field. setBoost(float boost);默認(rèn)值是1.0,也就是說要增加權(quán)重的需要設(shè)置得比1大。

?

轉(zhuǎn)載聲明:?本文轉(zhuǎn)自 http://www.javaeye.com/topic/210567 (JavaEve博客)

==============================================================================

?

Apache Lucene與Lucene.Net——全文檢索服務(wù)器

?

Lucene并不是一個爬行搜索引擎,也不會自動地索引內(nèi)容。我們得先將要索引的文檔中的文本抽取出來,然后再將其加到Lucene索引中。標(biāo)準(zhǔn)的步驟是先初始化一個Analyzer、打開一個IndexWriter、然后再將文檔一個接一個地加進(jìn)去。

?

十年前,在Windows世界中使用開源項目簡直是不可想象的一件事。現(xiàn)在.NET程序員在Java平臺上驗證并開發(fā)的企業(yè)級軟件世界中也開始覺醒了。今天讓我們一起來看看流行的全文檢索引擎——Apache Lucene與Lucene.Net。

Apache Lucene與其兄弟Lucene.Net是經(jīng)過了大規(guī)模測試的產(chǎn)品,他們已經(jīng)為一些著名站點(diǎn)如Wikipedia、CNET及Monster.com提供了搜索功能。因此,沒人會懷疑其功能與未來的發(fā)展。

Lucene并不是一個爬行搜索引擎,也不會自動地索引內(nèi)容。我們得先將要索引的文檔中的文本抽取出來,然后再將其加到Lucene索引中。標(biāo)準(zhǔn)的步驟是先初始化一個Analyzer、打開一個IndexWriter、然后再將文檔一個接一個地加進(jìn)去。一旦完成這些步驟,索引就可以在關(guān)閉前得到優(yōu)化,同時所做的改變也會生效。這個過程可能比開發(fā)者習(xí)慣的方式更加手工化一些,但卻在數(shù)據(jù)的索引上給予你更多的靈活性。

我們可以借助于一個對象模型來完成搜索,通過查詢來建立條件。其次,Lucene可以解析并執(zhí)行(可能由最終用戶輸入的)普通文本搜索字符串。使用.NET 3.5或后續(xù)版本的.NET開發(fā)者還有第三種選擇:LINQ to Lucene。其項目主頁上有一張圖清晰地描述了Lucene的搜索語法與相應(yīng)的LINQ to Lucene語法的區(qū)別。

如果你想試一下,可以參考Andrew Smith對Lucene.NET的介紹。無論你選擇.NET還是Java版本,看看Erik Hatcher對Lucene的介紹都會大有好處。

查看英文原文:Apache Lucene and Lucene.Net – Full Text Search Servers

?

轉(zhuǎn)載聲明:?本文轉(zhuǎn)自 http://www.infoq.com/cn/news/2008/11/Lucene (Info Q)

==============================================================================

Lucene-2.0學(xué)習(xí)文檔

?

Lucene是apache組織的一個用java實(shí)現(xiàn)全文搜索引擎的開源項目。其功能非常的強(qiáng)大,api也很簡單。總得來說用Lucene來進(jìn)行建立和搜索和操作數(shù)據(jù)庫是差不多的(有點(diǎn)像),Document可以看作是數(shù)據(jù)庫的一行記錄,Field可以看作是數(shù)據(jù)庫的字段。用lucene實(shí)現(xiàn)搜索引擎就像用JDBC實(shí)現(xiàn)連接數(shù)據(jù)庫一樣簡單。

Lucene2.0,它與以前廣泛應(yīng)用和介紹的Lucene 1.4.3并不兼容。

Lucene2.0的下載地址是http://apache.justdn.org/lucene/java/

大家先看一個例子,通過這個例子來對lucene的一個大概的認(rèn)識。

一個Junit測試用例:(為了讓代碼清晰好看,我們將異常都拋出)

a)??? 這是一個建立文件索引的例子

public void testIndexHello() throws IOException
??? {
??????? Date date1 = new Date();????????
??????? //可以說是創(chuàng)建一個新的寫入工具
??????? //第一個參數(shù)是要索引建立在哪個目錄里
??????? //第二個參數(shù)是新建一個文本分析器,這里用的是標(biāo)準(zhǔn)的大家也可以自己寫一個
??????? //第三個參數(shù)如果是true,在建立索引之前先將c://index目錄清空。
??????? IndexWriter writer = new IndexWriter("c://index",new StandardAnalyzer(),true);????????
??????? // 這個是數(shù)據(jù)源的文件夾
??????? File file = new File("c://file");
??????? /* 例子主要是將C://file目錄下的文件的內(nèi)容進(jìn)行建立索引,將文件路徑作為搜索內(nèi)容的附屬. */? ????????????
??????? if(file.isDirectory())
??????? {
??????????? String[] fileList = file.list();


??????????? for (int i = 0; i < fileList.length; i++)
??????????? {
???????????? ? //? 建立一個新的文檔,它可以看作是數(shù)據(jù)庫的一行記錄

??????????????? Document doc = new Document();

??????????????? File f = new File(file,

??????????????????????? fileList[i]);

??????????????? Reader reader = new BufferedReader(new FileReader(f));

??????????????? doc.add(new Field("file",reader));//為doument添加field

??????????????? doc.add(new Field("path",f.getAbsolutePath(),Field.Store.YES,Field.Index.NO));

??????????????? writer.addDocument(doc);
??????????? }
??????? }

??????? writer.close();//這一步是必須的,只有這樣數(shù)據(jù)才會被寫入索引的目錄里

??????? Date date2 = new Date();

??????? System.out.println("用時"+(date2.getTime()-date1.getTime())+"毫秒");

}?

注意:因為建立索引本來就是費(fèi)時,所以說最后輸出的用時會比較長,請不要奇怪。?

b)一個通過索引來全文檢索的例子?

public void HelloSearch() throws IOException, ParseException?

??? {
??????? IndexSearcher indexSearcher = new IndexSearcher("c://index");//和上面的IndexWriter一樣是一個工具

??????? QueryParser queryParser = new QueryParser("file",//這是一個分詞器

??????????????? new StandardAnalyzer());

??????? BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

??????? Query query = queryParser.parse(br.readLine());//這個地方Query是抽象類大家也注意一下,下面會講到的

??????? Hits hits = indexSearcher.search(query);

??????? Document doc = null;

??????? System.out.print("正搜索................");

??????? for (int i = 0; i < hits.length(); i++)
??????? {
??????????? doc = hits.doc(i);

??????????? System.out.println("內(nèi)容是:"+doc.get("file"));//注意這里輸出的是什么

??????????? System.out.println("文件的路徑是:" + doc.get("path"));
??????? }
??? }?

通過上面的兩個例子應(yīng)該可以看出Lucene還是比較簡單的。

運(yùn)行一下上面的兩個例子,大家可能會說怎么doc.get(“file”);返回的是空呢,我們馬上會講到。

?

轉(zhuǎn)載聲明:?本文轉(zhuǎn)自 http://www.360doc.com/content/06/1229/01/16773_311395.shtml (360 doc)

==============================================================================

?

Lucene.Net 基本用法

?

本文僅記錄一些簡單的使用方法,供初學(xué)者參考。
以下例子采用 Lucene.NET 1.9 版本,可取去 Lucene.Net 下載。

1. 基本應(yīng)用
using System;
using System.Collections.Generic;
using System.Text;
using Lucene.Net;
using Lucene.Net.Analysis;
using Lucene.Net.Analysis.Standard;
using Lucene.Net.Documents;
using Lucene.Net.Index;
using Lucene.Net.QueryParsers;
using Lucene.Net.Search;
using Lucene.Net.Store;
using Lucene.Net.Util;

namespace ConsoleApplication1.Lucene
{
? public class LuceneTest
? {
??? private const string FieldName = "name";
??? private const string FieldValue = "value";

??? private Directory directory = new RAMDirectory();
??? private Analyzer analyzer = new StandardAnalyzer();

??? public LuceneTest()
??? {
??? }

??? private void Index()
??? {
????? IndexWriter writer = new IndexWriter(directory, analyzer, true);
????? writer.maxFieldLength = 1000;
??????
????? for (int i = 1; i <= 100; i++)
????? {
??????? Document document = new Document();

??????? document.Add(new Field(FieldName, "name" + i, Field.Store.YES, Field.Index.UN_TOKENIZED));
??????? document.Add(new Field(FieldValue, "Hello, World!", Field.Store.YES, Field.Index.TOKENIZED));

??????? writer.AddDocument(document);
????? }

????? writer.Optimize();
????? writer.Close();
??? }

??? private void Search()
??? {
????? Query query = QueryParser.Parse("name*", FieldName, analyzer);

????? IndexSearcher searcher = new IndexSearcher(directory);

????? Hits hits = searcher.Search(query);
??????
????? Console.WriteLine("符合條件記錄:{0}; 索引庫記錄總數(shù):{1}", hits.Length(), searcher.Reader.NumDocs());
????? for (int i = 0; i < hits.Length(); i++)
????? {
??????? int docId = hits.Id(i);
??????? string name = hits.Doc(i).Get(FieldName);
??????? string value = hits.Doc(i).Get(FieldValue);
??????? float score = hits.Score(i);

??????? Console.WriteLine("{0}: DocId:{1}; Name:{2}; Value:{3}; Score:{4}",?
????????? i + 1, docId, name, value, score);
????? }

????? searcher.Close();
??? }
? }
}

除了 RAMDirectory,還可以使用 FSDirectory。(注意 FSDirectory.GetDirectory 的 create 參數(shù),為 true 時將刪除已有索引庫文件,可以通過 IndexReader.IndexExists() 方法判斷。)

從指定目錄打開已有索引庫。
private Directory directory = FSDirectory.GetDirectory("c:/index", false);

將索引庫載入內(nèi)存,以提高搜索速度。
private Directory directory = new RAMDirectory(FSDirectory.GetDirectory(@"c:/index", false));
//或
//private Directory directory = new RAMDirectory(c:/index");

2. 多字段搜索

使用 MultiFieldQueryParser 可以指定多個搜索字段。
Query query = MultiFieldQueryParser.Parse("name*", new string[] { FieldName, FieldValue }, analyzer);

IndexReader reader = IndexReader.Open(directory);
IndexSearcher searcher = new IndexSearcher(reader);
Hits hits = searcher.Search(query);

3. 多條件搜索

除了使用 QueryParser.Parse 分解復(fù)雜的搜索語法外,還可以通過組合多個 Query 來達(dá)到目的。
Query query1 = new TermQuery(new Term(FieldValue, "name1")); // 詞語搜索
Query query2 = new WildcardQuery(new Term(FieldName, "name*")); // 通配符?
//Query query3 = new PrefixQuery(new Term(FieldName, "name1")); // 字段搜索 Field:Keyword,自動在結(jié)尾添加 *
//Query query4 = new RangeQuery(new Term(FieldNumber, NumberTools.LongToString(11L)), new Term(FieldNumber, NumberTools.LongToString(13L)), true); // 范圍搜索
//Query query5 = new FilteredQuery(query, filter); // 帶過濾條件的搜索
??????
BooleanQuery query = new BooleanQuery();
query.Add(query1, BooleanClause.Occur.MUST);
query.Add(query2, BooleanClause.Occur.MUST);

IndexSearcher searcher = new IndexSearcher(reader);
Hits hits = searcher.Search(query);

4. 設(shè)置權(quán)重

可以給 Document 和 Field 增加權(quán)重(Boost),使其在搜索結(jié)果排名更加靠前。缺省情況下,搜索結(jié)果以 Document.Score 作為排序依據(jù),該數(shù)值越大排名越靠前。Boost 缺省值為 1。
Score = Score * Boost

通過上面的公式,我們就可以設(shè)置不同的權(quán)重來影響排名。

如下面的例子中根據(jù) VIP 級別設(shè)定不同的權(quán)重。
Document document = new Document();
switch (vip)
{
? case VIP.Gold: document.SetBoost(2F); break;
? case VIP.Argentine: document.SetBoost(1.5F); break;
}

只要 Boost 足夠大,那么就可以讓某個命中結(jié)果永遠(yuǎn)排第一位,這就是百度等網(wǎng)站的"收費(fèi)排名"業(yè)務(wù)。明顯有失公平,鄙視一把。??

5. 排序

通過 SortField 的構(gòu)造參數(shù),我們可以設(shè)置排序字段,排序條件,以及倒排。
Sort sort = new Sort(new SortField(FieldName, SortField.DOC, false));

IndexSearcher searcher = new IndexSearcher(reader);
Hits hits = searcher.Search(query, sort);

排序?qū)λ阉魉俣扔绊戇€是很大的,盡可能不要使用多個排序條件。

6. 過濾

使用 Filter 對搜索結(jié)果進(jìn)行過濾,可以獲得更小范圍內(nèi)更精確的結(jié)果。

舉個例子,我們搜索上架時間在 2005-10-1 到 2005-10-30 之間的商品。
對于日期時間,我們需要轉(zhuǎn)換一下才能添加到索引庫,同時還必須是索引字段。
// index
document.Add(FieldDate, DateField.DateToString(date), Field.Store.YES, Field.Index.UN_TOKENIZED);

//...

// search
Filter filter = new DateFilter(FieldDate, DateTime.Parse("2005-10-1"), DateTime.Parse("2005-10-30"));
Hits hits = searcher.Search(query, filter);

除了日期時間,還可以使用整數(shù)。比如搜索價格在 100 ~ 200 之間的商品。
Lucene.Net NumberTools 對于數(shù)字進(jìn)行了補(bǔ)位處理,如果需要使用浮點(diǎn)數(shù)可以自己參考源碼進(jìn)行。
// index
document.Add(new Field(FieldNumber, NumberTools.LongToString((long)price), Field.Store.YES, Field.Index.UN_TOKENIZED));

//...

// search
Filter filter = new RangeFilter(FieldNumber, NumberTools.LongToString(100L), NumberTools.LongToString(200L), true, true);
Hits hits = searcher.Search(query, filter);

使用 Query 作為過濾條件。
QueryFilter filter = new QueryFilter(QueryParser.Parse("name2", FieldValue, analyzer));

我們還可以使用 FilteredQuery 進(jìn)行多條件過濾。
Filter filter = new DateFilter(FieldDate, DateTime.Parse("2005-10-10"), DateTime.Parse("2005-10-15"));
Filter filter2 = new RangeFilter(FieldNumber, NumberTools.LongToString(11L), NumberTools.LongToString(13L), true, true);

Query query = QueryParser.Parse("name*", FieldName, analyzer);
query = new FilteredQuery(query, filter);
query = new FilteredQuery(query, filter2);

IndexSearcher searcher = new IndexSearcher(reader);
Hits hits = searcher.Search(query);

7. 分布搜索

我們可以使用 MultiReader 或 MultiSearcher 搜索多個索引庫。
MultiReader reader = new MultiReader(new IndexReader[] { IndexReader.Open(@"c:/index"), IndexReader.Open(@"//server/index") });
IndexSearcher searcher = new IndexSearcher(reader);
Hits hits = searcher.Search(query);


IndexSearcher searcher1 = new IndexSearcher(reader1);
IndexSearcher searcher2 = new IndexSearcher(reader2);
MultiSearcher searcher = new MultiSearcher(new Searchable[] { searcher1, searcher2 });
Hits hits = searcher.Search(query);

還可以使用 ParallelMultiSearcher 進(jìn)行多線程并行搜索。

8. 合并索引庫

將 directory1 合并到 directory2 中。
Directory directory1 = FSDirectory.GetDirectory("index1", false);
Directory directory2 = FSDirectory.GetDirectory("index2", false);

IndexWriter writer = new IndexWriter(directory2, analyzer, false);
writer.AddIndexes(new Directory[] { directory });
Console.WriteLine(writer.DocCount());
writer.Close();

9. 顯示搜索語法字符串

我們組合了很多種搜索條件,或許想看看與其對等的搜索語法串是什么樣的。
BooleanQuery query = new BooleanQuery();
query.Add(query1, true, false);
query.Add(query2, true, false);
//...

Console.WriteLine("Syntax: {0}", query.ToString());

輸出:
Syntax: +(name:name* value:name*) +number:[0000000000000000b TO 0000000000000000d]

呵呵,就這么簡單。

10. 操作索引庫

刪除 (軟刪除,僅添加了刪除標(biāo)記。調(diào)用 IndexWriter.Optimize() 后真正刪除。)
IndexReader reader = IndexReader.Open(directory);

// 刪除指定序號(DocId)的 Document。
reader.Delete(123);

// 刪除包含指定 Term 的 Document。
reader.Delete(new Term(FieldValue, "Hello"));

// 恢復(fù)軟刪除。
reader.UndeleteAll();

reader.Close();

增量更新 (只需將 create 參數(shù)設(shè)為 false,即可往現(xiàn)有索引庫添加新數(shù)據(jù)。)
Directory directory = FSDirectory.GetDirectory("index", false);
IndexWriter writer = new IndexWriter(directory, analyzer, false);
writer.AddDocument(doc1);
writer.AddDocument(doc2);
writer.Optimize();
writer.Close();

11. 優(yōu)化

批量向 FSDirectory 增加索引時,增大合并因子(mergeFactor )和最小文檔合并數(shù)(minMergeDocs)有助于提高性能,減少索引時間。
IndexWriter writer = new IndexWriter(directory, analyzer, true);

writer.maxFieldLength = 1000; // 字段最大長度
writer.mergeFactor = 1000;
writer.minMergeDocs = 1000;

for (int i = 0; i < 10000; i++)
{
? // Add Documentes...
}

writer.Optimize();
writer.Close();

相關(guān)參數(shù)說明?


轉(zhuǎn)自《深入 Lucene 索引機(jī)制》

利用 Lucene,在創(chuàng)建索引的工程中你可以充分利用機(jī)器的硬件資源來提高索引的效率。當(dāng)你需要索引大量的文件時,你會注意到索引過程的瓶頸是在往磁盤上寫索引文件的過程中。為了解決這個問題, Lucene 在內(nèi)存中持有一塊緩沖區(qū)。但我們?nèi)绾慰刂?Lucene 的緩沖區(qū)呢?幸運(yùn)的是,Lucene 的類 IndexWriter 提供了三個參數(shù)用來調(diào)整緩沖區(qū)的大小以及往磁盤上寫索引文件的頻率。

1.合并因子 (mergeFactor)

這個參數(shù)決定了在 Lucene 的一個索引塊中可以存放多少文檔以及把磁盤上的索引塊合并成一個大的索引塊的頻率。比如,如果合并因子的值是 10,那么當(dāng)內(nèi)存中的文檔數(shù)達(dá)到 10 的時候所有的文檔都必須寫到磁盤上的一個新的索引塊中。并且,如果磁盤上的索引塊的隔數(shù)達(dá)到 10 的話,這 10 個索引塊會被合并成一個新的索引塊。這個參數(shù)的默認(rèn)值是 10,如果需要索引的文檔數(shù)非常多的話這個值將是非常不合適的。對批處理的索引來講,為這個參數(shù)賦一個比較大的值會得到比較好的索引效果。

2.最小合并文檔數(shù) (minMergeDocs)

這個參數(shù)也會影響索引的性能。它決定了內(nèi)存中的文檔數(shù)至少達(dá)到多少才能將它們寫回磁盤。這個參數(shù)的默認(rèn)值是10,如果你有足夠的內(nèi)存,那么將這個值盡量設(shè)的比較大一些將會顯著的提高索引性能。

3.最大合并文檔數(shù) (maxMergeDocs)

這個參數(shù)決定了一個索引塊中的最大的文檔數(shù)。它的默認(rèn)值是 Integer.MAX_VALUE,將這個參數(shù)設(shè)置為比較大的值可以提高索引效率和檢索速度,由于該參數(shù)的默認(rèn)值是整型的最大值,所以我們一般不需要改動這個參數(shù)。


-------------------迷糊中的分割線-----------------------------

Lucene 相關(guān)資源:

1. Lucene 官方網(wǎng)站
2. Apache Lucene
3. Lucene FAQ
4. Lucene.Net
5. Lucene API (Java)
6. DotLucene
7. Luke - Lucene Index Toolbox
8. Nutch
9. LUCENE.COM.CN 中國
10. Compass
11. 實(shí)戰(zhàn) Lucene,第 1 部分: 初識 Lucene
12. 深入 Lucene 索引機(jī)制

?

轉(zhuǎn)載聲明:?本文轉(zhuǎn)自 http://www.rainsts.net/article.asp?id=313 (雨痕)

轉(zhuǎn)載于:https://www.cnblogs.com/skybreak/archive/2013/05/06/3063520.html

創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎勵來咯,堅持創(chuàng)作打卡瓜分現(xiàn)金大獎

總結(jié)

以上是生活随笔為你收集整理的lucene,lucene.net学习教程的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。