中文分詞

本文是對ElasticSearch中文分詞學(xué)習(xí)的一個知識總結(jié),包括如下章節(jié)的內(nèi)容:

  • 基本概念
  • ik分詞器的安裝
  • ik中文分詞器的使用
  • ik的自定義詞典
  • 文檔的中文分詞使用

參考資料:
1、如果希望先對ElasticSearch組件的基本概念有所了解,可先閱讀《ElasticSearch學(xué)習(xí)筆記》

一、基本概念

當(dāng)一個文檔被存儲時,ES會使用分詞器從文檔中提取出若干詞元(token)來支持索引的存儲和搜索。
ES內(nèi)置了很多分詞器,但內(nèi)置的分詞器對中文的處理不好。下面通過例子來看內(nèi)置分詞器的處理。在web客戶端發(fā)起如下的一個REST請求,對英文語句進(jìn)行分詞:

POST http://localhost:9200/_analyze
{  
    "text": "hello world"  
}

操作成功后,響應(yīng)的內(nèi)容如下:

{
  "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
    }
  ]
}

上面結(jié)果顯示 "hello world"語句被分為兩個單詞,因?yàn)橛⑽奶焐钥崭穹指?,自然就以空格來分詞,這沒有任何問題。

下面我們看一個中文的語句例子,請求REST如下:

POST http://localhost:9200/_analyze
{  
    "text": "世界如此之大"  
}

操作成功后,響應(yīng)的內(nèi)容如下:

{
  "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
    }
  ]
}

從結(jié)果可以看出,這種分詞把每個漢字都獨(dú)立分開來了,這對中文分詞就沒有意義了,所以ES默認(rèn)的分詞器對中文處理是有問題的。好在有很多不錯的第三方的中文分詞器,可以很好地和ES結(jié)合起來使用。在ES中,每種分詞器(包括內(nèi)置的、第三方的)都會有個名稱。上面默認(rèn)的操作,其實(shí)用的分詞器的名稱是standard。下面的請求與前面介紹的請求是等價的,如:

POST http://localhost:9200/_analyze
{  
    "analyzer": "standard",
    "text": "世界如此之大"  
}

當(dāng)我們換一個分詞器處理分詞時,只需將"analyzer"字段設(shè)置相應(yīng)的分詞器名稱即可。
ES通過安裝插件的方式來支持第三方分詞器,對于第三方的中文分詞器,比較常用的是中科院ICTCLAS的smartcn和IKAnanlyzer分詞器。在本文中,我們介紹IKAnanlyzer分詞器(下面簡稱ik)的使用。

因?yàn)槭窃诰W(wǎng)上搜索資料來進(jìn)行ik的安裝,碰到了很多坑,折騰很長時間才搞定,主要原因是網(wǎng)上的很多資料都是針對舊版本的ES和IK版本,有很多信息在新版本中已經(jīng)有變化。下面的內(nèi)容會介紹那些遇到的坑。

二、ik分詞器的安裝

ES提供了一個腳本elasticsearch-plugin(windows下為elasticsearch-plugin.bat)來安裝插件,腳本位于ES安裝目錄的bin目錄下。elasticsearch-plugin腳本可以有三種命令,靠參數(shù)區(qū)分:

1、 elasticsearch-plugin install 插件地址
install 參數(shù)指定的命令是安裝指定的插件到當(dāng)前ES節(jié)點(diǎn)中。

2、 elasticsearch-plugin list
list參數(shù)指定的命令是顯示當(dāng)前ES節(jié)點(diǎn)已經(jīng)安裝的插件列表。

3、 elasticsearch-plugin remove 插件名稱
remove 參數(shù)指定的命令是刪除已安裝的插件。

使用elasticsearch-plugin install 安裝插件時,插件地址既可以是一個遠(yuǎn)程文件地址(在線安裝),也可以是下載到本地的文件,不管是遠(yuǎn)程文件或本地文件,對于ik插件來說都是一個zip文件。
注意,ik的版本要與ES的版本一致,因?yàn)楸疚腅S用的是5.6.9版本,所以我們ik也用的是5.6.9版本。

遠(yuǎn)程文件安裝命令如下:

elasticsearch-plugin  install  
https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v5.6.9/elasticsearch-analysis-ik-5.6.9.zip

因?yàn)槭褂玫腖inux機(jī)器無法直接上外網(wǎng),所以就考慮采用本地文件安裝的方式,這是碰到的第一個坑。從上面地址上下載了elasticsearch-analysis-ik-5.6.9.zip文件到本地,然后執(zhí)行命令如下(實(shí)際下面寫法是錯誤的):

elasticsearch-plugin  install 
/home/hadoop/elasticsearch-analysis-ik-5.6.9.zip

