原文鏈接:https://blog.csdn.net/qq_26803795/article/details/106522611
文章目錄
- 一、前言
- 二、內置分詞器解析
- 2.1、內置分詞器梳理
- 2.2、內置分詞器對中文的局限性
- 三、安裝IK分詞器
- 3.1、下載IK分詞器
- 3.2、編譯源碼包
- 3.3、上傳編譯好的包到Elasticsearch
- 四、玩轉ik分詞器
- 4.1、測試ik分詞器
- 4.2、來個小案例加深理解
- 五、總結
一、前言
本文版本說明:
- ElasticSearch版本:7.7 (目前最新版)
- Kibana版本:7.7(目前最新版)
前文咱們圍繞Elasticsearch最新版進行了上萬字的詳細解析,相信看過的朋友對Elasticsearch及kibana等工具的極速安裝配置印象深刻,也至少會對Elasticsearch有一個入門的掌握。
前文鏈接:ElasticSearch最新版快速入門詳解
本文咱們深入一些,詳細分析一下Elasticsearch的中文分詞,並順便解答和演示一下上篇文章有朋友對docker安裝的Elasticsearch如何支持中文分詞的疑問。好了,廢話不多說,讓我們開始吧!
二、內置分詞器解析
咱們知道Elasticsearch之所以模糊查詢這么快,是因為采用了倒排索引,而倒排索引的核心就是分詞,把text格式的字段按照分詞器進行分詞並編排索引。為了發揮自己的優勢,Elasticsearch已經提供了多種功能強大的內置分詞器,它們的作用都是怎樣的呢?能處理中文嗎?咱們往下看!
2.1、內置分詞器梳理
首先咱們可以對Elasticsearch提供的內置分詞器的作用進行如下總結:
| 分詞器 | 作用 |
|---|---|
| Standard | ES默認分詞器,按單詞分類並進行小寫處理 |
| Simple | 按照非字母切分,然后去除非字母並進行小寫處理 |
| Stop | 按照停用詞過濾並進行小寫處理,停用詞包括the、a、is |
| Whitespace | 按照空格切分 |
| Language | 據說提供了30多種常見語言的分詞器 |
| Patter | 按照正則表達式進行分詞,默認是\W+ ,代表非字母 |
| Keyword | 不進行分詞,作為一個整體輸出 |
可以發現,這些內置分詞器擅長處理單詞和字母,所以如果咱們要處理的是英文數據的話,它們的功能可以說已經很全面了!那處理中文效果怎么樣呢?下面咱們舉例驗證一下。
2.2、內置分詞器對中文的局限性
-
首先咱們創建一個索引,並批量插入一些包含中文和英文的數據:
// 創建索引 PUT /ropledata { "settings": { "number_of_shards": "2", "number_of_replicas": "0" } } // 批量插入數據 POST _bulk { "create" : { "_index" : "ropledata", "_id" : "1001" } } {"id":1,"name": "且聽風吟","hobby": "music and movie"} { "create" : { "_index" : "ropledata", "_id" : "1002" } } {"id":2,"name": "靜待花開","hobby": "music"} { "create" : { "_index" : "ropledata", "_id" : "1003" } } {"id":3,"name": "大數據","hobby": "movie"} { "create" : { "_index" : "ropledata", "_id" : "1004" } } {"id":4,"name": "且聽_風吟","hobby": "run"}我的運行結果:
在kibana的Dev Tools里執行情況:

查看Elasticsearch head里ropledata索引下的數據:

-
使用iterm查詢匹配的數據,分別對比中文英文:
首先咱們查詢愛好包含 ”music“ 的用戶數據,根據咱們之前錄入的數據,應該返回第一條和第二條才對,代碼如下:
POST /ropledata/_search { "query" : { "term" : { "hobby" : "music" } } }運行結果:

可以看到,很順利的就查出來咱們期望的數據,所以在英文詞匯下,即使是默認的分詞器Standard也夠用了。然后咱們試一下查找名字包含 “風吟” 的用戶,理想情況下,應該能返回第一條和第四條數據才對,咱們執行如下代碼:
POST /ropledata/_search { "query" : { "term" : { "name" : "風吟" } } }運行結果:

我們可以發現,查中文詞匯居然什么都沒有匹配到,好奇怪呀!疑問一:為什么在默認分詞器下,不能查找到詞匯呢?
因為咱們中文是非常博大精深的,詞匯是由多個漢字組成的,不像英文,一個詞匯就是一個單詞,比如“music”對應音樂,漢字需要兩個字才可以表示。而內置分詞器是沒有考慮到這類情況的,所以它們切分漢字時就會全部切分成單個漢字了,因此咱們找不到“風吟”這條數據,但是應該可以找到“風”這條數據,咱們接下來試一下。
根據剛才的解釋,咱們查找一個包含 “風” 的數據,代碼如下:
POST /ropledata/_search { "query" : { "term" : { "name" : "風" } } }運行結果如下:

所以,咱們剛才對這個疑問的解釋是正確的。如果想匹配到某條數據而不想讓它分詞,需要使用keyword,這樣對應的text就會作為一個整體來查詢:

-
便捷分詞器測試技巧
其實咱們測試分詞器對詞匯的分詞,有一個更簡便的方法,就是利用Elasticsearch的
_analyze,比如咱們想看“且聽風吟”被默認分詞器standard分詞后的效果,只需要執行如下代碼:POST /_analyze { "analyzer":"standard", "text":"且聽風吟" }運行結果如下:

