アーキテクチャ
モジュール構成
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/
│ ├── compound.rs # 複合語フィルタが共有する結合ヘルパー(非公開)
│ ├── 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_compound_word.rs
│ ├── korean_decompound.rs
│ ├── korean_keep_tags.rs
│ ├── korean_number.rs
│ ├── korean_reading_form.rs
│ ├── korean_stop_tags.rs
│ ├── length.rs
│ ├── lowercase.rs
│ ├── mapping.rs
│ ├── numeral.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ファイルの形式は設定を、フィルタの完全なリファレンスはフィルタを参照してください。
TokenizerBuilder::buildは、設定が指す辞書を読み込みます。TokenizerBuilder::build_with_dictionaries(とTokenizer::from_config_with_dictionaries)は、代わりにバイト列から読み込んだ辞書などの読み込み済みの辞書を受け取り、フィルタを含む設定のほかの項目をすべてその辞書に適用します。渡した辞書が設定の辞書をどう置き換えるかはConfig からの構築を参照してください。WASMバインディングのTokenizerBuilderは、setDictionaryInstance()とsetUserDictionaryInstance()で設定した辞書を渡して、この方法でトークナイザーをビルドします。
AnalysisWorker
AnalysisWorker(Tokenizer::new_workerまたはTokenizer::into_workerで作成)は、解析チェーン全体に対する再利用可能なセッションです。呼び出しごとのバッファ — Viterbiラティスとバックトレース用スクラッチ(SegmentWorker経由)、文字フィルタが操作する正規化テキストバッファ、オフセットマッピング用スクラッチ — をすべて所有するため、tokenizeを繰り返し呼び出してもTokenizer::tokenizeが支払う呼び出しごとのアロケーションを回避できます。文字フィルタが設定されている場合、トークンのsurfaceはトークンごとのStringにコピーされる代わりにワーカーのバッファを借用します。返されるトークンはワーカーを借用するため、次の呼び出しの前に消費する必要があります。マルチスレッドで使う場合はスレッドごとにワーカーを作成してください(あるいはlindera-bindingのように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)— 以降の呼び出しで空白トークンを出力に残すかどうかを設定します。残した空白はラティスにも残るため、他のトークンも変わることがあります。set_skip_whitespace(&mut self, skip: bool)— 空白トークンを残さないとき、以降の呼び出しで空白をラティス上で読み飛ばすかどうかを設定します(デフォルトは辞書の設定)。set_max_grouping_len(&mut self, max_grouping_len: Option<usize>)・set_unknown_word_ladder(&mut self, unknown_word_ladder: bool)— 以降の呼び出しで使う未知語グルーピングの上限と候補ラダーを設定します。set_space_penalty(&mut self, space_penalty: Option<SpacePenaltyConfig>)・set_space_penalty_from_dictionary(&mut self)— 以降の呼び出しで使う左側空白ペナルティのルールを設定するか、辞書のルールに戻します。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 |