Lucene.Net概述
Lucene.Net是一个C#开发的开源全文索引库,其源码包括"核心"与"外围"两部分。外围部分实现辅助功能,而核心部分包括:
- Lucene.Net.Index 提供索引管理,词组排序。
- Lucene.Net.Search 提供查询相关功能。
- Lucene.Net.Store 支持数据存储管理,主要包括I/O操作。
- Lucene.Net.Util 公共类。
- Lucene.Net.Documents 负责描述索引存储时的文件结构管理。
- Lucene.Net.QueryParsers 提供查询语法。
- Lucene.Net.Analysis 负责分析文本。
全文检索流程如下:

一个简单的全文检索实例:
创建索引:

关键代码形如:

static void createIndex(string title, string content)
{
LN.Analysis.Analyzer analyzer = new LN.Analysis.Standard.StandardAnalyzer();
LN.Index.IndexWriter iw = new LN.Index.IndexWriter("Index", analyzer, false);
LN.Documents.Document document = new LN.Documents.Document();
document.Add(new LN.Documents.Field("title", title, LN.Documents.Field.Store.YES, LN.Documents.Field.Index.TOKENIZED));
document.Add(new LN.Documents.Field("content", content, LN.Documents.Field.Store.YES, LN.Documents.Field.Index.TOKENIZED));
iw.AddDocument(document);
iw.Optimize();
iw.Close();
}

查询:

关键代码形如:

static List<Item> search(string keyWord)
{
List<Item> results = new List<Item>();
LN.Analysis.Analyzer analyzer = new LN.Analysis.Standard.StandardAnalyzer();
LN.Search.IndexSearcher searcher = new LN.Search.IndexSearcher("Index");
LN.QueryParsers.MultiFieldQueryParser parser = new LN.QueryParsers.MultiFieldQueryParser(new string[] { "title", "content" }, analyzer);
LN.Search.Query query = parser.Parse(keyWord);
LN.Search.Hits hits = searcher.Search(query);
for (int i = 0; i < hits.Length(); i++)
{
LN.Documents.Document doc = hits.Doc(i);
results.Add(new Item() { Title = doc.Get("title"), Content = doc.Get("content") });
}
searcher.Close();
return results;
}

二 分词
(一)内置分词器
分词(切词)是实现全文检索的基础,之所以我们能够让机器理解我们的自然语言,是因为有了分词的帮助。分词工作由Analyzer类完成,它负责把文本切成Token序列,Token就是索引中的单词。Lucene.Net在两个地方用到分词:创建文档索引和分析搜索关键字。其过程示意如下:


由此可知,在创建索引和搜索时,必须使用同样的分词器,保证其切出相同的Token才能检索到结果。(Lucene.Net把查询关键字中的单词叫做"Term",Term和Token的文本是一样的,只是某些属性不一样。)
Lucene.Net实现了一些分词器,其对英文支持较好,但是对中文支持欠佳。

针对内置分词器测试结果如下:





关键代码形如:

private static List<string> cutWords(string words, Analyzer analyzer)
{
List<string> results = new List<string>();
TokenStream ts = analyzer.ReusableTokenStream("", new StringReader(words));
Token token;
while ((token = ts.Next()) != null)
{
results.Add(token.TermText());
}
ts.Close();
return results;
}

可见,除了StandardAnalyzer外,其它分词器对中文基本无法处理,需要用户自行解决。
(二)分词过程
分词实际是由以下类型完成:

查看WhitespaceAnalyzer的部分源码如下:

public sealed class WhitespaceAnalyzer:Analyzer
{
public override TokenStream TokenStream(System.String fieldName, System.IO.TextReader reader)
{
return new WhitespaceTokenizer(reader);
}
...
}

由此可见,WhitespaceAnalyzer的工作都是交给WhitespaceTokenizer来完成的,并且没有使用筛选器,这也与之前测试的结果相符。我们可以利用TokenStream的派生类型来实现自定义分词器。 例如修改上述代码来得到一个新的分词器,功能类似WhitespaceAnalyzer,不同的是将大写字母变为小写,其代码形如:

public sealed class NewWhitespaceAnalyzer:Analyzer
{
public override TokenStream TokenStream(System.String fieldName, System.IO.TextReader reader)
{
TokenStream ts = new WhitespaceTokenizer(reader);
return new LowerCaseFilter(ts);
}
...
}

(三)中文分词
显然,用户可以自定义分词器,来实现中文分词。但是,大多数用户不熟悉中文分词算法,同时也没有时间和精力来实现自定义分词,毕竟分词并不是我们系统的核心功能。因此,笔者引用了另一个中文分词组件------盘古分词。测试结果如下:

盘古分词使用步骤如下:
Setp 1:添加相关程序集引用
这里需要添加2个程序集,PanGu.dll(盘古分词的核心组件)和PanGu.Lucene.Analyzer.dll(盘古分词的Lucene组件)。
Step 2:添加中文分词库
Step 3:添加并设置配置文件

Step 4:在Lucene.Net使用盘古分词
PanGu.Lucene.Analyzer.dll中定义了Analyzer的派生类型Lucene.Net.Analysis.PanGu.PanGuAnalyzer,与Tokenizer的派生类Lucene.Net.Analysis.PanGu.PanGuTokenizer,语法与Lucene.Net内置分词器相同。
Step 5:维护分词库
使用DictManage.exe管理和维护词库:

三 索引
(一)索引的存储结构
为了方便索引大量文档,Lucene.Net中的一个索引包括多个子索引,叫做Segment(段)。每个Segment包括多个可搜索的文档,叫做Document;每个Document包括多个Field;每个Field又包括多个Term。综上所述,Lucene.Net的索引文件的逻辑结构如下:

索引文件的物理表示如下:

Lucene.Net把一个文档写入索引时,首先生成这个文档的到排索引,然后再把文档的倒排索引合并到段的倒排索引中。
(二)常用类型
- DirectoryLucene.Net的Directory类型实现索引的存储。常用类型继承树如下:
