可單獨搭配主流搜尋引擎,專門給繁體中文使用的繁體中文文本預處理工具 —— CKIP 分詞 + bigram 索引生成,附可選擇的領域字典系統。
需要 Python 3.9+ · 屬於 notoriouslab 開源工具組的一員。
你的文本 → trad-zh-search → 搜尋引擎(Meilisearch / MiniSearch / Elasticsearch / ...)
| 元件 | 是什麼 | 需要裝嗎 |
|---|---|---|
| CKIP (ckip-transformers) | 中研院開發的繁體中文 NLP 工具,用 Transformer 模型做分詞 | 選裝(pip install trad-zh-search[ckip]) |
| albert-tiny | CKIP 用的分詞模型,只有 ~50MB,CPU 就能跑 | 隨 CKIP 自動下載 |
| Bigram | 把中文字兩兩組合(「聖靈」→「聖靈」「靈充」「充滿」),確保搜尋不漏 | 內建,不需要額外安裝 |
| 領域字典 | YAML 格式的專有名詞表,告訴分詞器哪些詞不要拆開 | 內建基督教繁中字典,也可自己建 |
| PyYAML | 讀寫 YAML | 自動安裝 |
最小安裝只需要 PyYAML(幾 KB),就能用 bigram 模式。加裝 CKIP 會多 PyTorch(~700MB)+ 模型(~50MB),但分詞品質大幅提升。
主流搜尋引擎(Meilisearch、Elasticsearch、SQLite FTS5)的中文支援大多依賴 jieba(簡體中文訓練),對繁體中文分詞品質差,這問題已經很多年了,但沒有一個很好的解決方案,我最近整理了一些文章,在過程中陸續找出了適合自己的解法,提供出來給大家參考使用。
先看看實際差異:
| 原文 | jieba 分詞 | CKIP + 自訂字典 |
|---|---|---|
| 聖靈充滿的經歷 | 聖靈 / 充滿 / 的 / 經歷 | 聖靈充滿 / 的 / 經歷 |
| 因信稱義的教義 | 因信 / 稱義的 / 教義 | 因信稱義 / 的 / 教義 |
| 台北靈糧堂的主日崇拜 | 台北 / 靈糧堂 / 的 / 主日 / 崇拜 | 台北靈糧堂 / 的 / 主日崇拜 |
| 靈糧教牧宣教神學院 | 靈糧 / 教牧 / 宣教 / 神學院 | 靈糧教牧宣教神學院 |
jieba 把「稱義的」黏在一起、「聖靈充滿」拆成兩個詞、機構名全部切碎,CKIP + 自訂字典都能正確處理。
在一個 8,000+ 篇繁體中文文章的搜尋系統上實測(80 組 benchmark query):
- CKIP 分詞 + bigram:Top-1 搜尋結果有 21% 的查詢獲得改善(17/80 好轉,3/80 變差)
- albert-tiny 模型 vs bert-base:分詞結果完全一致,但速度快 4 倍、模型小 10 倍
- 自訂字典(915 詞):機構名、人名不再被拆開,搜「靈糧教牧宣教神學院」直接命中
| 特色 | 說明 |
|---|---|
| CKIP 分詞 | ckip-transformers(albert-tiny),繁體中文專用 |
| Bigram 索引 | CJK 字符滑動窗口 bigram,確保子字串都能搜到 |
| 可選 CKIP | 沒裝 CKIP 時自動退回 bigram-only——tokens 回空 list、used_ckip 為 False,bigram 照常產生 |
| 領域字典 | YAML 格式,可插拔。首發基督教繁中字典(915 自訂詞) |
| 自動建字典 | 丟一批文件進去,CKIP NER 自動提取專有名詞 |
| Meilisearch Adapter | TokenResult → 多欄位文件格式,一行搞定 |
| MiniSearch Adapter | 靜態網站客戶端搜尋,build time 建索引、瀏覽器直接用 |
| Stop-bigrams | 內建 102 個繁中虛詞 bigram 過濾表,提升搜尋精準度 |
pip install trad-zh-search
# (選裝)CKIP 分詞支援
pip install trad-zh-search[ckip]CKIP 安裝須知
trad-zh-search[ckip]會一併安裝 PyTorch(約 700MB+),這是 ckip-transformers 的底層依賴。 首次呼叫tokenize()時會自動從 HuggingFace 下載 albert-tiny 模型(約 50MB),需要對外網路。 離線環境請參考 HuggingFace offline mode。不裝 CKIP 也能用——自動退回 bigram-only 模式,仍比 jieba 更適合繁體中文。
from trad_zh_search import tokenize
result = tokenize("轉型正義委員會的調查報告")
print(result.bigrams) # ['轉型', '型正', '正義', '義委', '委員', '員會', '會的', '的調', '調查', '查報', '報告']
print(result.tokens) # CKIP 分詞結果(有裝 CKIP 時)
print(result.used_ckip) # True / Falsefrom trad_zh_search import tokenize, load_dictionary
# 載入內建基督教繁中字典
ck_dict = load_dictionary("christian-zh-hant")
result = tokenize("台北靈糧堂的主日崇拜", dictionary=ck_dict)
# CKIP + 自訂詞合併:「台北靈糧堂」不會被切成「台北/靈糧/堂」from trad_zh_search import build_dictionary, save_dictionary
# 丟一批文本 → CKIP NER 提取專有名詞 → 產生字典
texts = [open(f).read() for f in my_articles]
my_dict = build_dictionary(texts, min_freq=2)
save_dictionary(my_dict, "my_domain.yaml") # 存檔可人工微調from trad_zh_search import tokenize, load_dictionary
from trad_zh_search.adapters.meilisearch import to_meilisearch, to_meilisearch_synonyms
ck_dict = load_dictionary("christian-zh-hant")
# 文件預處理
doc = to_meilisearch(
fields={
"title": tokenize(title, dictionary=ck_dict),
"content": tokenize(content, dictionary=ck_dict),
},
original={"id": doc_id, "title": title, "content": content},
)
# → {"id": ..., "title": ..., "title_ckip": "...", "title_bigram": "...",
# "content": ..., "content_ckip": "...", "content_bigram": "...", ...}
# 同義詞設定
synonyms = to_meilisearch_synonyms(ck_dict)
# → {"敬拜": ["崇拜", "主日"], "崇拜": ["敬拜", "主日"], ...}搜尋建議:將以下欄位依序加入 searchableAttributes(順序即權重,越前面越重要):
title_ckip → title_bigram → content_ckip → content_bigram
實戰 benchmark 顯示 CKIP 和 bigram 互補——CKIP 提供精確的詞邊界匹配,bigram 確保不漏掉子字串。
v0.2 新增 — 適用於所有靜態網站(Astro、Hugo、Next.js SSG、11ty 等)搭配 GitHub Pages / Cloudflare Pages / Vercel 部署。
MiniSearch 是輕量的客戶端搜尋引擎,支援序列化索引。搭配 trad-zh-search 的 build-time 分詞,靜態網站也能有高品質的繁中搜尋。
架構:
Build time (Python): 文章內容 → tokenize() → to_minisearch() → JSON
Build time (Node.js): JSON → MiniSearch.addAll() + toJSON() → 序列化索引
Runtime (瀏覽器): fetch 索引 → MiniSearch.loadJSON() → 即時搜尋
Python 端(build time):
from trad_zh_search import tokenize
from trad_zh_search.adapters.minisearch import to_minisearch
doc = to_minisearch(
fields={
"title": tokenize(title),
"content": tokenize(content),
},
original={"id": doc_id, "title": title, "url": url},
)
# → {"id": ..., "title": ..., "title_bigram": "台灣 灣人 人權 ...",
# "content_bigram": "...", ...}查詢端過濾虛詞:
from trad_zh_search.adapters.minisearch import filter_stop_bigrams
bigrams = ["中文", "文工", "工具", "具可", "可以", "搜尋"]
filtered = filter_stop_bigrams(bigrams)
# ["中文", "文工", "工具", "具可", "搜尋"] ("可以" 被過濾)JavaScript 端:MiniSearch 的 tokenize 設為空格分割(因為 bigram 已預處理),查詢端用 CJK bigram 分詞即可。完整範例請參考 jacobmei.com 的搜尋實作。
@dataclass
class TokenResult:
original: str # 輸入原文(截斷後)
tokens: list[str] # CKIP 分詞結果(無 CKIP 時為空 list)
bigrams: list[str] # CJK bigrams(永遠產生)
used_ckip: bool # 是否使用了 CKIPYAML 格式,三個可選區塊:
# 自訂分詞詞庫(Phase 1 核心)
ckip_custom_words:
- 轉型正義
- 國家人權委員會
# 別名映射(目前供參考,未來 entity-resolver 會使用)
aliases:
人權會: 國家人權委員會
# 同義詞組(adapter 可直接輸出為搜尋引擎 synonyms)
synonyms:
判決: [裁定, 裁判]內建的 christian-zh-hant 字典包含部分知名牧師、神學家、聖經人物及歷史人物的姓名,均來自各教會公開網站及公開出版物。若當事人希望移除,請開 issue 告知,我們會盡速處理。
| 函式 | 說明 |
|---|---|
tokenize(text, dictionary?, max_chars?) |
分詞 + bigram,回傳 TokenResult |
tokenize_batch(texts, dictionary?, batch_size?) |
批次版本 |
load_dictionary(name) |
載入內建字典 |
load_dictionary_file(path) |
載入 YAML 字典檔 |
merge_dictionaries(*dicts) |
合併多個字典 |
save_dictionary(dictionary, path) |
儲存字典為 YAML(原子寫入) |
build_dictionary(texts, min_freq?) |
NER 自動提取字典(需要 CKIP) |
to_meilisearch(fields, original?) |
TokenResult → Meilisearch 文件格式 |
to_meilisearch_batch(fields_list, originals?) |
批次版本 |
to_meilisearch_synonyms(dictionary) |
同義詞 → Meilisearch 雙向格式 |
to_minisearch(fields, original?) |
TokenResult → MiniSearch 文件格式(含 Latin 詞自動提取) |
to_minisearch_batch(fields_list, originals?) |
批次版本 |
filter_stop_bigrams(bigrams) |
過濾查詢中的虛詞 bigram |
STOP_BIGRAMS |
內建繁中虛詞 bigram 集合(frozenset) |
詳細參數說明請參考各函式的 docstring。
以下是規劃中但尚未實作的功能:
| Adapter | 狀態 | 說明 |
|---|---|---|
| Meilisearch | v0.1 已完成 | 多欄位格式 + 同義詞轉換 |
| MiniSearch | v0.2 已完成 | 靜態網站客戶端搜尋 + stop-bigrams |
| Elasticsearch / OpenSearch | 規劃中 | _analyze 自訂分析器 + mapping 生成 |
| SQLite FTS5 | 規劃中 | trigram tokenizer + 自訂 tokenize 函式 |
| Typesense | 考慮中 | 另一個熱門的開源搜尋引擎 |
| 功能 | 狀態 | 說明 |
|---|---|---|
| Entity Resolver(別名展開) | 規劃中 | 搜「周牧師」自動展開為「周神助 OR 周巽正」 |
| Synonym Expander | 規劃中 | 搜「宣教」自動展開為「宣教 OR 差傳 OR 宣植」 |
| 簡繁正規化 | 考慮中 | 輸入簡體自動轉繁體再分詞(opencc s2twp) |
| 停用詞過濾 | v0.2 部分完成 | 內建 stop-bigrams(102 個繁中虛詞),完整停用詞表規劃中 |
| 功能 | 狀態 | 說明 |
|---|---|---|
| CLI 工具 | 規劃中 | trad-zh-search tokenize "你的文本" 命令列直接用 |
| 更多領域字典 | 歡迎貢獻 | 法律、醫療、教育... |
| 字典品質報告 | 考慮中 | 分析字典覆蓋率、衝突、冗餘 |
有想法或需求?歡迎開 issue 討論。
歡迎貢獻領域字典、回報 bug、或提交 PR。詳見 CONTRIBUTING.md。
MIT