寫在前面:我是「且聽風吟」,目前是某上市遊戲公司的大數據開發工程師,熱愛大數據開源技術,喜歡分享自己的所學所悟,現階段正在從頭梳理大數據體系的知識,以後將會把時間重點放在Spark和Flink上面。
如果你也對大數據感興趣,希望在這個行業一展拳腳。歡迎關注我,我們一起努力,一起學習。博客地址:https://ropledata.blog.csdn.net
博客的名字來源於:且聽風吟,靜待花開。也符合我對技術的看法,想要真正掌握一門技術就需要厚積薄發的毅力,同時保持樂觀的心態。
你只管努力,剩下的交給時間!
文章目錄
一、前言
本文版本說明:
- 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在中文分詞的學習方面有沒有更進一步呢?
如果您對我的文章感興趣,歡迎關注點贊收藏,如果您有疑惑或發現文中有不對的地方,還請不吝賜教,非常感謝!!