アーキテクチャ
モジュール構成
lindera-analysis/src/
├── lib.rs # パブリックAPIの再エクスポート、CLIフラグ解析ヘルパー
├── character_filter.rs # CharacterFilter trait、OffsetMapping、CharacterFilterLoader
├── character_filter/
│ ├── unicode_normalize.rs # Unicode正規化(NFC/NFD/NFKC/NFKD)
│ ├── japanese_iteration_mark.rs # 日本語の踊り字(繰り返し記号)正規化
│ ├── mapping.rs # マッピングによるテキスト置換
│ └── regex.rs # 正規表現によるテキスト置換
├── token_filter.rs # TokenFilter trait、TokenFilterLoader
├── token_filter/
│ ├── japanese_base_form.rs
│ ├── japanese_compound_word.rs
│ ├── japanese_kana.rs
│ ├── japanese_katakana_stem.rs
│ ├── japanese_keep_tags.rs
│ ├── japanese_number.rs
│ ├── japanese_reading_form.rs
│ ├── japanese_stop_tags.rs
│ ├── keep_words.rs
│ ├── korean_keep_tags.rs
│ ├── korean_reading_form.rs
│ ├── korean_stop_tags.rs
│ ├── length.rs
│ ├── lowercase.rs
│ ├── mapping.rs
│ ├── remove_diacritical_mark.rs
│ ├── stop_words.rs
│ ├── tags.rs # keep/stop系タグフィルタが共有するヘルパー(非公開)
│ └── uppercase.rs
└── tokenizer.rs # Tokenizer、TokenizerBuilder
主要コンポーネント
CharacterFilter
セグメンテーション前にテキストを前処理するフィルタのtraitです。各実装はname()と、textをその場で書き換えて実施した変換内容をOffsetMappingとして返すapply(&self, text: &mut String) -> LinderaResult<OffsetMapping>を提供します。
OffsetMapping(Transformationレコードのリストから構築される)により、複数のフィルタを順に適用した後でも、Tokenizerはフィルタ後のテキストに対して計算されたトークンのバイトオフセットを、元の入力テキストにおけるバイトオフセットへ変換できます。BoxCharacterFilterは任意のCharacterFilter実装をボックス化・クローン可能なトレイトオブジェクトとしてラップし、CharacterFilterLoaderはkind文字列とserde_json::Valueの引数からフィルタを構築します(YAML設定の読み込みとCLIフラグ解析の両方で利用されます)。
TokenFilter
Segmenterが生成したトークンを後処理するフィルタのtraitです。各実装はname()と、トークンをその場で変換・結合・並べ替え・除去するapply(&self, tokens: &mut Vec<Token<'_>>) -> LinderaResult<()>を提供します。BoxTokenFilterは任意のTokenFilter実装をボックス化・クローン可能なトレイトオブジェクトとしてラップし、TokenFilterLoaderはCharacterFilterLoaderと同様に、kind文字列とserde_json::Valueの引数からフィルタを構築します。
Tokenizer / TokenizerBuilder
Tokenizerは、文字フィルタ、lindera::segmenter::Segmenter、トークンフィルタを1つの解析パイプラインとして組み合わせます。tokenizeを呼び出すと、入力テキストに文字フィルタを適用し、フィルタ後のテキストをセグメンテーションし、得られたトークンにトークンフィルタを適用したうえで、記録済みのOffsetMappingを使って各トークンのバイトオフセットを元のテキストに対する値へ補正します。
TokenizerBuilderはTokenizerConfig(serde_json::Value)からTokenizerを組み立てます。この設定はプログラムから直接構築することも、YAMLファイルから読み込むこと(TokenizerBuilder::from_file、または環境変数LINDERA_CONFIG_PATH経由で自動的に読み込むTokenizerBuilder::new)も、set_segmenter_mode・set_segmenter_dictionary・append_character_filter・append_token_filterで段階的に組み立てることもできます。YAMLファイルの形式は設定を、フィルタの完全なリファレンスはフィルタを参照してください。
AnalysisWorker
AnalysisWorker(Tokenizer::new_workerまたはTokenizer::into_workerで作成)は、解析チェーン全体に対する再利用可能なセッションです。呼び出しごとのバッファ — Viterbiラティスとバックトレース用スクラッチ(SegmentWorker経由)、文字フィルタが操作する正規化テキストバッファ、オフセットマッピング用スクラッチ — をすべて所有するため、tokenizeを繰り返し呼び出してもTokenizer::tokenizeが支払う呼び出しごとのアロケーションを回避できます。文字フィルタが設定されている場合、トークンのsurfaceはトークンごとのStringにコピーされる代わりにワーカーのバッファを借用します。返されるトークンはワーカーを借用するため、次の呼び出しの前に消費する必要があります。マルチスレッドで使う場合はスレッドごとにワーカーを作成してください(あるいはlindera-binding-coreのようにMutexで保護します)。基盤となるSegmentWorkerと自動メモリ縮小ポリシーについてはSegmenterのページを参照してください。
AnalysisWorkerの主なpublicメソッド:
tokenize(&mut self, text: &str)— ワーカーの内部バッファを再利用しながら、解析チェーン全体を通してtextをトークナイズします。同じ入力・設定であればTokenizer::tokenizeとまったく同じトークンを返します。tokenize_nbest(&mut self, text: &str, n, unique, cost_threshold)— ワーカーの内部バッファを再利用しながら、コスト付きの上位N件の結果をトークナイズして返します。Tokenizer::tokenize_nbestとまったく同じ結果を返します。set_mode(&mut self, mode: Mode)— 以降の呼び出しで使用するセグメンテーションモードを設定します。set_keep_whitespace(&mut self, keep: bool)— 以降の呼び出しで空白トークンを出力に残すかどうかを設定します。shrink_to(&mut self, text_len_hint: usize)— ワーカーの内部バッファを、text_len_hintバイトの入力に必要なサイズまで直ちに縮小します。reset(&mut self)— すべての内部バッファを破棄し、新しいバッファに置き換えます。(例えばワーカーを保持するMutexがパニックでpoisonedになった場合の)リカバリ用途を想定しており、設定(辞書・フィルタ・モード)は保持されます。
Feature フラグ
| Feature | 説明 | デフォルト |
|---|---|---|
embed-ipadic | IPADIC辞書をバイナリに埋め込む(lindera/embed-ipadicへ委譲) | No |
embed-ipadic-neologd | IPADIC-NEologd辞書をバイナリに埋め込む(lindera/embed-ipadic-neologdへ委譲) | No |
embed-unidic | UniDic辞書をバイナリに埋め込む(lindera/embed-unidicへ委譲) | No |
embed-sudachidict | SudachiDict辞書をバイナリに埋め込む(lindera/embed-sudachidictへ委譲) | No |
embed-ko-dic | ko-dic辞書をバイナリに埋め込む(lindera/embed-ko-dicへ委譲) | No |
embed-cc-cedict | CC-CEDICT辞書をバイナリに埋め込む(lindera/embed-cc-cedictへ委譲) | No |
embed-jieba | Jieba辞書をバイナリに埋め込む(lindera/embed-jiebaへ委譲) | No |