ES 終於可以搜到”悟空哥“了!

Elasticsearch 搜索引擎內置了很多種分詞器,但是對中文分詞不友好,所以我們需要藉助第三方中文分詞工具包。

悟空哥專門研究了下 ik 中文分詞工具包該怎麼玩,希望對大家有所幫助。

本文主要內容如下:

主要內容

1 ES 中的分詞的原理

1.1 ES 的分詞器概念

ES 的一個分詞器 ( tokenizer ) 接收一個字符流,將其分割爲獨立的詞元 ( tokens ) ,然後輸出詞元流。

ES 提供了很多內置的分詞器,可以用來構建自定義分詞器 ( custom ananlyzers )

1.2 標準分詞器原理

比如 stadard tokenizer 標準分詞器,遇到空格進行分詞。該分詞器還負責記錄各個詞條 ( term ) 的順序或 position 位置 ( 用於 phrase 短語和 word proximity 詞近鄰查詢 ) 。每個單詞的字符偏移量 ( 用於高亮顯示搜索的內容 ) 。

1.3 英文和標點符號分詞示例

查詢示例如下:

POST _analyze
{
  "analyzer": "standard",
  "text": "Do you know why I want to study ELK? 2 3 33..."
}

查詢結果:

do, you, know, why, i, want, to, study, elk, 2,3,33

從查詢結果可以看到:

(1)標點符號沒有分詞。

(2)數字會進行分詞。

英文句子分詞

1.4 中文分詞示例

但是這種分詞器對中文的分詞支持不友好,會將詞語分詞爲單獨的漢字。比如下面的示例會將 悟空聊架構 分詞爲 ,,,,,期望分詞爲 悟空架構

POST _analyze
{
  "analyzer": "standard",
  "text": "悟空聊架構"
}

中文分詞悟空聊架構

我們可以安裝 ik 分詞器來更加友好的支持中文分詞。

2 安裝 ik 分詞器

2.1 ik 分詞器地址

ik 分詞器地址:

https://github.com/medcl/elasticsearch-analysis-ik/releases

先檢查 ES 版本,我安裝的版本是 7.4.2,所以我們安裝 ik 分詞器的版本也選擇 7.4.2

http://192.168.56.10:9200/
{
  "name" : "8448ec5f3312",
  "cluster_name" : "elasticsearch",
  "cluster_uuid" : "xC72O3nKSjWavYZ-EPt9Gw",
  "version" : {
    "number" : "7.4.2",
    "build_flavor" : "default",
    "build_type" : "docker",
    "build_hash" : "2f90bbf7b93631e52bafb59b3b049cb44ec25e96",
    "build_date" : "2019-10-28T20:40:44.881551Z",
    "build_snapshot" : false,
    "lucene_version" : "8.2.0",
    "minimum_wire_compatibility_version" : "6.8.0",
    "minimum_index_compatibility_version" : "6.0.0-beta1"
  },
  "tagline" : "You Know, for Search"
}

選擇 ik 分詞器

2.2 安裝 ik 分詞器的方式

2.2.1 方式一:容器內安裝 ik 分詞器

  • 進入 es 容器內部 plugins 目錄
docker exec -it <容器 id> /bin/bash
  • 獲取 ik 分詞器壓縮包
wget https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v7.4.2/elasticsearch-analysis-ik-7.4.2.zip
  • 解壓縮 ik 壓縮包
unzip 壓縮包
  • 刪除下載的壓縮包
rm -rf *.zip

2.2.2 方式二:映射文件安裝 ik 分詞器

進入到映射文件夾

cd /mydata/elasticsearch/plugins

下載安裝包

wget https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v7.4.2/elasticsearch-analysis-ik-7.4.2.zip
  • 解壓縮 ik 壓縮包
unzip 壓縮包
  • 刪除下載的壓縮包
rm -rf *.zip

2.2.3 方式三:Xftp 上傳壓縮包到映射目錄

先用 XShell 工具連接虛擬機 ( 操作步驟可以參考之前寫的文章 02. 快速搭建 Linux 環境-運維必備) ,然後用 Xftp 將下載好的安裝包複製到虛擬機。

Xftp 上傳壓縮包

3 解壓 ik 分詞器到容器中

  • 如果沒有安裝 unzip 解壓工具,則安裝 unzip 解壓工具。
apt install unzip
  • 解壓 ik 分詞器到當前目錄的 ik 文件夾下。

命令格式:unzip <ik 分詞器壓縮包>

實例:

unzip ELK-IKv7.4.2.zip -d ./ik

解壓 ik 分詞器

  • 修改文件夾權限爲可讀可寫。
chmod -R 777 ik/
  • 刪除 ik 分詞器壓縮包
rm ELK-IKv7.4.2.zip

4 檢查 ik 分詞器安裝

  • 進入到容器中
docker exec -it <容器 id> /bin/bash
  • 查看 Elasticsearch 的插件
elasticsearch-plugin list

結果如下,說明 ik 分詞器安裝好了。是不是很簡單。

ik

ik 分詞器插件

然後退出 Elasticsearch 容器,並重啓 Elasticsearch 容器

exit
docker restart elasticsearch

5 使用 ik 中文分詞器

ik 分詞器有兩種模式

  • 智能分詞模式 ( ik_smart )

  • 最大組合分詞模式 ( ik_max_word )

我們先看下 智能分詞 模式的效果。比如對於 一顆小星星 進行中文分詞,得到的兩個詞語:一顆小星星

我們在 Dev Tools Console 輸入如下查詢

