一、基本概念
當一個文檔被存儲時,ES會使用分詞器從文檔中提取出若干詞元(token)來支持索引的存儲和搜索。
ES內置了很多分詞器,但內置的分詞器對中文的處理不好。下面通過例子來看內置分詞器的處理。在web客戶端發起如下的一個REST請求,對英文語句進行分詞:
POST http://localhost:9200/_analyze { "text": "hello world" }
操作成功後,響應的內容如下:
{ "tokens": [ { "token": "hello", "start_offset": 0, "end_offset": 5, "type": "<ALPHANUM>", "position": 0 }, { "token": "world", "start_offset": 6, "end_offset": 11, "type": "<ALPHANUM>", "position": 1 } ] }
上面結果顯示 "hello world"語句被分爲兩個單詞,因爲英文天生以空格分隔,自然就以空格來分詞,這沒有任何問題。
下面我們看一箇中文的語句例子,請求REST如下:
POST http://localhost:9200/_analyze { "text": "世界如此之大" }
操作成功後,響應的內容如下:
{ "tokens": [ { "token": "世", "start_offset": 0, "end_offset": 1, "type": "<IDEOGRAPHIC>", "position": 0 }, { "token": "界", "start_offset": 1, "end_offset": 2, "type": "<IDEOGRAPHIC>", "position": 1 }, { "token": "如", "start_offset": 2, "end_offset": 3, "type": "<IDEOGRAPHIC>", "position": 2 }, { "token": "此", "start_offset": 3, "end_offset": 4, "type": "<IDEOGRAPHIC>", "position": 3 }, { "token": "之", "start_offset": 4, "end_offset": 5, "type": "<IDEOGRAPHIC>", "position": 4 }, { "token": "大", "start_offset": 5, "end_offset": 6, "type": "<IDEOGRAPHIC>", "position": 5 } ] }
POST http://localhost:9200/_analyze { "analyzer": "standard", "text": "世界如此之大" }
ES通過安裝插件的方式來支持第三方分詞器,對於第三方的中文分詞器,比較常用的是中科院ICTCLAS的smartcn和IKAnanlyzer分詞器。在本文中,我們介紹IKAnanlyzer分詞器(下面簡稱ik)的使用。
二、ik分詞器的安裝
ES提供了一個腳本elasticsearch-plugin(windows下爲elasticsearch-plugin.bat)來安裝插件,腳本位於ES安裝目錄的bin目錄下。elasticsearch-plugin腳本可以有三種命令,靠參數區分:
1、 elasticsearch-plugin install 插件地址
install 參數指定的命令是安裝指定的插件到當前ES節點中。
2、 elasticsearch-plugin list
list參數指定的命令是顯示當前ES節點已經安裝的插件列表。
3、 elasticsearch-plugin remove 插件名稱
remove 參數指定的命令是刪除已安裝的插件。
使用elasticsearch-plugin install 安裝插件時,插件地址既可以是一個遠程文件地址(在線安裝),也可以是下載到本地的文件,不管是遠程文件或本地文件,對於ik插件來說都是一個zip文件。
注意,ik的版本要與ES的版本一致,因爲本文ES用的是7.8.0版本,所以我們ik也用的是7.8.0版本。
遠程文件安裝命令如下:
./bin/elasticsearch-plugin install https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v7.8.0/elasticsearch-analysis-ik-7.8.0.zip
如果不能下載,也可以從本地文件安裝,elasticsearch-plugin install後面跟的路徑,如果是本地的話,需要帶file:///協議頭
linux下的本地安裝命令是:
./bin/elasticsearch-plugin install file:///home/hadoop/elasticsearch-analysis-ik-7.8.0.zip
windows下本地安裝的命令是:
elasticsearch-plugin.bat install file:///D:/hadoop/elasticsearch-analysis-ik-7.8.0.zip
安裝完畢後,發現在ES的安裝目錄下的plugins目錄下多了一個analysis-ik目錄(內容是ik的zip包解壓後根目錄下的所有文件,一共是5個jar文件和1個properties配置文件),另外ES的安裝目錄下的config目錄下多了一個analysis-ik目錄(內容是ik的zip包解壓後根目錄下的config目錄下所有文件,用於放置ik的自定義詞庫)。
如果要使用插件,需要重啓es.
新版本的ik提供了兩個分詞器,分別是ik_max_word 和ik_smart
三、ik中文分詞器的使用
輸入命令如下:
POST http://localhost:9200/_analyze { "analyzer": "ik_max_word", "text": "世界如此之大" }
響應結果如下:
{ "tokens": [ { "token": "世界", "start_offset": 0, "end_offset": 2, "type": "CN_WORD", "position": 0 }, { "token": "如此之", "start_offset": 2, "end_offset": 5, "type": "CN_WORD", "position": 1 }, { "token": "如此", "start_offset": 2, "end_offset": 4, "type": "CN_WORD", "position": 2 }, { "token": "之大", "start_offset": 4, "end_offset": 6, "type": "CN_WORD", "position": 3 } ] }
再測試ik_smart,輸入命令如下:
POST http://localhost:9200/_analyze { "analyzer": "ik_smart", "text": "世界如此之大" }
響應結果如下:
{ "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 }, { "token": "之大", "start_offset": 4, "end_offset": 6, "type": "CN_WORD", "position": 2 } ] }
比較兩個分詞器對同一句中文的分詞結果,ik_max_word比ik_smart得到的中文詞更多(從兩者的英文名含義就可看出來),但這樣也帶來一個問題,使用ik_max_word會佔用更多的存儲空間。
四、ik的自定義詞典
有時,可能ik自身提供的分詞詞典無法滿足特定的一些需求(如專用名詞等),ik提供了自定義詞典的功能,也就是用戶可以自己定義一些詞彙,這樣ik就會把它們當作詞典中的內容來處理。
舉個例子,對於上面例子中的“世界如此之大”這個中文語句,ik詞庫中不會有“界如此”這樣一個單詞,假設“界如此”就是一個專用名詞,我們希望ik能識別出來。這時就可自定義ik的詞典。具體方法是:
1、新建擴展名爲dic的文本文件,文件中寫入想增加的詞條,每個詞條單獨一行,如文件名是test.dic,文件內容如下:
界如此
高潛
上面例子中有兩個自定義詞條。
2、將上面的dic文件保存到ES安裝目錄的config目錄下的analysis-ik目錄(安裝ik插件時產生的目錄)下,可以建立子目錄,放在子目錄下。比如文件的路徑如:
** config/analysis-ik/mydic/test.dic**
3、修改ik的配置文件IKAnalyzer.cfg.xml(位於config/analysis-ik目錄下),在配置文件中增加如下條目:
<entry key="ext_dict">mydict/test.dic</entry>
這樣就將自定義的字典文件加到ik的字典中了。
4、重啓ES讓生效。
這時我們發起如下的REST請求:
POST http://localhost:9200/_analyze { "analyzer": "ik_max_word", "text": "世界如此之大" }
響應結果如下:
{ "tokens": [ { "token": "世界", "start_offset": 0, "end_offset": 2, "type": "CN_WORD", "position": 0 }, { "token": "界如此", "start_offset": 1, "end_offset": 4, "type": "CN_WORD", "position": 1 }, { "token": "如此之", "start_offset": 2, "end_offset": 5, "type": "CN_WORD", "position": 2 }, { "token": "如此", "start_offset": 2, "end_offset": 4, "type": "CN_WORD", "position": 3 }, { "token": "之大", "start_offset": 4, "end_offset": 6, "type": "CN_WORD", "position": 4 } ] }
可以看出,自定義的“界如此”詞條被分詞出來了。不過如果我們將analyzer改爲ik_smart卻發現“界如此”詞條沒能被識別出來。