研究了一天终于搞定了在Lucene.net 里添加Analyzer 的方法。首先说明下,要添加中文分词必须继承Analyzer类。
参考网址:http://blog.likeshow.net/article.asp?id=39
仿照别人的一篇文章,写出了这个类。写完后发现,其实这样的东西没什么技术含量,不过对于理解Lucene确实帮助不少。下面我将代码贴出。
首先是:ChineseAnalyzer 类,这个类里面从别人的类中已经有现成的了。上面网址所说的方法有点不对,到了2.0里面,ChineseTokenizer 应该继承 Tokenizer 类,而Tokenizer类的构造函数只能传 TextReader _in 。所以 ChineseAnalyzer 类就保持原有的不变。
代码如下:
public class ChineseAnalyzer : Analyzer
{
public ChineseAnalyzer()
{
}
/// <summary>
/// Creates a TokenStream which tokenizes all the text in the provided Reader.
/// </summary>
/// <returns>A TokenStream build from a ChineseTokenizer filtered with ChineseFilter.</returns>
public override sealed TokenStream TokenStream(String fieldName, TextReader reader)
{
TokenStream result = new ChineseTokenizer(reader);
result = new ChineseFilter(result);
return result;
}
}
从上面可以看出,一个 Analyzer 类必须有 2个类与之对应: ChineseTokenizer , ChineseFilter 。前面一个类是我们需要修改的,也就是用中文分词技术将读进去的 TextReader 变成 一个个的 Token 。 既然不能传2个参数,那么中文分词只能在 ChineseTokenizer 里出现了。
此类代码如下:
public sealed class ChineseTokenizer : Tokenizer
{
private Segment segment; //分词类。
private string[] Wordlist; //切好的词放入此数组中
private string Allstr; //对传入的流转成此string
private int offset = 0; int start = 0; int step = 0; //offset偏移量,start开始位置,step次数
public ChineseTokenizer(TextReader _in)
{
input = _in;
Allstr = input.ReadToEnd(); //把流读到Allstr
segment=new Segment();
segment.InitWordDics();
segment.Separator="|";
Wordlist = segment.SegmentText(Allstr).Split('|'); //把分好的词装入wordlist
}
private Token Flush(string str)
{
if (str.Length > 0)
{
return new Token(str,start, start + str.Length); //返回一个Token 包含词,词在流中的开始位置和结束位置.
}
else
return null;
}
public override Token Next() //重载Next函数,就是返回Token
{
Token token = null;
if (step < Wordlist.Length)
{
start = Allstr.IndexOf(Wordlist[step], offset); //从Allstr里找每个分出来词汇的开始位置
offset = start + 1; //计算偏移量
token = Flush(Wordlist[step]); //返回已分词汇
step = step + 1; //变量+1,移动到wordlist的下一个词汇
}
return token;
}
}
而最后一个类,基本不用改变。
public sealed class ChineseFilter : TokenFilter
{
// Only English now, Chinese to be added later.
public static String[] STOP_WORDS =
{
"and", "are", "as", "at", "be", "but", "by",
"for", "if", "in", "into", "is", "it",
"no", "not", "of", "on", "or", "such",
"that", "the", "their", "then", "there", "these",
"they", "this", "to", "was", "will", "with"
};
private Hashtable stopTable;
public ChineseFilter(TokenStream _in) : base (_in)
{
stopTable = new Hashtable(STOP_WORDS.Length);
for (int i = 0; i < STOP_WORDS.Length; i++)
stopTable[STOP_WORDS[i]] = STOP_WORDS[i];
}
public override Token Next()
{
for (Token token = input.Next(); token != null; token = input.Next())
{
String text = token.TermText();
// why not key off token type here assuming ChineseTokenizer comes first?
if (stopTable[text] == null)
{
switch (Char.GetUnicodeCategory(text[0]))
{
case UnicodeCategory.LowercaseLetter:
case UnicodeCategory.UppercaseLetter:
// English word/token should larger than 1 character.
if (text.Length > 1)
{
return token;
}
break;
case UnicodeCategory.OtherLetter:
// One Chinese character as one Chinese word.
// Chinese word extraction to be added later here.
return token;
}
}
}
return null;
}
}
至此中文分词就完全搞定了。用java版的Luke 可以看到里面出现了中文的分词。又一次证明了Lucene.net 和 Lucene的索引是通用的。
在这里要利用了开源的 分词库: http://www.shootsoft.net/home/show.aspx?id=38&cid=8 感谢作者无私分享,在网上找了好多天,才找到这个开源的分词程序,而且带有分词字典。
至此,终于完成了一个简单的中文全文检索程序了。明天开始测试这个程序的性能。并且换几个其他的分词程序试试看效果。后天利用这个做一个简单的全文检索程序,将我一个5万编程文档的网站实现全文检索。