08-07
18
java lucene 技术 (2)
作者:Java伴侣 日期:2008-07-18
使用Lucene时,选择一个合适的分析器是非常关键的。对分析器的选择没有惟一的标准。待分析的语种是影响分析器选择的因素之一,因为每种语言都有其自 身的特点。影响分析器选择的另一个因素是被分析的文本所属的领域,不同的行业有不同的术语、缩写词和缩略语,我们在分析过程中一定要注意这一点。尽管我们 在选择分析器时考虑了很多因素,但是不存在任何一个分析器能适用于所有情况。有可能所有的Lucene内置分析器都不能满足你的需求,这时就得创建一个自定义分析解决方案。本章我将就Lucene的内置分析器以及网络上流行的开源分析器作出讲解。在开始文字讲解之前,我们先做一个简单的例子,可以使我们从一开始就有更直观的理解。
public class test {
private static final String[] examples = {
"The quick brown fox jumped over the lazy dogs",
"美国民主党总统候选人希拉利是前总统克林顿的夫人"
};
private static final Analyzer[] analyzers = new Analyzer[]{
new WhitespaceAnalyzer(),
new SimpleAnalyzer(),
new StopAnalyzer(),
new StandardAnalyzer(),
new MIK_CAnalyzer(), //需要引入IKAnalyzer.jar
new ChineseAnalyzer(),
new CJKAnalyzer(),
new ThesaurusAnalyzer() //需要引入Thesaurus.jar
};
public static void main(String[] args) throws IOException {
String[] strings = examples;
if (args.length > 0) {
strings = args;
}
for (int i = 0; i < strings.length; i++) {
analyze(strings[i]);
}
}
private static void analyze(String text) throws IOException {
System.out.println("Analyzing \"" + text + "\"");
for (int i = 0; i < analyzers.length; i++) {
Analyzer analyzer = analyzers[i];
String name = analyzer.getClass().getName();
name = name.substring(name.lastIndexOf(".") + 1);
System.out.println(" " + name + ":");
System.out.print(" ");
displayTokens(analyzer, text);
System.out.println("\n");
}
}
public static void displayTokens(Analyzer analyzer,
String text) throws IOException {
Token[] tokens = tokensFromAnalysis(analyzer, text);
for (int i = 0; i < tokens.length; i++) {
Token token = tokens[i];
System.out.print("[" + token.termText() + "] ");
}
}
public static Token[] tokensFromAnalysis(Analyzer analyzer,
String text) throws IOException {
TokenStream stream =
analyzer.tokenStream("contents", new StringReader(text));
ArrayList tokenList = new ArrayList();
while (true) {
Token token = stream.next();
if (token == null) break;
tokenList.add(token);
}
return (Token[]) tokenList.toArray(new Token[0]);
}
}
分析结果如下:
Analyzing "The quick brown fox jumped over the lazy dogs"
WhitespaceAnalyzer:
[The] [quick] [brown] [fox] [jumped] [over] [the] [lazy] [dogs]
SimpleAnalyzer:
[the] [quick] [brown] [fox] [jumped] [over] [the] [lazy] [dogs]
StopAnalyzer:
[quick] [brown] [fox] [jumped] [over] [lazy] [dogs]
StandardAnalyzer:
[quick] [brown] [fox] [jumped] [over] [lazy] [dogs]
MIK_CAnalyzer:
[quick] [brown] [fox] [jumped] [lazy] [dogs]
ChineseAnalyzer:
[quick] [brown] [fox] [jumped] [over] [lazy] [dogs]
CJKAnalyzer:
[quick] [brown] [fox] [jumped] [over] [lazy] [dogs]
ThesaurusAnalyzer:
[the] [quick] [brown] [fox] [jumped] [over] [the] [lazy] [dogs]
Analyzing "美国民主党总统候选人希拉利是前总统克林顿的夫人"
WhitespaceAnalyzer:
[美国民主党总统候选人希拉利是前总统克林顿的夫人]
SimpleAnalyzer:
[美国民主党总统候选人希拉利是前总统克林顿的夫人]
StopAnalyzer:
[美国民主党总统候选人希拉利是前总统克林顿的夫人]
StandardAnalyzer:
[美] [国] [民] [主] [党] [总] [统] [候] [选] [人] [希] [拉] [利] [是] [前] [总] [统] [克] [林] [顿] [的] [夫] [人]
MIK_CAnalyzer:
[美国] [国民] [民主党] [总统] [候选人] [希拉] [利是] [前总统] [克林顿] [夫人]
ChineseAnalyzer:
[美] [国] [民] [主] [党] [总] [统] [候] [选] [人] [希] [拉] [利] [是] [前] [总] [统] [克] [林] [顿] [的] [夫] [人]
CJKAnalyzer:
[美国] [国民] [民主] [主党] [党总] [总统] [统候] [候选] [选人] [人希] [希拉] [拉利] [利是] [是前] [前总] [总统] [统克] [克林] [林顿] [顿的] [的夫] [夫人]
ThesaurusAnalyzer:
[美国] [民主党] [总统] [候选人] [希] [拉] [利] [是] [前总统] [克林顿] [的] [夫人]
以上的程序中,我们使用了8个分析器进行分析,除了IKAnalyzer和ThesaurusAnalyzer不是Lucene内置的分析器外,其他都是。通过分析结果,读者已经可以了解各个分析器的作用了,其中还有一些要点值得我们在此指出:
——WhitespaceAnalyzer不会把指定的单词转换为小写形式,它以空格作为边界,将空格间的内容切分为最小的语汇单元。
——SimpleAnalyzer会保留那些所谓的停用词,但是它会把指定域中的所有单词转换为小写形式,并以非字母字符作为单个语汇单元的边界。
——StopAnalyzer和StandardAnalyzer都删除了单词“the”。
——MIK_CAnalyzer、ChineseAnalyzer、CJKAnalyzer、ThesaurusAnalyzer主要针对的是中文分词。可以发现ThesaurusAnalyzer对中文有更好的分析效果,那么它的作用机制是什么呢?
ThesaurusAnalyzer是笔者通过网络发现的一个公开的分词包,在此,我要向它的作者表达我崇高的敬意。
它的内部包括了一个拥有17万中文的词库,并且通过‘联想流’的方式把词库读进内存后构建一个词语树.树的每个节点包含一个字. 比方 中国 中国人 中华民族 中华人民共和国 几个词,构成的树的结构:
中
国^ 华
人^ 人 民
民 族^
共
和
国^
ThesaurusAnalyzer读取一个字,然后联想,直到联想到不能为止.如果当前可以构成词,便返回一个Token.如果当前不能构成词语,便回溯到最近的可以构成词语的节点,返回.最差的情况就是返回第一个单字.然后从返回结果的下一个字重新开始联想。
从ThesaurusAnalyzer,我们可以发现,一个好的分词分析器要有一个庞大优良的词库以及设计优秀的数据结构。lucene自带的几个分词程序中,ChineseAnalyzer是按字分的,与StandardAnalyzer对中文的分词没有大的区别.CJKAnalyzer是按两字切分的,比较武断,并且会产生垃圾Token,影响索引大小。
笔者MSN:wpkk66@hotmail.com QQ:569634476
http://www.tornado.cn
public class test {
private static final String[] examples = {
"The quick brown fox jumped over the lazy dogs",
"美国民主党总统候选人希拉利是前总统克林顿的夫人"
};
private static final Analyzer[] analyzers = new Analyzer[]{
new WhitespaceAnalyzer(),
new SimpleAnalyzer(),
new StopAnalyzer(),
new StandardAnalyzer(),
new MIK_CAnalyzer(), //需要引入IKAnalyzer.jar
new ChineseAnalyzer(),
new CJKAnalyzer(),
new ThesaurusAnalyzer() //需要引入Thesaurus.jar
};
public static void main(String[] args) throws IOException {
String[] strings = examples;
if (args.length > 0) {
strings = args;
}
for (int i = 0; i < strings.length; i++) {
analyze(strings[i]);
}
}
private static void analyze(String text) throws IOException {
System.out.println("Analyzing \"" + text + "\"");
for (int i = 0; i < analyzers.length; i++) {
Analyzer analyzer = analyzers[i];
String name = analyzer.getClass().getName();
name = name.substring(name.lastIndexOf(".") + 1);
System.out.println(" " + name + ":");
System.out.print(" ");
displayTokens(analyzer, text);
System.out.println("\n");
}
}
public static void displayTokens(Analyzer analyzer,
String text) throws IOException {
Token[] tokens = tokensFromAnalysis(analyzer, text);
for (int i = 0; i < tokens.length; i++) {
Token token = tokens[i];
System.out.print("[" + token.termText() + "] ");
}
}
public static Token[] tokensFromAnalysis(Analyzer analyzer,
String text) throws IOException {
TokenStream stream =
analyzer.tokenStream("contents", new StringReader(text));
ArrayList tokenList = new ArrayList();
while (true) {
Token token = stream.next();
if (token == null) break;
tokenList.add(token);
}
return (Token[]) tokenList.toArray(new Token[0]);
}
}
分析结果如下:
Analyzing "The quick brown fox jumped over the lazy dogs"
WhitespaceAnalyzer:
[The] [quick] [brown] [fox] [jumped] [over] [the] [lazy] [dogs]
SimpleAnalyzer:
[the] [quick] [brown] [fox] [jumped] [over] [the] [lazy] [dogs]
StopAnalyzer:
[quick] [brown] [fox] [jumped] [over] [lazy] [dogs]
StandardAnalyzer:
[quick] [brown] [fox] [jumped] [over] [lazy] [dogs]
MIK_CAnalyzer:
[quick] [brown] [fox] [jumped] [lazy] [dogs]
ChineseAnalyzer:
[quick] [brown] [fox] [jumped] [over] [lazy] [dogs]
CJKAnalyzer:
[quick] [brown] [fox] [jumped] [over] [lazy] [dogs]
ThesaurusAnalyzer:
[the] [quick] [brown] [fox] [jumped] [over] [the] [lazy] [dogs]
Analyzing "美国民主党总统候选人希拉利是前总统克林顿的夫人"
WhitespaceAnalyzer:
[美国民主党总统候选人希拉利是前总统克林顿的夫人]
SimpleAnalyzer:
[美国民主党总统候选人希拉利是前总统克林顿的夫人]
StopAnalyzer:
[美国民主党总统候选人希拉利是前总统克林顿的夫人]
StandardAnalyzer:
[美] [国] [民] [主] [党] [总] [统] [候] [选] [人] [希] [拉] [利] [是] [前] [总] [统] [克] [林] [顿] [的] [夫] [人]
MIK_CAnalyzer:
[美国] [国民] [民主党] [总统] [候选人] [希拉] [利是] [前总统] [克林顿] [夫人]
ChineseAnalyzer:
[美] [国] [民] [主] [党] [总] [统] [候] [选] [人] [希] [拉] [利] [是] [前] [总] [统] [克] [林] [顿] [的] [夫] [人]
CJKAnalyzer:
[美国] [国民] [民主] [主党] [党总] [总统] [统候] [候选] [选人] [人希] [希拉] [拉利] [利是] [是前] [前总] [总统] [统克] [克林] [林顿] [顿的] [的夫] [夫人]
ThesaurusAnalyzer:
[美国] [民主党] [总统] [候选人] [希] [拉] [利] [是] [前总统] [克林顿] [的] [夫人]
以上的程序中,我们使用了8个分析器进行分析,除了IKAnalyzer和ThesaurusAnalyzer不是Lucene内置的分析器外,其他都是。通过分析结果,读者已经可以了解各个分析器的作用了,其中还有一些要点值得我们在此指出:
——WhitespaceAnalyzer不会把指定的单词转换为小写形式,它以空格作为边界,将空格间的内容切分为最小的语汇单元。
——SimpleAnalyzer会保留那些所谓的停用词,但是它会把指定域中的所有单词转换为小写形式,并以非字母字符作为单个语汇单元的边界。
——StopAnalyzer和StandardAnalyzer都删除了单词“the”。
——MIK_CAnalyzer、ChineseAnalyzer、CJKAnalyzer、ThesaurusAnalyzer主要针对的是中文分词。可以发现ThesaurusAnalyzer对中文有更好的分析效果,那么它的作用机制是什么呢?
ThesaurusAnalyzer是笔者通过网络发现的一个公开的分词包,在此,我要向它的作者表达我崇高的敬意。
它的内部包括了一个拥有17万中文的词库,并且通过‘联想流’的方式把词库读进内存后构建一个词语树.树的每个节点包含一个字. 比方 中国 中国人 中华民族 中华人民共和国 几个词,构成的树的结构:
中
国^ 华
人^ 人 民
民 族^
共
和
国^
ThesaurusAnalyzer读取一个字,然后联想,直到联想到不能为止.如果当前可以构成词,便返回一个Token.如果当前不能构成词语,便回溯到最近的可以构成词语的节点,返回.最差的情况就是返回第一个单字.然后从返回结果的下一个字重新开始联想。
从ThesaurusAnalyzer,我们可以发现,一个好的分词分析器要有一个庞大优良的词库以及设计优秀的数据结构。lucene自带的几个分词程序中,ChineseAnalyzer是按字分的,与StandardAnalyzer对中文的分词没有大的区别.CJKAnalyzer是按两字切分的,比较武断,并且会产生垃圾Token,影响索引大小。
笔者MSN:wpkk66@hotmail.com QQ:569634476
http://www.tornado.cn
评论: 0 | 引用: 0 | 查看次数: 502
发表评论