Metadata-Version: 2.4
Name: trad-zh-search
Version: 0.1.0
Summary: Traditional Chinese text preprocessing for search engines — CKIP segmentation + bigram indexing with pluggable domain dictionaries
Project-URL: Homepage, https://github.com/notoriouslab/trad-zh-search
Project-URL: Repository, https://github.com/notoriouslab/trad-zh-search
Author: JacobMei
License-Expression: MIT
Keywords: bigram,ckip,meilisearch,nlp,search,tokenizer,traditional-chinese
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Text Processing :: Linguistic
Requires-Python: >=3.9
Requires-Dist: pyyaml>=6.0
Provides-Extra: ckip
Requires-Dist: ckip-transformers>=0.3.2; extra == 'ckip'
Provides-Extra: dev
Requires-Dist: pytest-cov>=4.0; extra == 'dev'
Requires-Dist: pytest>=7.0; extra == 'dev'
Description-Content-Type: text/markdown

# trad-zh-search

搜尋引擎無關的繁體中文文本預處理工具——CKIP 分詞 + bigram 索引生成，附可插拔的領域字典系統。

**需要 Python 3.9+** · 屬於 [notoriouslab](https://github.com/notoriouslab) 開源工具組的一員。

> [English README](README.en.md)

---

## 為什麼需要這個工具

主流搜尋引擎（Meilisearch、Elasticsearch、SQLite FTS5）的中文支援大多依賴 jieba（簡體中文訓練），對繁體中文分詞品質差——「稱義」「靈恩」「聖靈充滿」這類術語切不好，簡繁正規化更不可靠。

trad-zh-search 從一個 8,000+ 篇繁體中文文章搜尋系統的實戰經驗提取，把核心預處理方案包裝成通用工具：

| 特色 | 說明 |
|------|------|
| CKIP 分詞 | ckip-transformers（albert-tiny），比 jieba 更適合繁體中文 |
| Bigram 索引 | CJK 字符滑動窗口 bigram，確保子字串都能搜到 |
| 可選 CKIP | 沒裝 CKIP 時自動退回 bigram-only，降級但可用 |
| 領域字典 | YAML 格式，可插拔。首發基督教繁中字典（1,394 自訂詞） |
| 自動建字典 | 丟一批文件進去，CKIP NER 自動提取專有名詞 |
| Meilisearch Adapter | TokenResult → 多欄位文件格式，一行搞定 |

---

## 快速開始

```bash
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](https://huggingface.co/docs/transformers/installation#offline-mode)。
>
> 不裝 CKIP 也能用——自動退回 bigram-only 模式，仍比 jieba 更適合繁體中文。

### 三行程式碼

```python
from trad_zh_search import tokenize

result = tokenize("轉型正義委員會的調查報告")
print(result.bigrams)   # ['轉型', '型正', '正義', '義委', '委員', '員會', '會的', '的調', '調查', '查報', '報告']
print(result.tokens)    # CKIP 分詞結果（有裝 CKIP 時）
print(result.used_ckip) # True / False
```

### 搭配領域字典

```python
from trad_zh_search import tokenize, load_dictionary

# 載入內建基督教繁中字典
dict = load_dictionary("christian-zh-hant")
result = tokenize("台北靈糧堂的主日崇拜", dictionary=dict)
# CKIP + 自訂詞合併：「台北靈糧堂」不會被切成「台北/靈糧/堂」
```

### 從文件自動建字典

```python
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")  # 存檔可人工微調
```

### Meilisearch 整合

```python
from trad_zh_search import tokenize, load_dictionary
from trad_zh_search.adapters.meilisearch import to_meilisearch, to_meilisearch_synonyms

dict = load_dictionary("christian-zh-hant")

# 文件預處理
doc = to_meilisearch(
    fields={
        "title": tokenize(title, dictionary=dict),
        "content": tokenize(content, dictionary=dict),
    },
    original={"id": doc_id, "title": title, "content": content},
)
# → {"id": ..., "title": ..., "title_ckip": "...", "title_bigram": "...",
#    "content": ..., "content_ckip": "...", "content_bigram": "...", ...}

# 同義詞設定
synonyms = to_meilisearch_synonyms(dict)
# → {"敬拜": ["崇拜", "主日"], "崇拜": ["敬拜", "主日"], ...}
```

**搜尋建議**：將 `title_ckip`、`title_bigram`、`content_ckip`、`content_bigram` 都加入 `searchableAttributes`。實戰 benchmark 顯示 CKIP 和 bigram 互補——bigram 提供高召回率，CKIP 提供高精確率。

---

## TokenResult

```python
@dataclass
class TokenResult:
    original: str        # 輸入原文（截斷後）
    tokens: list[str]    # CKIP 分詞結果（無 CKIP 時為空 list）
    bigrams: list[str]   # CJK bigrams（永遠產生）
    used_ckip: bool      # 是否使用了 CKIP
```

---

## 字典格式

YAML 格式，三個可選區塊：

```yaml
# 自訂分詞詞庫（Phase 1 核心）
ckip_custom_words:
  - 轉型正義
  - 國家人權委員會

# 別名映射（未來 entity-resolver 用）
aliases:
  人權會: 國家人權委員會

# 同義詞組（adapter 可直接輸出為搜尋引擎 synonyms）
synonyms:
  判決: [裁定, 裁判]
```

---

## API 參考

| 函式 | 說明 |
|------|------|
| `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(dict, path)` | 儲存字典為 YAML |
| `build_dictionary(texts, min_freq?)` | NER 自動提取字典（需要 CKIP） |
| `to_meilisearch(fields, original?)` | TokenResult → Meilisearch 文件格式 |
| `to_meilisearch_synonyms(dict)` | 同義詞 → Meilisearch 雙向格式 |

---

## 授權

MIT
