基于 HanLP 的 ES 中文分词插件
一、分詞插件
1、分詞器概念
在 ES 中,分詞器的作用是從文本中提取出若干詞元(token)來支持索引的存儲和搜索,分詞器(Analyzer)由一個分解器(Tokenizer)、零個或多個詞元過濾器(TokenFilter)組成。
分解器用于將字符串分解成一系列詞元,詞元過濾器的作用是對分詞器提取出來的詞元做進一步處理,比如轉成小寫,增加同義詞等。處理后的結果稱為索引詞(Term),引擎會建立 Term 和原文檔的倒排索引(Inverted Index),這樣就能根據 Term 很快到找到源文檔了。
2、選擇分詞器
目前 ES 分詞插件的選擇性還是很多的,分詞插件的核心就是提供各種分詞器(Analyzer)、分解器(Tokenizer)、詞元過濾器(TokenFilter);根據依賴的核心分詞包(分詞算法)的不同顯現出不同的差異性,除了分詞算法之外,是否支持用戶自定義詞典,是否支持詞典熱更新等其他附加功能也是選擇分詞插件時需要參考的。
下面列出選擇分詞插件需要考慮的因素(僅供參考):
- 分詞準確性:大家都希望分詞結果能夠盡可能準確,與分詞準確性直接相關的就是用戶詞典了,此外才是分詞算法;
- 分詞算法:個人認為無需糾結于分詞算法,大多數分詞包提供的分詞算法都比較類似,選擇時不需要過于糾結;
- 分詞速度:這個與分詞算法直接相關,基于詞典的分詞算法一般比基于模型的分詞算法要快;基于詞典如果考慮詞頻、命名實體識別、詞性標注則會慢一些;
- 啟動速度:當詞典較大時,初始化詞典會比較慢,某些分詞器會對詞典進行緩存,第二次啟動會非常速度;
- 內存占用:與分詞算法、詞典大小、模型大小均有關系,設計精巧的算法對內存占用較小;
- 易用性:分詞器是否開箱即用,是否可以直接使用在線鏈接或者壓縮包進行安裝,是否需要復雜的配置;
- 擴展性:是否支持用戶自定義詞典、是否支持自定義分詞算法、是否支持熱更新等;
- 是否開源:開源的分詞器在遇到問題的時候可以自己進行深度調試,甚至可以進行二次開發;
- 社區活躍度:這個看一下 github 的 star 數或者依賴的分詞包的 star 數和 issue 數目即可判定;
- 更新頻率:是否能夠與最新版的 ES 同步更新。
二、HanLP 簡介
HanLP 是一系列模型與算法組成的 NLP 工具包,具備功能完善、性能高效、架構清晰、語料時新、可自定義的特點,詳情可參考 github 介紹:github.com/hankcs/HanL…。
選擇 HanLP 作為核心的分詞包開發 ES 分詞插件,主要考慮以下因素:
- HanLP 是 Java 分詞包中最為流行的;
- HanLP 提供了多種分詞器,既可以基于詞典也可以基于模型(在一億字的大型綜合語料庫上訓練的分詞模型);
- HanLP 堅持使用明文詞典,這樣可以借助社區的力量對詞典不斷進行完善;
- 完善的開發文檔和代碼樣例,較為活躍的用戶群體;
- 個人參與了部分功能的開發,對代碼結構較為熟悉。
三、開發分詞插件
1、代碼結構
- conf:插件的配置文件、HanLP 的配置文件、Java 安全策略文件;
- scr.main.java.assemby:插件打包(maven-assembly-plugin)配置文件;
- org.elasticsearch.plugin.hanlp.analysis:分詞插件核心構建器;
- org.elasticsearch.plugin.hanlp.conf:管理插件配置、分詞器配置以及 HanLP 配置;
- org.elasticsearch.plugin.hanlp.lucene:HanLP 中文分詞 Lucene 插件,對 Lucune 分詞進行實現;
- scr.main.resources:插件屬性文件所在目錄
2、TokenStream
Analyzer 類是一個抽象類,是所有分詞器的基類,它通過 TokenStream 類將文本轉換為詞匯單元流;TokenStream 有兩種實現 Tokenizer(輸入為 Reader) 和 TokenFilter(輸入為另一個 TokenStream)。
TokenStream 基本使用流程:
綜上,開發 Tokenizer 或者 TokenFilter 時,需要重點關注 reset、incrementToken、end、close 四個方法的實現。
3、開發中的小技巧
獲取插件目錄或文件目錄
//獲取插件根目錄 private static Path getPluginPath() {return env.pluginsFile().resolve("analysis-hanlp"); } //獲取插件目錄下的文件 private static Path getDefDicConfigPath() {return env.pluginsFile().resolve("analysis-hanlp/hanlp.properties").toAbsolutePath(); } 復制代碼插件屬性文件
如果希望插件屬性文件(plugin-descriptor.properties)能夠自動根據 pom.xml 中的屬性進行賦值,則需要將文件防止到 resources 文件夾下。
插件版本兼容性
從實際測試來看:
- ES5.X 及其以上的代碼是完全復用的,也就是說代碼邏輯不需要調整;
- ES5.X 到 ES6.2.X 的插件是可以通用的,其特征是打包的時候需要將插件的文件全部打包到 elasticsearch 文件夾下;
- ES6.3.X 以上的插件是可以通用的,打包的時候插件的文件全部打包到根目錄即可。
也就是說,如果你升級了新版本 ES,對于插件升級,大多數情況只需要修改下 plugin-descriptor.properties 文件中 ES 的版本號即可。
4、安全策略文件
在插件開發中經常會使用到文件讀取、屬性讀取、網絡鏈接等功能,如果不提前注冊安全策略,在調用這些功能的時候會報以下錯誤java.security.AccessControlException: access denied。
官方給出的解決方案就是新建一個 plugin-security.policy 文件,然后在文件中聲明需要的權限信息,最后在打包的時候將文件放置到插件的根目錄,這樣在使用 zip 包進行安裝的時候,ES 會提示用戶插件所需的權限信息,需要用戶確認后插件才能正常安裝。
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @ WARNING: plugin requires additional permissions @ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ * java.io.FilePermission <<ALL FILES>> read,write,delete * java.lang.RuntimePermission createClassLoader * java.lang.RuntimePermission getClassLoader * java.lang.RuntimePermission setContextClassLoader * java.net.SocketPermission * connect,resolve * java.util.PropertyPermission * read,write See http://docs.oracle.com/javase/8/docs/technotes/guides/security/permissions.html for descriptions of what these permissions allow and the associated risks.Continue with installation? [y/N]y -> Installed analysis-hanlp 復制代碼5、安全策略的坑
最開始認為只需要添加了 policy 文件,且打包到正確的位置即可解決插件的權限問題,因為在插件安裝的時候 ES 已經提示了所需權限,但是代碼在實際執行的時候依舊報 AccessControlException 的錯誤。
參考了多個 HanLP 的 ES 分詞插件,都沒有獲得較好的方法,后來考慮到 IK 分詞器遠程加載詞典時,需要網絡連接權限,就去看了下其遠程詞典加載的代碼,最終找到了正確的使用方法。
// 需要特殊權限的代碼 AccessController.doPrivileged((PrivilegedAction<Segment>) () -> {Segment segment;if (config.getAlgorithm().equals("extend")) {segment = new ViterbiSegment();} else {segment = HanLP.newSegment(config.getAlgorithm());}// 在此處顯示調用一下分詞,使得加載詞典、緩存詞典的操作可以正確執行System.out.println( segment.seg("HanLP中文分詞工具包!"));return segment; }); 復制代碼四、插件特色
簡單介紹一下插件的特點:
- 內置多種分詞模式,適合不同場景;
- 內置詞典,無需額外配置即可使用;
- 支持外置詞典,用戶可自定義分詞算法,基于詞典或是模型;
- 支持分詞器級別的自定義詞典,便于用于多租戶場景;
- 支持遠程詞典熱更新(待開發);
- 拼音過濾器、繁簡體過濾器(待開發);
- 基于詞語或單字的 ngram 切分分詞(待開發)。
Github 地址:github.com/AnyListen/e…
Any Code,Code Any!
掃碼關注『AnyCode』,編程路上,一起前行。
總結
以上是生活随笔為你收集整理的基于 HanLP 的 ES 中文分词插件的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【APUE】Chapter17 Adva
- 下一篇: 用rvest包来抓取Google学术搜索