這樣看就更加簡單直觀了,咱們可以看到不同分詞器對text格式數據的分詞結果,感興趣的朋友可以把所有的分詞器都玩一玩。
為了解決中文分詞的問題,咱們需要掌握至少一種中文分詞器,常用的中文分詞器有IK、jieba、THULAC等,推薦使用IK分詞器,這也是目前使用最多的分詞器,接下來咱們在docker環境下把IK分詞器裝一下。
三、安裝IK分詞器
3.1、下載IK分詞器
下載地址:https://github.com/medcl/elasticsearch-analysis-ik/releases
打開上述網址后,根據咱們的Elasticsearch版本找到對應的編譯好的包來下載,正常情況下都是有編譯好的包,比如7.6.2版本的:

可是由於咱們用的是最新的7.7版本,截止到我寫這篇文章的時候,7.7版本還只提供源碼包,沒有編譯后的包:

如果你看這篇文章的時候,這里已經提供了編譯后的包,請把編譯好的包直接下載下來並解壓,然后跳過下一小節,直接看3.3小節就可以了。如果和我一樣,那就一起愉快的編譯吧!
3.2、編譯源碼包
-
下載源碼包
既然沒有提供編譯好的包,那么咱們就要下載源碼包,自己編譯了。首先把源碼包下載下來,比如咱們選擇zip格式的:

-
解壓並進入解壓后的文件夾

-
執行mvn編譯
在這個源碼包的目錄下分別執行如下命令:
mvn clean mvn compile mvn package -
mvn編譯完成后,會在
elasticsearch-analysis-ik-7.7.0/target/releases目錄下生成一個zip文件:

-
解壓這個zip文件,並刪除原本的zip包:
unzip elasticsearch-analysis-ik-7.4.0.zip rm -rf elasticsearch-analysis-ik-7.4.0.zip
-
修改
plugin-descriptor.properties包里的最后的Elasticsearch版本:vi plugin-descriptor.properties
-
修改后按
ESC鍵,並輸入:wq保存退出,這時候咱們的ik插件包就准備好了,如果官網有的話,下載下來也是這樣的。
3.3、上傳編譯好的包到Elasticsearch
到這里,咱們已經有編譯好的包了,不管是官方提供的,還是自己編譯的,都是一樣的。
-
首先新建文件夾ik,然后把咱們下載的或者自己編譯好的ik源碼包里的文件都復制進去:

-
使用docker cp命令把ik文件夾及里面的文件都上傳到容器的
/home/elasticsearch/elasticsearch-7.7.0/plugins/目錄下:語法格式:docker cp 本地文件或文件夾路徑 容器ID:容器文件或文件夾路徑
docker cp ../ik a79d4cddb331:/home/elasticsearch/elasticsearch-7.7.0/plugins/ -
然后重啟咱們的容器就搞定了:
docker restart a79d4cddb331
到這里,咱們已經把ik分詞器插件安裝成功了,下面就開始愉快的玩耍吧!
四、玩轉ik分詞器
4.1、測試ik分詞器
根據官方的建議,ik分詞器的名字可以使用:ik_smart , ik_max_word:

咱們可以在kibana的dev tools里執行如下代碼,來測試ik分詞器對中文的分詞效果:
POST /_analyze
{
"analyzer": "ik_max_word",
"text": "且聽風吟"
}
我的運行效果:

4.2、來個小案例加深理解
下面創建一個索引,然后要求對中文部分的text用ik分詞器來解析,來觀察ik分詞器的效果。
-
創建一個索引
PUT /ropledata { "settings": { "index": { "number_of_shards": "2", "number_of_replicas": "0" } }, "mappings": { "properties": { "id": { "type": "integer" }, "name": { "type": "text", "analyzer": "ik_max_word" }, "hobby": { "type": "text" } } } } -
批量添加數據
POST _bulk { "create" : { "_index" : "ropledata", "_id" : "1001" } } {"id":1,"name": "且聽風吟,靜待花開","hobby": "music and movie"} { "create" : { "_index" : "ropledata", "_id" : "1002" } } {"id":2,"name": "且聽_風吟","hobby": "music"} { "create" : { "_index" : "ropledata", "_id" : "1003" } } {"id":3,"name": "大數據領域","hobby": "movie"} { "create" : { "_index" : "ropledata", "_id" : "1004" } } {"id":4,"name": "一起學習","hobby": "run"}在kibana里可以看到,數據已經插入成功:

-
首先驗證一下英文默認分詞效果,查找hobby包含
music的數據:POST /ropledata/_search { "query": { "match": { "hobby": "music" } } }
-
然后驗證一下中文ik分詞器效果,查找name包含
風吟的數據:POST /ropledata/_search { "query": { "match": { "name": "風吟" } } }
疑問二:ik分詞器是根據什么來分詞的呢?如果有些特殊的詞匯比如人名,店名,網名,想根據自己的要求特殊處理來分詞,能不能解決呢?
ik分詞器本身維護了一個超大的詞匯文本,里面有非常多的中文詞匯。這個文件在
ik/config/下,名為main.dic,咱們可以打開看看:
如果要根據自己的特殊詞匯來切分,咱們可以把想要切分成的詞匯加入到這個文件里面就可以了。
五、總結
本文我們圍繞Elasticsearch的分詞器,從內置分詞器的局限性出發,引出了中文分詞器,然后詳細介紹了ik分詞器的編譯和在docker容器環境下的安裝和使用,其實在linux環境下步驟也是差不多的。不知道看完之后,大家對Elasticsearch在中文分詞的學習方面有沒有更進一步呢?
如果您對我的文章感興趣,歡迎關注點贊收藏,如果您有疑惑或發現文中有不對的地方,還請不吝賜教,非常感謝!!

