前言
前面的案例使用standard、english分詞器,是英文原生的分詞器,對中文分詞支持不太好。中文做爲全球最優美、最複雜的語言,目前中文分詞器較多,ik-analyzer、結巴中文分詞、THULAC、NLPIR和阿里的aliws都是很是優秀的,咱們以ik-analyzer做爲講解的重點,其它分詞器能夠觸類旁通。java
概要
本篇主要介紹中文分詞器ik-analyzer的安裝使用、自定義詞庫以及熱更新方案。node
分詞器插件安裝
咱們Elasticsearch 6.3.1版本爲例,集成IK分詞器,其餘的分詞器過程也相似,在ES的bin目錄下執行插件安裝命令便可:
./elasticsearch-plugin install https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v6.3.1/elasticsearch-analysis-ik-6.3.1.zipmysql
其中install後面的那個的地址是 elasticsearch-analysis-ik 的github release對應ES版本的下載地址。git
插件的版本最好與Elasticsearch版本保持一致,若是Elasticsearch爲別的版本,下載對應版本的ik-analyzer插件便可。github
安裝成功後,ES啓動日誌就能看到以下信息:
[2019-11-27T12:17:15,255][INFO ][o.e.p.PluginsService] [node-1] loaded plugin [analysis-ik]web
IK分詞器
基礎知識
IK分詞器包含兩種analyzer,通常用ik_max_word
ik_max_word:會將文本作最細粒度的拆分
ik_smart:會作最粗粒度的拆分sql
測試分詞效果數據庫
GET /_analyze
{
"text": "您好祖國",
"analyzer": "ik_smart"
}服務器
{
"tokens": [
{
"token": "您好",
"start_offset": 0,
"end_offset": 2,
"type": "CN_WORD",
"position": 0
},
{
"token": "祖國",
"start_offset": 2,
"end_offset": 4,
"type": "CN_WORD",
"position": 1
}
]
}微信
GET /_analyze
{
"text": "我和個人祖國",
"analyzer": "ik_max_word"
}
{
"tokens": [
{
"token": "我",
"start_offset": 0,
"end_offset": 1,
"type": "CN_CHAR",
"position": 0
},
{
"token": "和我",
"start_offset": 1,
"end_offset": 3,
"type": "CN_WORD",
"position": 1
},
{
"token": "的",
"start_offset": 3,
"end_offset": 4,
"type": "CN_CHAR",
"position": 2
},
{
"token": "祖國",
"start_offset": 4,
"end_offset": 6,
"type": "CN_WORD",
"position": 3
}
]
}
配置文件
ik插件安裝完成後,能夠在elasticsearch-6.3.1/config/analysis-ik看到ik的配置文件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"></entry>
<!--用戶能夠在這裏配置本身的擴展中止詞字典-->
<entry key="ext_stopwords"></entry>
<!--用戶能夠在這裏配置遠程擴展字典 -->
<!-- <entry key="remote_ext_dict">words_location</entry> -->
<!--用戶能夠在這裏配置遠程擴展中止詞字典-->
<!-- <entry key="remote_ext_stopwords">words_location</entry> -->
</properties>
該目錄下帶有許多文件,含義以下:
main.dic ik 原生內置的中文詞庫,裏面有275909條現成的詞語
quantifier.dic 量詞和單位名稱,如個,斤,克,米之類的
suffix.dic 常見後綴詞,如江,村,省,市,局等
surname.dic 中國姓氏
stopword.dic 停用詞,目前默認的是寫的幾個英文單詞,如and, a, the等
preposition.dic 副詞、語氣助詞,鏈接詞等無實際含義的詞語,如卻,也,是,不然之類的
6.3.1版本的IK分詞器還提供了額外的詞庫補充文件,extra開頭的那幾個就是,如extra_main.dic,共收錄398716條現有的詞語,默認沒有使用,有須要能夠在配置文件IKAnalyzer.cfg.xml上添加,其餘相似。
最重要的是main.dic和stopword.dic。stopword(停用詞),分詞時會直接被幹掉,不會創建在倒排索引中。
自定義詞庫
建立自定義詞庫文件mydic.dic,並在IKAnalyzer.cfg.xml的ext_dict屬性里加上該文件名,能夠在mydic.dic文件裏補充本身的詞彙,如網絡流行詞:跪族籃孩。
添加前的分詞效果:
GET /forum/_analyze
{
"text": "跪族籃孩",
"analyzer": "ik_max_word"
}
響應結果:
{
"tokens": [
{
"token": "跪",
"start_offset": 0,
"end_offset": 1,
"type": "CN_WORD",
"position": 0
},
{
"token": "族",
"start_offset": 1,
"end_offset": 2,
"type": "CN_CHAR",
"position": 1
},
{
"token": "籃",
"start_offset": 2,
"end_offset": 3,
"type": "CN_WORD",
"position": 2
},
{
"token": "孩",
"start_offset": 3,
"end_offset": 4,
"type": "CN_CHAR",
"position": 3
}
]
}
添加詞庫後:
{
"tokens": [
{
"token": "跪族籃孩",
"start_offset": 0,
"end_offset": 4,
"type": "CN_WORD",
"position": 0
},
{
"token": "跪",
"start_offset": 0,
"end_offset": 1,
"type": "CN_WORD",
"position": 1
},
{
"token": "族",
"start_offset": 1,
"end_offset": 2,
"type": "CN_CHAR",
"position": 2
},
{
"token": "籃",
"start_offset": 2,
"end_offset": 3,
"type": "CN_WORD",
"position": 3
},
{
"token": "孩",
"start_offset": 3,
"end_offset": 4,
"type": "CN_CHAR",
"position": 4
}
]
}
能看到完整的「跪族籃孩」,能看到完整的語詞出現。
2)本身創建停用詞庫,如了,的,哈,啥,這幾個字不想去創建索引
在配置文件IKAnalyzer.cfg.xml下ext_stopwords標籤添加:extra_stopword.dic,並加幾個詞,修改後一樣要重啓es。
例:加一個"啥"字在ext_stopword中
修改前:
GET /forum/_analyze
{
"text": "啥都好",
"analyzer": "ik_max_word"
}
響應結果:
{
"tokens": [
{
"token": "啥",
"start_offset": 0,
"end_offset": 1,
"type": "CN_WORD",
"position": 0
},
{
"token": "都好",
"start_offset": 1,
"end_offset": 3,
"type": "CN_WORD",
"position": 1
}
]
}
添加停用詞後
{
"tokens": [
{
"token": "都好",
"start_offset": 1,
"end_offset": 3,
"type": "CN_WORD",
"position": 0
}
]
}
那個啥字直接沒有了,結果符合預期。
熱更新方案
上面自定義詞庫有一個致命問題:必需要重啓ES,新增的詞庫才能生效。
研發、測試環境本身玩玩無所謂,多半是本身使用,節點又少,重啓就重啓,關係不大。但想一想生產環境能隨便讓你重啓嗎?動輒幾百個ES實例,重啓的事就別想了,另外找辦法。
由此引出如今的熱更新需求,讓ES不停機能當即加載新增的詞庫。
熱更新的方案
基於id分詞器原生支持的更新方案,部署一個web服務器,提供一個http接口,經過modified和try兩個http響應頭,來提供詞語的熱更新操做。
修改ik分詞器源碼,而後手動支持從mysql中每隔必定時間,自動加載新的詞庫。
推薦方案二,方案一雖是官方提供的,但操做起來比較麻煩,還須要部署http服務器。
方案步驟
1)下載源碼
git clone https://github.com/medcl/elasticsearch-analysis-ik
git checkout tags/v6.3.1
該工程是Maven項目工程,將代碼導入IDEA或Eclipse。
2)修改點
org.wltea.analyzer.dic.Dictionary
主要思路是在這個類的initial()方法內增長一個入口,反覆去調用reLoadMainDict()方法,此方法以下:
public void reLoadMainDict() {
logger.info("從新加載詞典...");
// 新開一個實例加載詞典,減小加載過程對當前詞典使用的影響
Dictionary tmpDict = new Dictionary(configuration);
tmpDict.configuration = getSingleton().configuration;
tmpDict.loadMainDict();
tmpDict.loadStopWordDict();
_MainDict = tmpDict._MainDict;
_StopWords = tmpDict._StopWords;
logger.info("從新加載詞典完畢...");
}
這個方法就是從新加載詞庫的,而後修改loadMainDict()和loadStopWordDict()方法,在這兩個方法最後加上讀取數據庫獲取最新的數據記錄的邏輯便可。數據庫的表結構本身定義兩張表,知足數據庫表設計規範便可。
3)IDE上mvn package打包
能夠直接用target/releases/目錄下的elasticsearch-analysis-ik-6.3.1.zip
4)解壓zip包,加上jdbc的配置,該修改的修改,重啓ES,看日誌
5)在數據庫里加幾個字段,在線嘗試是否生效。
方案延伸
該方案使用數據庫輪詢的方法,簡單有效,但比較浪費資源,畢竟生產上修改詞庫的動做是按需求發生的,能夠考慮由定時輪詢改爲MQ消息通知,這樣就能夠作到按需更新,而不用浪費太多的資源作詞典更新。
小結
本篇對中文分詞器IK做了簡單的講解,市面上流行的中文分詞器不少,若是咱們遇到有中文分詞的需求,貨比三家是永遠不過期的道理,調研可能要花費一些時間,但能挑到適合本身項目的分詞器,仍是划算的。
專一Java高併發、分佈式架構,更多技術乾貨分享與心得,請關注公衆號:Java架構社區能夠掃左邊二維碼添加好友,邀請你加入Java架構社區微信羣共同探討技術