一、分词器作用
-
在创建索引的时候需要用到分词器,在使用字符串搜索的时候也会用到分词器,并且这两个地方要使用同一个分词器,否则可能会搜索不出来结果。
-
分词器(Analyzer)的作用是把一段文本中的词按规则取出所包含的所有词,对应的是Analyzer类,这是一个抽象类(public abstract class org.apache.lucene.analysis.Analyzer),切分词的具体规则是由子类实现的,所以对于不同的语言规则,要有不同的分词器。
二、分词器原理
分词器分为中文分词器和英文分词器:
英文分词器是按照词汇切分,同时做词干提取,也就是将单词末尾的变化还原,使其能搜索出来(例如输入boy,能搜索出boys),另外各种分词器对英文都支持的比较好。
中文分词器有很多实现方式,实现原理基本差不多,都是Analyzer的子类:
- 标准分词器:也叫单字分词,将中文一个字一个字的分词。
- 简单分词器:根据标点符号进行分词。
- 二分法分词器:按照两个字进行分词。
- 停用词分词器:和简单分词器很像,根据被忽略停用的词(比如标点符号)进行分词。
- 空格分词器:根据空格进行分词
- IK中文分词器:分为两种实现,一种是采用智能切分,另一种是最细粒度切分算法。
Lucene自带的分词器对中文分词的效果不是很理想,IKAnalyzer分词器是由他人自定义编写的分析器,最新版本为2012年的版本,支持lucene4.0。后续Lucene版本接口改变使其不能支持,所以要用IK分词器,智能修改其源码,或者降低Lucene版本
三、代码示例
本文代码示例IK分词器为Lucene4.0版本,其余分词器对应Lucene版本为5.3.1
public static void display(String str, Analyzer a) {
TokenStream stream = null ;
try {
stream = a.tokenStream( "renyi", new StringReader(str)) ;
PositionIncrementAttribute pia = stream.addAttribute(PositionIncrementAttribute.class ) ; //保存位置
OffsetAttribute oa = stream.addAttribute(OffsetAttribute.class ) ; //保存辞与词之间偏移量
CharTermAttribute cta = stream.addAttribute(CharTermAttribute.class ) ;//保存响应词汇
TypeAttribute ta = stream.addAttribute(TypeAttribute.class ) ; //保存类型
//在lucene 4 以上 要加入reset 和 end方法
stream.reset() ;
while (stream.incrementToken()) {
System. out.println(pia.getPositionIncrement() + ":[" + cta.toString() + "]:" + oa.startOffset() + "->" + oa.endOffset() + ":" + ta.type());
}
stream.end() ;
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
String str = "我是Lucene 分词器,查看分词情况" ;
Analyzer a = new StandardAnalyzer() ; //标准分词器
Analyzer b = new SimpleAnalyzer() ; //简单分词器
Analyzer c = new StopAnalyzer() ; //停用词分词器
Analyzer d = new WhitespaceAnalyzer() ; //空格分词器
Analyzer f = new CJKAnalyzer();//二分法分词器
display(str,a) ;
System. out.println( "-----------------------------");
display(str,b) ;
System. out.println( "-----------------------------");
display(str,c) ;
System. out.println( "-----------------------------");
display(str,d) ;
System. out.println( "-----------------------------");
display(str,f) ;
System. out.println( "-----------------------------");
}
IK分词器代码示例
public static List<String> getAnalyzedStr(Analyzer analyzer, String content) throws Exception {
TokenStream stream = analyzer.tokenStream(null, new StringReader(content));
CharTermAttribute term = stream.addAttribute(CharTermAttribute.class);
List<String> result = new ArrayList<String>();
while (stream.incrementToken()) {
result.add(term.toString());
}
return result;
}
public static void testAnalyzer(String content) throws Exception {
Analyzer analyzer = new IKAnalyzer(); // 等于new IKAnalyzer(false);
System.out.println("new IKAnalyzer()解析输出:" + getAnalyzedStr(analyzer, content));
analyzer = new IKAnalyzer(true);
System.out.println("new IKAnalyzer(true)解析输出:" + getAnalyzedStr(analyzer, content));
}
public static void main(String[] args) throws Exception {
String content = "我是Lucene 分词器,查看分词情况";
System.out.println("原文:" + content);
testAnalyzer(content);
}
各分词器分词比较
1:[我]:0->1:<IDEOGRAPHIC>
1:[是]:1->2:<IDEOGRAPHIC>
1:[lucene]:2->8:<ALPHANUM>
1:[分]:9->10:<IDEOGRAPHIC>
1:[词]:10->11:<IDEOGRAPHIC>
1:[器]:11->12:<IDEOGRAPHIC>
1:[查]:13->14:<IDEOGRAPHIC>
1:[看]:14->15:<IDEOGRAPHIC>
1:[分]:15->16:<IDEOGRAPHIC>
1:[词]:16->17:<IDEOGRAPHIC>
1:[情]:17->18:<IDEOGRAPHIC>
1:[况]:18->19:<IDEOGRAPHIC>
-----------------------------
1:[我是lucene]:0->8:word
1:[分词器]:9->12:word
1:[查看分词情况]:13->19:word
-----------------------------
1:[我是lucene]:0->8:word
1:[分词器]:9->12:word
1:[查看分词情况]:13->19:word
-----------------------------
1:[我是Lucene]:0->8:word
1:[分词器,查看分词情况]:9->19:word
-----------------------------
1:[我是]:0->2:<DOUBLE>
1:[lucene]:2->8:<ALPHANUM>
1:[分词]:9->11:<DOUBLE>
1:[词器]:10->12:<DOUBLE>
1:[查看]:13->15:<DOUBLE>
1:[看分]:14->16:<DOUBLE>
1:[分词]:15->17:<DOUBLE>
1:[词情]:16->18:<DOUBLE>
1:[情况]:17->19:<DOUBLE>
-----------------------------
原文:我是Lucene 分词器,查看分词情况
new IKAnalyzer()解析输出:[我, 是, lucene, 分词器, 分词, 器, 查看, 分词, 情况]
new IKAnalyzer(true)解析输出:[我, 是, lucene, 分词器, 查看, 分词, 情况]