type
status
date
slug
summary
tags
category
icon
password
什麼是分詞?為什麼需要分詞器?
搜尋引擎的目的是用來文本搜尋,為了更高效率的搜尋需要建立倒排索引,而建立倒排索引就需要分詞這個動作,將文本切分成一個一個的單詞並進行一些額外加工來建立高效的索引。

Analyzer 分詞器
一個 analyzer 由以下三部分組成:
- 0...N 個 Character Filters:對輸入的 text 進行預處理。
- 1 個 Tokenizer:進行分詞。
- 0...N 個 Token Filters:對分詞後的結果加工。

下圖展示了 analyzer 為一個文本建立索引的過程:

Character Filters
在將 text 傳遞給 Tokenizer 之前,會先交由 Character Filter 進行預處理。例如:去除 HTML 標籤、字串替換......等。
Elasticsearch 提供以下內建的 Character Filter:
- HTML Strip Character Filter:去除 text 中的 HTML 標籤,並使用解碼值取代 HTML 實體。
- Mapping Character Filter:將符合設定的字串替換成別的字串。
- Pattern Replace Character Filter:透過正則表達式進行替換。
Tokenizer
接收來自 Character Filter 處理後的結果,並將其切分為一個一個 terms/tokens (通常是一個單詞)。例如:Time is money 會被切分為 [ Time, is, money ]。
Tokenizer 除了進行切分,同時還會記錄以下資訊:
- position:紀錄 terms/tokens 所在的位置順序,用於 phrase 和 word proximity Query。
- start_offset、end_offset:紀錄 terms/tokens 的開始和結束位置,用於 highlight 搜尋結果。
- type:紀錄 token type 。
Token Filters
接收來自 Tokenizer 的產出的 terms/tokens 並進行調整,例如:轉小寫、刪除 stopwords (停用詞)、添加 synonyms (同義詞)。
以下範例為轉小寫的 Token filter:
中文分詞
難點
英文本身以單詞為單位,單詞與單詞之間通常是空格、逗號和句號分隔,因此對與英文來說可以很簡單的進行分詞,例如以下例子:

可以看到分出了 time、is、money 這三個分詞來建立實用的索引。
但不同的是中文是以字為單位,再由多個字組成一個單詞,單詞則會連貫在一起組成句子,因此並不適用於英文的分詞方式,也因為這樣如果不使用為中文設計的分詞器,則會使用
一元切分法
也就是一個字單獨做為一個索引,例如以下例子:
上述例子中一個字做為一個單獨的索引,但使用者很可能是用
時間
這個單詞去搜尋,因此上述的例子查詢效率並不是很好(但適用於各種語言),因此還有一種是固定將多個字視為一個單詞-- Lucene 提供的 CJKAnalyzer:這是一個
二元切分法
的分詞器,例如:時間就是金錢,這個例子會被切分為 時間、間就、就是、是金、金錢。

- MySQL 全文檢索中的 N-gram:透過
ngram_token_size
參數來決定將幾個字視為一個單詞,因此預設值 2 就等同於上方介紹的二元切分法
,假設將其設為 3 則時間就是金錢,這個例子會被切分為 時間就、間就是、就是金、是金錢。
雖然相較於
一元切分法
好了點,但還是會有許多不適用的索引,因此就有了其他專門針對中文處理的分詞器被設計出來,而我們使用搜尋引擎的時候就會需要這些中文分詞器的幫助。Lucene 核心 analyzer 插件
SmartCN
中英混合的分詞器,該分詞器針對簡體中文有較好的分詞結果,對繁體中文支援不好。
測試(展開查看)
ICU
添加 ICU libraries 擴展對 unicode 支持,並能更好的分析亞洲語言,對於繁體中文分詞來說效果比 SmartCN 好很多。
測試
社群貢獻 analyzer 插件
ik
IK 是社群非常活躍的中文分詞,基本上搜尋中文分詞大部分都會推薦 IK。
不過測試發現 ik 主要也是針對簡體中文的,例如:繁體
金錢
使用 IK 會被拆分為 金
、錢
,只有簡體的 金钱
會被視為一個 token。測試
stconvert
嚴格來說這只是一個 filter,因為 stconvert 不會進行分詞的動作,他只會將字進行繁簡轉換。
測試
jieba
支援繁體中文,但文檔不友善。
在 github 上也有提供對繁體分詞更好的字典。
測試
THULAC
由清華大學自然語言處理與社會人文計算實驗室研製的一套中文詞法分析工具包。
到官方 demo 試用了一下,可以發現就算是繁體中文效果也非常好:

不過看了一下 PRO 版本是需要提交申請書的,所以只能用 Lite 版本將就一下了
Elasticsearch Lite 版本測試結果,雖然沒有 PRO 那麼厲害,但是效果還可以。(展開查看)
安裝步驟如下:
中文方案推薦
簡體中文
基本上推薦直接使用 IK 就可以了,方便使用社群活躍。
繁體中文
因為 IK 對於繁體中文支持不夠,因此需要另尋方案:
- jieba:雖然一樣是中國開發的,但是是有支持繁體分詞的。
- STConvert + IK:先在 char_filter 透過 STConvert 將繁體轉為簡體,再交給 tokenizer IK 來進行分詞,透過這種方式解決 IK 在繁體分詞的不足。
範例(展開查看)
- THULAC:雖然不能使用 PRO 版本,但 Lite 版本也非常不錯了,而且同樣有自訂辭典的功能。
範例(展開查看)
- IK + 自訂繁體辭典:透過 IK 的自訂辭典導入繁體中文詞庫來改善。
- ICU:Lucene 自帶的,對於繁體字來說效果還不錯。
範例(展開查看)
- CJKAnalyzer:直接使用二元切分法,也比使用預設、smartCN 有更好的效果,但會有很多無意義佔用空間的 token。
課外知識
中研院 CKIP Lab 中文詞知識庫小組在 2019/09 的時候開源了專屬於台灣的繁體中文斷詞 ckiptagger ,對於繁體中文斷詞是我目前看到效果最好的,在官方提供的測試數據中準確率也比 jieba-zh_TW 效果更好,可惜的是目前沒有其他人將其變成搜尋引擎的 plugin。
參考
ES+Solr 文檔:
分詞器:
stconvert 相關:
THULAC 相關: