ElasticSearch中文分詞,看這一篇就夠了

寫在前面:我是「且聽風吟」,目前是某上市遊戲公司的大數據開發工程師,熱愛大數據開源技術,喜歡分享自己的所學所悟,現階段正在從頭梳理大數據體系的知識,以後將會把時間重點放在Spark和Flink上面。

如果你也對大數據感興趣,希望在這個行業一展拳腳。歡迎關注我,我們一起努力,一起學習。博客地址:https://ropledata.blog.csdn.net

博客的名字來源於:且聽風吟,靜待花開。也符合我對技術的看法,想要真正掌握一門技術就需要厚積薄發的毅力,同時保持樂觀的心態。

你只管努力,剩下的交給時間!

在這裏插入圖片描述

一、前言

本文版本說明:

  1. ElasticSearch版本:7.7 (目前最新版)
  2. 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、內置分詞器對中文的侷限性

  1. 首先咱們創建一個索引,並批量插入一些包含中文和英文的數據:

    // 創建索引
    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索引下的數據:
    在這裏插入圖片描述

  2. 使用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就會作爲一個整體來查詢:

    在這裏插入圖片描述

  3. 便捷分詞器測試技巧

    其實咱們測試分詞器對詞彙的分詞,有一個更簡便的方法,就是利用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、編譯源碼包

  1. 下載源碼包

    既然沒有提供編譯好的包,那麼咱們就要下載源碼包,自己編譯了。首先把源碼包下載下來,比如咱們選擇zip格式的:
    在這裏插入圖片描述

  2. 解壓並進入解壓後的文件夾
    在這裏插入圖片描述

  3. 執行mvn編譯

    在這個源碼包的目錄下分別執行如下命令:

    mvn clean
    mvn compile
    mvn package
    
  4. mvn編譯完成後,會在elasticsearch-analysis-ik-7.7.0/target/releases目錄下生成一個zip文件:
    在這裏插入圖片描述

  5. 解壓這個zip文件,並刪除原本的zip包:

    unzip elasticsearch-analysis-ik-7.4.0.zip
    rm -rf elasticsearch-analysis-ik-7.4.0.zip
    

    在這裏插入圖片描述

  6. 修改plugin-descriptor.properties包裏的最後的Elasticsearch版本:

    vi plugin-descriptor.properties
    

    在這裏插入圖片描述

  7. 修改後按ESC鍵,並輸入:wq保存退出,這時候咱們的ik插件包就準備好了,如果官網有的話,下載下來也是這樣的。

3.3、上傳編譯好的包到Elasticsearch

到這裏,咱們已經有編譯好的包了,不管是官方提供的,還是自己編譯的,都是一樣的。

  1. 首先新建文件夾ik,然後把咱們下載的或者自己編譯好的ik源碼包裏的文件都複製進去:
    在這裏插入圖片描述

  2. 使用docker cp命令把ik文件夾及裏面的文件都上傳到容器的/home/elasticsearch/elasticsearch-7.7.0/plugins/ 目錄下:

    語法格式:docker cp 本地文件或文件夾路徑 容器ID:容器文件或文件夾路徑

     
     docker cp  ../ik a79d4cddb331:/home/elasticsearch/elasticsearch-7.7.0/plugins/
    
  3. 然後重啓咱們的容器就搞定了:

    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分詞器的效果。

  1. 創建一個索引

    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"
          }
        }
      }
    }
    
  2. 批量添加數據

    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裏可以看到,數據已經插入成功:
    在這裏插入圖片描述

  3. 首先驗證一下英文默認分詞效果,查找hobby包含music的數據:

    POST /ropledata/_search
    {
      "query": {
        "match": {
          "hobby": "music"
        }
      }
    }
    

    在這裏插入圖片描述

  4. 然後驗證一下中文ik分詞器效果,查找name包含風吟的數據:

    POST /ropledata/_search
    {
      "query": {
        "match": {
          "name": "風吟"
        }
      }
    }
    

    在這裏插入圖片描述

疑問二:ik分詞器是根據什麼來分詞的呢?如果有些特殊的詞彙比如人名,店名,網名,想根據自己的要求特殊處理來分詞,能不能解決呢?

ik分詞器本身維護了一個超大的詞彙文本,裏面有非常多的中文詞彙。這個文件在ik/config/下,名爲main.dic,咱們可以打開看看:
在這裏插入圖片描述
如果要根據自己的特殊詞彙來切分,咱們可以把想要切分成的詞彙加入到這個文件裏面就可以了。


五、總結

本文我們圍繞Elasticsearch的分詞器,從內置分詞器的侷限性出發,引出了中文分詞器,然後詳細介紹了ik分詞器的編譯和在docker容器環境下的安裝和使用,其實在linux環境下步驟也是差不多的。不知道看完之後,大家對Elasticsearch在中文分詞的學習方面有沒有更進一步呢?

如果您對我的文章感興趣,歡迎關注點贊收藏,如果您有疑惑或發現文中有不對的地方,還請不吝賜教,非常感謝!!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章