IKAnalyzer3.2.8 中文分词器介绍
2012 年 3 月 2 日
1. IKAnalyzer 简介
IKAnalyzer 是一个开源基于 JAVA 语言的轻量级的中文分词第三方工具 包,从 2006 年推出已经经历了三个较为完整的版本,目前最新版本为 3.2.8, 它基于 lucene 为应用主体,但是,它也支持脱离 lucene,成为一个独立的面 向 JAVA 的分词工具。
2. IKAnalyzer 结构图 结构图
3. IKAnalyzer 特性
a. 算法采用“正向迭代最细粒度切分算法”, 支持细粒度和最大词长两种分词 方式,速度最大支持 80W 字/秒(1600KB/秒) 。 b. 支持多子处理器分析模式:中文、数字、字母,并兼容日文、韩文。 c. 较小的内存占用,优化词库占有空间,用户可自定义扩展词库。 采用歧义分析算法优化查询关键字的搜索排列组 d. 扩展 lucene 的扩展实现,
合,提高 lucene 检索命中率。
4. 关键类介绍
org.wltea.analyzer.lucene.IKAnalyzer
IK分词主类,基于Lucene的Analyzer接口实现。
org.wltea.analyzer.lucene.IKQueryParser IK分词器提供的Query解析、构造工具类,其中parseMultiField 函数(所有的重载函数)为关键函数。 org.wltea.analyzer.IKSegmentation IK 分词器的核心类,真正分词的实现类。
5. IK 分词算法理解
根据作者官方说法 IK 分词器采用“正向迭代最细粒度切分算法”, 分析它 的源代码, 可以看到分词工具类 IKQueryParser 起至关重要的作用, 它对搜索 关键词采用从最大词到最小词层层迭代检索方式切分,比如搜索词:“中华人 民共和国成立了”, 首先到词库中检索该搜索词中最大分割词, 即分割为: “中 华人民共和国”和“成立了”, 然后对“中华人民共和国”切分为“中华人民”和“人 民共和国”,以此类推。最后,“中华人民共和国成立了”切分为:“中华人民 | 中华 | 华人 | 人民 | 人民共和国 | 共和国 | 共和 | 成立 | 立了”,当然, 该切分方式为默认的细粒度切分,若按最大词长切分,结果为:“中华人民共 和国 | 成立 | 立了”。核心算法代码如下:
boolean accept(Lexeme _lexeme){
/* * 检查新的lexeme 对当前的branch 的可接受类型 * acceptType : REFUSED 不能接受
* acceptType : ACCEPTED 接受 * acceptType : TONEXT 由相邻分支接受
*/ int acceptType = checkAccept(_lexeme); switch(acceptType){ case REFUSED: // REFUSE 情况 return false;
case ACCEPTED : if(acceptedBranchs == null){ //当前branch没有子branch,则添加到当前branch下 acceptedBranchs = new ArrayList<TokenBranch>(2); acceptedBranchs.add(new TokenBranch(_lexeme)); }else{ boolean acceptedByChild = false; //当前branch拥有子branch,则优先由子branch接纳 for(TokenBranch childBranch : acceptedBranchs){ acceptedByChild = childBranch.accept(_lexeme) || acceptedByChild; } //如果所有的子branch不能接纳,则由当前branch接纳 if(!acceptedByChild){ acceptedBranchs.add(new TokenBranch(_lexeme)); } } //设置branch的最大右边界 if(_lexeme.getEndPosition() > this.rightBorder){ this.rightBorder = _lexeme.getEndPosition(); } break;
case TONEXT : //把lexeme放入当前branch的相邻分支 if(this.nextBranch == null){ //如果还没有相邻分支,则建立一个不交叠的分支 this.nextBranch = new TokenBranch(null); } this.nextBranch.accept(_lexeme); break; }
return true; }
从代码中可以了解到,作者采用了递归算法(代码中加粗的部分)切分 搜索词。若词存在子词则递归该函数,继续切分。
6. 词库的扩展
IK 本身带有 27W 的词库,对于词库的扩展目前支持两种方式,分别是 配置文件和 API 扩展,同时提供了对用户自定义停止词的扩展支持。针对数 据库存储字库,采用这种方式比较好。 词库扩展: 基于 API 词库扩展: 类名:org.wltea.analyzer.dic.Dictionary 函数:public static void loadExtendWords(List<String> extWords) 加载用户扩展的词汇列表到IK的主词典中。 函数:public static void loadExtendStopWords(List<String> extStopWords) 加载用户扩展的停止词列表。 基于配置的词库扩展: 基于配置的词库扩展: 扩展
IKAnalyzer.cfg.xml 文件可以扩展专有词库及停止词库。配置如下:
<xml version="1.0" encoding="UTF-8"> <!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd"> <properties> <comment>IK Analyzer 扩展配置</comment> <!--用户可以在这里配置自己的扩展字典 --> <entry key="ext_dict">/mydict.dic; /com/mycompany/dic/mydict2.dic;</entry> <!--用户可以在这里配置自己的扩展停止词字典--> <entry key="ext_stopwords">/ext_stopword.dic</entry> </properties>
7. 与 solr 的结合
可以说 IK 与 solr 的结合非常简单,只要把 solr 中的 schema.xml 添加如下代 码即可:
<schema name="example" version="1.1">
……
<fieldType name="text" class="solr.TextField"> <analyzer class="org.wltea.analyzer.lucene.IKAnalyzer"/> </fieldType>
……
</schema>
或者是:
<fieldType name="text" class="solr.TextField" > <analyzer type="index"> <tokenizer class="org.wltea.analyzer.solr.IKTokenizerFactory" isMaxWordLength="false"/>
……
</analyzer> <analyzer type="query"> <tokenizer class="org.wltea.analyzer.solr.IKTokenizerFactory" isMaxWordLength="true"/>
……
</analyzer> </fieldType>
其中org.wltea.analyzer.solr.IKTokenizerFactory 继承了solr1.4的 BaseTokenizerFactory类,而org.wltea.analyzer.lucene.IKAnalyzer继承了lucene的 Analyzer类。
8. 在 solr1.4 中使用 IKQueryParser
由于 Solr 默认的 Query Parser 生成的 Query 一般是 “短语查询”,导致只 有很精确的结果才被搜索出来。比如默认情况下,库里有”北京爱皮科技有限公 司”,用户搜索词为”爱皮公司”,solr是不会把结果显示出来的。所以,必须分别 扩展:QParserPlugin、QParser,代码如下: IKQParserPlugin: :
import org.apache.solr.common.params.SolrParams; import org.apache.solr.common.util.NamedList; import org.apache.solr.request.SolrQueryRequest; import org.apache.solr.search.QParser; import org.apache.solr.search.QParserPlugin;
public class IKQParserPlugin extends QParserPlugin { public void init(NamedList args) { } public QParser createParser(String qstr, SolrParams localParams, SolrParams params, SolrQueryRequest req) { return new IKQParser(qstr, localParams, params, req); } }
IKQParser: :
import org.apache.lucene.queryParser.ParseException; import org.apache.lucene.search.Query;
import org.apache.solr.common.params.CommonParams; import org.apache.solr.common.params.SolrParams; import org.apache.solr.request.SolrQueryRequest; import org.apache.solr.search.QParser; import org.wltea.analyzer.lucene.IKQueryParser; class IKQParser extends QParser { String defaultField; public IKQParser(String qstr, SolrParams localParams, SolrParams params, SolrQueryRequest req) { super(qstr, localParams, params, req); } public Query parse() throws ParseException { String qstr = getString(); defaultField = getParam(CommonParams.DF); if (defaultField==null) { defaultField = getReq().getSchema ().getDefaultSearchFieldName(); } Query query = null; query = IKQueryParser.parse(defaultField, qstr); return query; } public String[] getDefaultHighlightFields() { return defaultField == null null : new String[] {defaultField}; }
}
将代码打包放到,solr-home的lib下面,配置solrconfig.xml里面: <queryParser name="ik" class="org.wltea.solr.search.IKQParserPlugin"/>然后在 <requestHandler name="standard" class="solr.SearchHandler" default="true">下 面增加<str name="defType">ik</str>即可。
9. 和其他中文分词器的比较
目前流行的几大开源分词器主要有:paoding、mmseg4j、IKAnalyzer,它们三个 都是基于 JAVA 语言开发的,总体上来说没有谁最好,各有优劣。
Paoding 开发者及活跃度:SVN 最后更新时间 2010 年 4 月 29 日,基本停止维护更新。 速度:在 PIII 1G 内存个人机器上,1 秒 可准确分词 100 万 汉字 算法和代码复杂度:采用基于 不限制个数 的词典文件对文章进行有效切分,使 能够将对词汇分类定义,7000 行左右 JAVA 代码。技术实现上和 IK 类似。 文档:无。 用户自定义词库:支持不限制个数的用户自定义词库,自动检测词库的更新。自 带词库 22W 个。 Lucene 和 solr 的支持:支持 Lucene3.0,和 solr 的集成需自己写代码扩展。 mmseg4j 开发者及活跃度:SVN 最后更新时间 2011 年 6 月 29 日。 速度:两种分词方法,Simple 和 Complex,目前 complex 1200kb/s 左右,simple 1900kb/s 左右,但内存开销了 50M 左右。 算法和代码复杂度:MMSeg 算法,2500 行左右代码。 文档:MMSeg 算法有英文文档,原理比较简单。 用户自定义词库:自带搜狗的词库,支持自定义词库,不支持自动检测。 自带 词库 16W 个。 Lucene 和 solr 的支持:支持 Lucene2.4、solr1.3 IKAnalyzer 开发者及活跃度:SVN 最后更新时间 2011 年 4 月 15 日。 速度:每秒 80W 字。 算法和代码复杂度:正向迭代最细粒度切分算法,4500 行左右代码。 文档:有一个中文使用手册。 用户自定义词库:支持自定义词库,不支持自动检测。 自带词库 27W 个。 Lucene 和 solr 的支持:支持 Lucene3.0、solr1.4 综上所述,IKAnalyzer 具有一定的优势。
10. IK 分词弱点、缺点 分词弱点 弱点、
总体来说,IK 是一个很不错的中文分词工具,但它自身也存在一些缺点,比如: a. 对歧义分词还需要扩展、改进,比如:”湖北石首” 和 “蒋介石首次访问”,
如果用户搜索”石首”会把”蒋介石首次访问”也显示出来。 b. 对英文单词的搜索还需改进,比如:”IKAnalyzer”或”UU 音乐”,如果用户输 入搜索关键词”IKAnaly”或”U”则无法搜索出结果。 c. IKAnalyzer.cfg.xml 中关于词典的配置,暂不支持通配符方式,这样导致如果 有大批词典配置文件时会很麻烦。 d. 不支持 solr3.5、lucene3.5 版本,需等待作者更新。 对于 a 和 b 应该是目前几大开源中文分词工具共同存在的问题。