Elasticsearch 中文同義詞與自動完成
最近幫公司實作自動完成的功能,趁機補了一下相關的基礎知識,寫在這邊跟各位分享,這篇文章提供要使用 Elasticsearch 完成中文同義詞與自動完成所需的最小知識。
專有名詞
其中有幾個概念跟這篇文章比較有關
- document
可以被 index 的最小單位。
- settings
針對某個 index 的 tokenizer、filter、shards、replica…等的設定,可以 update,要先關閉後才能做。
- mappings
定義某個index包含的fields的儲存方式,無法 update,有分靜態和動態,動態是指當有新 field 產生時 Elasticsearch 會嘗試猜測並賦予類型,只支援這幾種類型。
額外要提的是 type
在 7.0 版本之後預設移除,8.0 則不支援,官方說明原因為其設計理念與 Luence 實際儲存資料的方式有衝突:在 RDBMS 的 context 中,table 之間的 column 不會互相影響,而在 Elasticsearch 對 filed 儲存方式是在同個 index 裡面同名稱的 field 吃同樣的 mapping,跟原本想做到的概念相違。
index概念簡介
doc 透過 analyzer 處理後儲存成類似圖中的表,搜尋時用 Inverted index 的方法找出其於表中出現的次數,再去推出要找的doc,如圖中輸入”somethin funny” 查找後發現 “something”跟”funny”都有出現在 doc1 中,因此回傳 doc1 作為搜尋結果。
analyzer概念簡介
analyzer 由三個部分組成由處理順序左到右如圖,只有 text field 才支援analyzer 設定。圖解如下:
輸入字串透過 character filter 把字串的 html tag 去除後經過 whitespace tokenizer 去掉空白字元,最後經過 synonym filter 把同義字替換後再存到Inverted index 中準備提供查詢。
有了 analyzer 的概念後在設定同義詞時會比較明白在設定的到底是什麼。
同義詞
這邊使用 ik 分詞器,比較老牌(出問題比較能找到解)的中文分詞器,搭配自定義的字典檔
以及同義字字庫
就能開始使用,在 analyzer 中是屬於 Tokenizer 的層級。
- 範例
字典檔(custom-dict.txt):讓進去的字不要被切斷,能夠正確被同義字字庫比對。
胃食道逆流
流行性感冒
同義字字庫(synonym.txt)
流感,流行性感冒
胃食道逆流=>胃病
Dockerfile
FROM elasticsearch:7.6.2RUN ./bin/elasticsearch-plugin install -b https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v7.6.2/elasticsearch-analysis-ik-7.6.2.zip
RUN mkdir -p /usr/share/elasticsearch/config/analysis-ik/customCOPY ./dict/custom-dict.txt /usr/share/elasticsearch/config/analysis-ik/custom/custom-dict.dic
COPY ./dict/synonym.txt /usr/share/elasticsearch/config/analysis/synonym.txtUSER elasticsearch
利用上面這些範例可快速在本地建立一個具有 ik 分詞功能的 elasticsearch,接著在設定 mapping 與 setting
設定成功的話測試結果如下
自動完成
官方推薦兩種方式
- Completion Suggester
回應速度很快,但其資料結構因素只能做到prefix completion。
- search-as-you-type (7.2~)
使用 shingle token filter (ngram)當作 base,因此可以做到 infix completion。舊的版本可以用 ngram token filter 達到類似效果。
我最後使用 search-as-you-type,因為這個效果比較符合使用情境,設定步驟如下:
建立 mapping
PUT /<index>
建立 data
測試結果
前端隨便找一套看的順眼的 auto-completion library 套一下就好~這邊延用之前同義字的 analyzer,因為這樣自動完成出來的東西才不會被切的很奇怪。
上面大概說明怎麼快速建立一個具有同義字和自動完成功能的 Elasticsearch node,至於效果好不好得看字庫範圍夠不夠集中且多元,這塊很吃領域知識,這篇文章提供了「有」的部分,要「好」的話還有更多需要做的。