POST _analyze
{
  "analyzer": "ik_smart",
  "text": "一顆小星星"
}

得到如下結果,被分詞爲 一顆和小星星。

一顆小星星分詞結果

再來看下 最大組合分詞模式。輸入如下查詢語句。

POST _analyze
{
  "analyzer": "ik_max_word",
  "text": "一顆小星星"
}

一顆小星星 被分成了 6 個詞語:一顆、一、顆、小星星、小星、星星。

一顆小星星分詞結果

我們再來看下另外一箇中文分詞。比如搜索悟空哥聊架構,期望結果:悟空哥、聊、架構三個詞語。

實際結果:悟、空哥、聊、架構四個詞語。ik 分詞器將悟空哥分詞了,認爲 空哥 是一個詞語。所以需要讓 ik 分詞器知道 悟空哥 是一個詞語,不需要拆分。那怎麼辦做呢?

悟空哥聊架構分詞

6 自定義分詞詞庫

6.1 自定義詞庫的方案

  • 方案

    新建一個詞庫文件,然後在 ik 分詞器的配置文件中指定分詞詞庫文件的路徑。可以指定本地路徑,也可以指定遠程服務器文件路徑。這裏我們使用遠程服務器文件的方案,因爲這種方案可以支持熱更新 ( 更新服務器文件,ik 分詞詞庫也會重新加載 ) 。

  • 修改配置文件

ik 分詞器的配置文件在容器中的路徑:

/usr/share/elasticsearch/plugins/ik/config/IKAnalyzer.cfg.xml。

修改這個文件可以通過修改映射文件,文件路徑:

/mydata/elasticsearch/plugins/ik/config/IKAnalyzer.cfg.xml

編輯配置文件:

vim /mydata/elasticsearch/plugins/ik/config/IKAnalyzer.cfg.xml

配置文件內容如下所示:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
<properties>
    <comment>IK Analyzer 擴展配置</comment>
    <!--用戶可以在這裏配置自己的擴展字典 -->
    <entry key="ext_dict">custom/mydict.dic;custom/single_word_low_freq.dic</entry>
     <!--用戶可以在這裏配置自己的擴展停止詞字典-->
    <entry key="ext_stopwords">custom/ext_stopword.dic</entry>
     <!--用戶可以在這裏配置遠程擴展字典 -->
    <entry key="remote_ext_dict">location</entry>
     <!--用戶可以在這裏配置遠程擴展停止詞字典-->
    <entry key="remote_ext_stopwords">http://xxx.com/xxx.dic</entry>
</properties>

修改配置 remote_ext_dict 的屬性值,指定一個 遠程網站文件的路徑,比如 http://www.aaa.aaa/ikwords.text。

這裏我們可以自己搭建一套 nginx 環境,然後把 ikwords.text 放到 nginx 根目錄。

6.2 搭建 nginx 環境

方案:首先獲取 nginx 鏡像,然後啓動一個 nginx 容器,然後將 nginx 的配置文件拷貝到根目錄,再刪除原 nginx 容器,再用映射文件夾的方式來重新啓動 nginx 容器。

  • 通過 docker 容器安裝 nginx 環境。
docker run -p 80:80 --name nginx -d nginx:1.10
  • 拷貝 nginx 容器的配置文件到 mydata 目錄的 conf 文件夾
cd /mydata
docker container cp nginx:/etc/nginx ./conf
  • mydata 目錄 裏面創建 nginx 目錄
mkdir nginx
  • 移動 conf 文件夾到 nginx 映射文件夾
mv conf nginx/
  • 終止並刪除原 nginx 容器
docker stop nginx
docker rm <容器 id>
  • 啓動新的容器
docker run -p 80:80 --name nginx \
-v /mydata/nginx/html:/usr/share/nginx/html \
-v /mydata/nginx/logs:/var/log/nginx \
-v /mydata/nginx/conf:/etc/nginx \
-d nginx:1.10
  • 訪問 nginx 服務
192.168.56.10

報 403 Forbidden, nginx/1.10.3 則表示 nginx 服務正常啓動。403 異常的原因是 nginx 服務下沒有文件。

  • nginx 目錄新建一個 html 文件
cd /mydata/nginx/html
vim index.html
hello passjava
  • 再次訪問 nginx 服務

    瀏覽器打印 hello passjava。說明訪問 nginx 服務的頁面沒有問題。

  • 創建 ik 分詞詞庫文件

cd /mydata/nginx/html
mkdir ik
cd ik
vim ik.txt

填寫 悟空哥,並保存文件。

  • 訪問詞庫文件
http://192.168.56.10/ik/ik.txt

瀏覽器會輸出一串亂碼,可以先忽略亂碼問題。說明詞庫文件可以訪問到。

  • 修改 ik 分詞器配置
cd /mydata/elasticsearch/plugins/ik/config
vim IKAnalyzer.cfg.xml

修改 ik 分詞器配置

  • 重啓 elasticsearch 容器並設置每次重啓機器後都啓動 elasticsearch 容器。
docker restart elasticsearch
docker update elasticsearch --restart=always
  • 再次查詢分詞結果

可以看到 悟空哥聊架構 被拆分爲 悟空哥架構 三個詞語,說明自定義詞庫中的 悟空哥 有作用。

自定義詞庫後的分詞結果

寫了兩本 PDF,回覆 分佈式 或 PDF 下載。
我的 JVM 專欄已上架,回覆 JVM 領取。
個人網站:www.passjava.cn

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