Lucene.net是一個.net下的全文檢索類庫。配置簡單,功能豐富,比較成熟。我在項目中用Lucene.net有一段時間了,這里我把常用一些功能寫出來,與大家一起分享。
Lucene.net用的是3.0版本,分詞采用盤古分詞。示例程序用VS2010進行編譯。
1 索引
在做索引時,有些參數是需要配置的,下面介紹下常用的參數配置。
1) 數據類型,如整形、時間、字符。
每種類型生成的索引方式都是不同的。比如:字符串需要分詞,整形數據則不需要。生成索引的方式會影響到檢索,如果整形按照字符串的方式生成索引,則比較不容易實現區域檢索:如,ID>1000 and ID<2000。
時間索引比較特殊一些。Lucene.net無法對時間字段進行排序和區域檢索,所以,要把時間字段轉成長整形來實現。時間索引參考如下代碼:
var time = DateTime.Now;
var timeField = new NumericField("Publish", Field.Store.YES, true).SetLongValue(time.Ticks);
2) 是否存儲元數據。
如果進行存儲,Lucene則會把索引數據與元數據同時進行存儲。
好處:取數據比較容易。
壞處:索引比較大,可能會影響檢索的速度
3) 是否進行排序
Lucene.net是支持排序的,包括整形排序、時間排序、字符串排序。
但排序和索引有什么關系呢?
我們知道Lucene.net做索引時,需要把字符串數據進行分詞,便於實現全文檢索。這時,如果一段文字已經分過詞,如:“我的未來不是夢”,分詞后應該是:我-的-未來-不是-夢,這樣,一段文字分成若干個詞進行索引,索引時,詞的順序也發生了變化。其中有一些詞或符號在索引時會被濾掉,所以就無法進行排序了。如果要排序,則不應該進行分詞。做索引時參考如下代碼:
var filed = new Field("title_sort", "我的未來不是夢", Field.Store.NO, Field.Index.NOT_ANALYZED);
如果一個字段,既要實現模糊檢索,又要實現精確匹配或排序,則應該把這個字段做兩份索引,一份分詞,一份不分詞。
2 檢索
1) 字符串檢索
字符檢索時,一般要對關鍵詞進行分詞。
var keywords = ParserKeyWord(keyword);
QueryParser parser = new QueryParser(Lucene.Net.Util.Version.LUCENE_30, item.Column, analyzer);
query = parser.Parse(keywords);
2) 時間、整形檢索
時間和整形都是通過NumericRangeQuery來實現。
NumericRangeQuery<long> query = NumericRangeQuery.NewLongRange("ID", 0, 10000000, true, true);
3) 全詞匹配
如果要實現全詞匹配,在做索引時,該字段就不能進行分詞。
Term t = new Term(item.Column, item.Value.ToString());
query = new TermQuery(t);
4) 多條件檢索
多條件進行檢索可以通過BooleanQuery進行實現,參考如下代碼:
bq.Add(query, Occur.MUST);
bq.Add(query1, Occur.MUST);
這里query可以是任意檢索條件,BooleanQuery只是把條件進行拼接。在多條件的情況下,我們經常會遇到這樣的檢索條件:title =’a’ and (author=’x’ or author =’y’)
遇到這樣的條件時,我們可以使用BooleanQuery進行嵌套。這里我們可以用兩個BooleanQuery實現。
BooleanQuery1用來連接author=’x’和 author =’y’,邏輯運算符為OR
BooleanQuery2用來連接title =’a’和BooleanQuery1,邏輯運算會為And。
5) 多索引檢索
多索引檢索是指同時對多個索引目錄進行檢索。通過MultiSearcher來實現。參考如下代碼:
MultiSearcher multiSearch = new MultiSearcher(allIndexSearch.ToArray());
MultiSearcher初始化時,需要指定多個索引目錄,其它操作與單個索引檢索基本相同。
6) 多索引並行檢索
多索引並行檢索是指同時對多個索引進行並行檢索。當單個索引超過10G大小時,我們可以考慮做多個索引,然后利用並行檢索提高檢索性能。並行檢索通過ParallelMultiSearcher來實現,參考如下代碼:
ParallelMultiSearcher parallelMultiSearch = new ParallelMultiSearcher(allIndexSearch.ToArray());
ParallelMultiSearcher在初始化時,需要指定多個索引目錄,其它操作與單個索引檢索基本相同。
3 排序
Lucene.net支持常見字段的排序。默認按照相關度進行排序。在實現排序之前,一定要做好索引。當對特定字段進行排序時,會嚴重影響檢索的性能,尤其是按字符串進行排序。當數據量比較大時,一定要先做好壓力測試,以便確認lucene.net是否滿足性能要求。
排序是在檢索時,通過SortField來實現的。參考如下代碼:
searcher.Search(query, null, limitCount, new Sort(new SortField("Title", SortField.STRING, true)));
注意SortField.STRING這個參數。這里是字符串,所以用SortField.STRING,如果是整形字段,則參數應該是:SortField.INT。
4 常見問題
1) 時間字段:如果要實現時間字段的排序或區域檢索,一定要把時間字段的值轉成長整形。細節請參考《索引》。
2) 分頁:Lucene.net在檢索時有一個參數:(int n),這個參數是用來取前n條記錄,一般情況下,這個參數n最好不要太大,否則會影響檢索性能。百度即使檢索到1億條記錄,但最多也就顯示760條記錄。我一般都是取1000條記錄,然后在內存中進行分頁。
3) 關於Lucene.net的性能,可以參考:
http://www.cnblogs.com/xingzhang/p/LuceneProject.html
4) 檢索不准:一般情況下檢索不准都與分詞有關。不同的分詞效果會導致檢索與預期的不一致。
5 總結
用Lucene.net有一段時間了,總體感覺很穩定、性能也不錯、功能實現靈活。但Lucene.net畢竟是一個全文索引項目,所以,要完全實現關系型數據庫的功能,如:增、刪、改、查、聯合檢索、分組等,並不容易,而且沒有必要。不要用Lucene.net去代替關系型數據庫,應該把Lucene.net作為關系型數據庫的一個補充。
上面的例子只給出了關鍵代碼或邏輯代碼,下面提供完整的源代碼。