IKAnalyzer3.2.8 中文分詞器介紹 2012 年 3 月 2 日 1. IKAnalyzer 簡介 IKAnalyzer 是一個開源基于 JAVA 語言的輕量級的中文分詞第三方工具 包,,從 2006 年推出已經(jīng)經(jīng)歷了三個較為完整的版本,目前最新版本為 3.2.8, 它基于 lucene 為應(yīng)用主體,,但是,,它也支持脫離 lucene,成為一個獨立的面 向 JAVA 的分詞工具,。 2. IKAnalyzer 結(jié)構(gòu)圖 結(jié)構(gòu)圖 3. IKAnalyzer 特性 a. 算法采用“正向迭代最細(xì)粒度切分算法”,, 支持細(xì)粒度和最大詞長兩種分詞 方式,速度最大支持 80W 字/秒(1600KB/秒) ,。 b. 支持多子處理器分析模式:中文,、數(shù)字、字母,,并兼容日文,、韓文。 c. 較小的內(nèi)存占用,,優(yōu)化詞庫占有空間,,用戶可自定義擴展詞庫。 采用歧義分析算法優(yōu)化查詢關(guān)鍵字的搜索排列組 d. 擴展 lucene 的擴展實現(xiàn),, 合,,提高 lucene 檢索命中率。 4. 關(guān)鍵類介紹 org.wltea.analyzer.lucene.IKAnalyzer IK分詞主類,,基于Lucene的Analyzer接口實現(xiàn),。 org.wltea.analyzer.lucene.IKQueryParser IK分詞器提供的Query解析、構(gòu)造工具類,,其中parseMultiField 函數(shù)(所有的重載函數(shù))為關(guān)鍵函數(shù),。 org.wltea.analyzer.IKSegmentation IK 分詞器的核心類,真正分詞的實現(xiàn)類,。 5. IK 分詞算法理解 根據(jù)作者官方說法 IK 分詞器采用“正向迭代最細(xì)粒度切分算法”,, 分析它 的源代碼, 可以看到分詞工具類 IKQueryParser 起至關(guān)重要的作用,, 它對搜索 關(guān)鍵詞采用從最大詞到最小詞層層迭代檢索方式切分,,比如搜索詞:“中華人 民共和國成立了”, 首先到詞庫中檢索該搜索詞中最大分割詞,, 即分割為: “中 華人民共和國”和“成立了”,, 然后對“中華人民共和國”切分為“中華人民”和“人 民共和國”,以此類推,。最后,,“中華人民共和國成立了”切分為:“中華人民 | 中華 | 華人 | 人民 | 人民共和國 | 共和國 | 共和 | 成立 | 立了”,當(dāng)然,, 該切分方式為默認(rèn)的細(xì)粒度切分,,若按最大詞長切分,,結(jié)果為:“中華人民共 和國 | 成立 | 立了”。核心算法代碼如下: boolean accept(Lexeme _lexeme){ /* * 檢查新的lexeme 對當(dāng)前的branch 的可接受類型 * acceptType : REFUSED 不能接受 * acceptType : ACCEPTED 接受 * acceptType : TONEXT 由相鄰分支接受 */ int acceptType = checkAccept(_lexeme); switch(acceptType){ case REFUSED: // REFUSE 情況 return false; case ACCEPTED : if(acceptedBranchs == null){ //當(dāng)前branch沒有子branch,,則添加到當(dāng)前branch下 acceptedBranchs = new ArrayList<TokenBranch>(2); acceptedBranchs.add(new TokenBranch(_lexeme)); }else{ boolean acceptedByChild = false; //當(dāng)前branch擁有子branch,,則優(yōu)先由子branch接納 for(TokenBranch childBranch : acceptedBranchs){ acceptedByChild = childBranch.accept(_lexeme) || acceptedByChild; } //如果所有的子branch不能接納,則由當(dāng)前branch接納 if(!acceptedByChild){ acceptedBranchs.add(new TokenBranch(_lexeme)); } } //設(shè)置branch的最大右邊界 if(_lexeme.getEndPosition() > this.rightBorder){ this.rightBorder = _lexeme.getEndPosition(); } break; case TONEXT : //把lexeme放入當(dāng)前branch的相鄰分支 if(this.nextBranch == null){ //如果還沒有相鄰分支,,則建立一個不交疊的分支 this.nextBranch = new TokenBranch(null); } this.nextBranch.accept(_lexeme); break; } return true; } 從代碼中可以了解到,,作者采用了遞歸算法(代碼中加粗的部分)切分 搜索詞。若詞存在子詞則遞歸該函數(shù),,繼續(xù)切分,。 6. 詞庫的擴展 IK 本身帶有 27W 的詞庫,對于詞庫的擴展目前支持兩種方式,,分別是 配置文件和 API 擴展,,同時提供了對用戶自定義停止詞的擴展支持。針對數(shù) 據(jù)庫存儲字庫,,采用這種方式比較好,。 詞庫擴展: 基于 API 詞庫擴展: 類名:org.wltea.analyzer.dic.Dictionary 函數(shù):public static void loadExtendWords(List<String> extWords) 加載用戶擴展的詞匯列表到IK的主詞典中。 函數(shù):public static void loadExtendStopWords(List<String> extStopWords) 加載用戶擴展的停止詞列表,。 基于配置的詞庫擴展: 基于配置的詞庫擴展: 擴展 IKAnalyzer.cfg.xml 文件可以擴展專有詞庫及停止詞庫,。配置如下: <xml version="1.0" encoding="UTF-8"> <!DOCTYPE properties SYSTEM "http://java./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 的結(jié)合 可以說 IK 與 solr 的結(jié)合非常簡單,只要把 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 默認(rèn)的 Query Parser 生成的 Query 一般是 “短語查詢”,導(dǎo)致只 有很精確的結(jié)果才被搜索出來,。比如默認(rèn)情況下,,庫里有”北京愛皮科技有限公 司”,用戶搜索詞為”愛皮公司”,,solr是不會把結(jié)果顯示出來的,。所以,必須分別 擴展: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,,它們?nèi)齻€ 都是基于 JAVA 語言開發(fā)的,總體上來說沒有誰最好,,各有優(yōu)劣,。 Paoding 開發(fā)者及活躍度:SVN 最后更新時間 2010 年 4 月 29 日,,基本停止維護(hù)更新。 速度:在 PIII 1G 內(nèi)存?zhèn)€人機器上,,1 秒 可準(zhǔn)確分詞 100 萬 漢字 算法和代碼復(fù)雜度:采用基于 不限制個數(shù) 的詞典文件對文章進(jìn)行有效切分,使 能夠?qū)υ~匯分類定義,,7000 行左右 JAVA 代碼,。技術(shù)實現(xiàn)上和 IK 類似。 文檔:無,。 用戶自定義詞庫:支持不限制個數(shù)的用戶自定義詞庫,,自動檢測詞庫的更新。自 帶詞庫 22W 個,。 Lucene 和 solr 的支持:支持 Lucene3.0,,和 solr 的集成需自己寫代碼擴展。 mmseg4j 開發(fā)者及活躍度:SVN 最后更新時間 2011 年 6 月 29 日,。 速度:兩種分詞方法,,Simple 和 Complex,目前 complex 1200kb/s 左右,,simple 1900kb/s 左右,,但內(nèi)存開銷了 50M 左右。 算法和代碼復(fù)雜度:MMSeg 算法,,2500 行左右代碼,。 文檔:MMSeg 算法有英文文檔,原理比較簡單,。 用戶自定義詞庫:自帶搜狗的詞庫,,支持自定義詞庫,不支持自動檢測,。 自帶 詞庫 16W 個,。 Lucene 和 solr 的支持:支持 Lucene2.4、solr1.3 IKAnalyzer 開發(fā)者及活躍度:SVN 最后更新時間 2011 年 4 月 15 日,。 速度:每秒 80W 字,。 算法和代碼復(fù)雜度:正向迭代最細(xì)粒度切分算法,4500 行左右代碼,。 文檔:有一個中文使用手冊,。 用戶自定義詞庫:支持自定義詞庫,不支持自動檢測,。 自帶詞庫 27W 個,。 Lucene 和 solr 的支持:支持 Lucene3.0、solr1.4 綜上所述,,IKAnalyzer 具有一定的優(yōu)勢,。 10. IK 分詞弱點,、缺點 分詞弱點 弱點、 總體來說,,IK 是一個很不錯的中文分詞工具,,但它自身也存在一些缺點,比如: a. 對歧義分詞還需要擴展,、改進(jìn),,比如:”湖北石首” 和 “蔣介石首次訪問”, 如果用戶搜索”石首”會把”蔣介石首次訪問”也顯示出來,。 b. 對英文單詞的搜索還需改進(jìn),,比如:”IKAnalyzer”或”UU 音樂”,如果用戶輸 入搜索關(guān)鍵詞”IKAnaly”或”U”則無法搜索出結(jié)果,。 c. IKAnalyzer.cfg.xml 中關(guān)于詞典的配置,,暫不支持通配符方式,這樣導(dǎo)致如果 有大批詞典配置文件時會很麻煩,。 d. 不支持 solr3.5,、lucene3.5 版本,需等待作者更新,。 對于 a 和 b 應(yīng)該是目前幾大開源中文分詞工具共同存在的問題,。 |
|