上面命令是在linux系統(tǒng)下執(zhí)行的,zip文件位于本地的/home/hadoop目錄下。但是無論怎么執(zhí)行,都報錯,報/home/hadoop/elasticsearch-analysis-ik-5.6.9.zip不是插件。在網(wǎng)上搜索了半天,也沒有找到原因,甚至懷疑是下載的二進(jìn)制包有問題,直接下載源代碼自己編譯打包成zip包,結(jié)果還是有問題。后來請教了同事,才知道elasticsearch-plugin install后面跟的路徑,如果是本地的話,需要帶file:///協(xié)議頭。果然,帶上協(xié)議頭無論是在liunx下還是windows下安裝都是成功的。這個事情給的教訓(xùn)是,不要想當(dāng)然,因?yàn)橐詾楸镜刂苯硬捎帽镜芈窂郊纯?,沒想到要加file:///協(xié)議頭;第二,有問題一段時間搞不定時及時向他人請教,省得浪費(fèi)時間。

正確的linux下的本地安裝命令是:

elasticsearch-plugin  install 
file:///home/hadoop/elasticsearch-analysis-ik-5.6.9.zip

正確的windows下本地安裝的命令是:

elasticsearch-plugin.bat install 
file:///D:/hadoop/elasticsearch-analysis-ik-5.6.9.zip

安裝完畢后,發(fā)現(xiàn)在ES的安裝目錄下的plugins目錄下多了一個analysis-ik目錄(內(nèi)容是ik的zip包解壓后根目錄下的所有文件,一共是5個jar文件和1個properties配置文件),另外ES的安裝目錄下的config目錄下多了一個analysis-ik目錄(內(nèi)容是ik的zip包解壓后根目錄下的config目錄下所有文件,用于放置ik的自定義詞庫)。

遇到的第二個坑是,網(wǎng)上很多資料說,安裝ik插件后,需要在ES的配置文件elasticsearch.yml中加上如下一行內(nèi)容:

index.analysis.analyzer.ik.type: "ik"

可是,實(shí)際情況是加上這句話后,ES啟動失敗,從報的錯誤信息也看不到原因。又在網(wǎng)上查了半天,終于在一篇文章中看到對這個問題的解釋:“index.analysis.analyzer.ik.type這個在新版本的ES中已經(jīng)不需要了,添加了啟動時反而會報錯,ES5.X版本不再通過elasitcsearch.yml配置設(shè)置分詞規(guī)則,而是在創(chuàng)建索引時指定”。

下面再介紹遇到的第三個坑,網(wǎng)上給出使用ik的例子,請求命令如下:

POST http://localhost:9200/_analyze
{  
    "analyzer": "ik",
    "text": "世界如此之大"  
}

但是總是返回錯誤信息,錯誤如下:

{
  "error": {
    "root_cause": [
      {
        "type": "remote_transport_exception",
        "reason": "[IefRKZ0][localhost:9300][indices:admin/analyze[s]]"
      }
    ],
    "type": "illegal_argument_exception",
    "reason": "failed to find global analyzer [ik]"
  },
  "status": 400
}

錯誤信息還是很明確的,找不到分詞器ik。就以為是配置文件哪里配錯了,折騰試了半天沒找到原因。后來查找資料才知道在新的ik版本中,分詞器的名稱變了(不再叫ik),新版本的ik提供了兩個分詞器,分別是ik_max_word 和ik_smart,用任何一個替換ik,就沒問題了。
三、ik中文分詞器的使用
上面提到,ik提供了兩個分詞器,分別是ik_max_word 和ik_smart,下面我們分別測試下。
先測試ik_max_word,輸入命令如下:

POST http://localhost:9200/_analyze
{
"analyzer": "ik_max_word",
"text": "世界如此之大"
}
響應(yīng)結(jié)果如下:

{
"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": "世界如此之大"
}
響應(yīng)結(jié)果如下:

{
"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
}
]
}
比較兩個分詞器對同一句中文的分詞結(jié)果,ik_max_word比ik_smart得到的中文詞更多(從兩者的英文名含義就可看出來),但這樣也帶來一個問題,使用ik_max_word會占用更多的存儲空間。

四、ik的自定義詞典
有時,可能ik自身提供的分詞詞典無法滿足特定的一些需求(如專用名詞等),ik提供了自定義詞典的功能,也就是用戶可以自己定義一些詞匯,這樣ik就會把它們當(dāng)作詞典中的內(nèi)容來處理。

舉個例子,對于上面例子中的“世界如此之大”這個中文語句,ik詞庫中不會有“界如此”這樣一個單詞,假設(shè)“界如此”就是一個專用名詞,我們希望ik能識別出來。這時就可自定義ik的詞典。具體方法是:

1、新建擴(kuò)展名為dic的文本文件,文件中寫入想增加的詞條,每個詞條單獨(dú)一行,如文件名是test.dic,文件內(nèi)容如下:

界如此
高潛
上面例子中有兩個自定義詞條。

2、將上面的dic文件保存到ES安裝目錄的config目錄下的analysis-ik目錄(安裝ik插件時產(chǎn)生的目錄)下,可以建立子目錄,放在子目錄下。比如文件的路徑如:
** 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讓生效。

這時我們發(fā)起如下的REST請求:

POST http://localhost:9200/_analyze
{
"analyzer": "ik_max_word",
"text": "世界如此之大"
}
響應(yīng)結(jié)果如下:

{
"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卻發(fā)現(xiàn)“界如此”詞條沒能被識別出來。

五、文檔的中文分詞使用
前面的介紹只是簡單舉例介紹了ik的使用,下面我們來通過一個更完整的例子介紹分詞。ES的分詞在創(chuàng)建索引(index)后,可以通過REST命令來設(shè)置,這樣后續(xù)插入到該索引的數(shù)據(jù)都會被相應(yīng)的分詞器進(jìn)行處理。

為了比較ik的ik_smart和ik_max_word這兩個分詞器及默認(rèn)的分詞器standard,我們創(chuàng)建3個索引來分別使用這3個分詞器。

1、創(chuàng)建索引

PUT http://192.168.226.132:9200/index_ik_s
PUT http://192.168.226.132:9200/index_ik_m
PUT http://192.168.226.132:9200/index_stan
2、設(shè)置分析器

POST http://localhost:9200/index_ik_s/resource/_mapping
{
"properties": {
"content": {
"type": "text",
"analyzer": "ik_smart",
"search_analyzer": "ik_smart"
}
}
}
POST http://localhost:9200/index_ik_m/resource/_mapping
{
"properties": {
"content": {
"type": "text",
"analyzer": "ik_max_word",
"search_analyzer": "ik_max_word"
}
}
}
POST http://localhost:9200/index_stan/resource/_mapping
{
"properties": {
"content": {
"type": "text",
"analyzer": "standard",
"search_analyzer": "standard"
}
}
}
3、插入數(shù)據(jù)
為了批量插入,我們使用了linxu的curl命令來執(zhí)行REST操作。

curl -XPOST http://localhost:9200/index_ik_s/resource/1 -d'
{"content":"上海牛人科技有限公司"}'

curl -XPOST http://localhost:9200/index_ik_s/resource/2 -d'
{"content":"上海牛人科技有限公司,牛人聚集的地方"}'

curl -XPOST http://localhost:9200/index_ik_s/resource/3 -d'
{"content":"最牛的人所在的地方,上海牛人科技有限公司"}'

curl -XPOST http://localhost:9200/index_ik_s/resource/4 -d'
{"content":" This is an English test case"}'

curl -XPOST http://localhost:9200/index_ik_s/resource/5 -d'
{"content":" English Test Case"}'
curl -XPOST http://localhost:9200/index_ik_m/resource/1 -d'
{"content":"上海牛人科技有限公司"}'

curl -XPOST http://localhost:9200/index_ik_m/resource/2 -d'
{"content":"上海牛人科技有限公司,牛人聚集的地方"}'

curl -XPOST http://localhost:9200/index_ik_m/resource/3 -d'
{"content":"最牛的人所在的地方,上海牛人科技有限公司"}'

curl -XPOST http://localhost:9200/index_ik_m/resource/4 -d'
{"content":" This is an English test case"}'

curl -XPOST http://localhost:9200/index_ik_m/resource/5 -d'
{"content":" English Test Case"}'
curl -XPOST http://localhost:9200/index_stan/resource/1 -d'
{"content":"上海牛人科技有限公司"}'

curl -XPOST http://localhost:9200/index_stan/resource/2 -d'
{"content":"上海牛人科技有限公司,牛人聚集的地方"}'

curl -XPOST http://localhost:9200/index_stan/resource/3 -d'
{"content":"最牛的人所在的地方,上海牛人科技有限公司"}'

curl -XPOST http://localhost:9200/index_stan/resource/4 -d'
{"content":" This is an English test case"}'

curl -XPOST http://localhost:9200/index_stan/resource/5 -d'
{"content":" English Test Case"}'
4、測試驗(yàn)證和對比
先測下他們對中文標(biāo)準(zhǔn)單詞的支持,查詢“科技”,3種索引效果都一樣的,都能勝任。請求命令如下:

POST http://localhost:9200/_search
{
"query": {
"query_string": {
"query": "科技",
"fields": ["content"]
}
}
}
再測試下非標(biāo)準(zhǔn)的搜索,搜索“海?!?,ik_smart搜索不出結(jié)果,因?yàn)樵趕mart的反向索引中分詞是“上?!薄ⅰ芭H恕?。ik_max_word搜索得到結(jié)果,因?yàn)樵趍axword的反向索引中“上?!薄ⅰ芭H恕?、“海牛”這些都有分詞。Stardard可以搜索的到結(jié)果,因?yàn)閟tartard的反向索引中每個字都拆分成一個分詞“?!?、“牛”,在搜索時又將每個字都拆成一個檢索條件,所以查詢得到。

案例中也給了英文的例子,測試后發(fā)現(xiàn),ik_smart和ik_max_word對英文的分詞不比standard差多少。

對比后我們的結(jié)論是:ik_smart既能滿足英文的要求,又更智能更輕量,占用存儲最小,所以首推ik_smart;standard對英語支持是最好的,但是對中文是簡單暴力每個字建一個反向索引,浪費(fèi)存儲空間而且效果很差;ik_max_word比ik_smart對中文的支持更全面,但是存儲上的開銷實(shí)在太大,不建議使用。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容