MeCab ソースコードリーディング私的メモ(形態素解析編)
先日、次のエントリーを書きました。
日本語形態素解析の裏側を覗く!MeCab はどのように形態素解析しているか - クックパッド開発者ブログ
このエントリーを書く際に MeCab のソースコードをそれなりに読んだので、記憶が薄れないうちにメモっておきます。とりあえず形態素解析部分です。コスト算出部分は気が向いたら書きます・・・。
勘違いしている箇所もあるかと思うので、気付いたら指摘してもらえると嬉しいです!
形態素解析時の主要クラス
形態素解析時に関連するクラスとして特に意識しないといけないのは以下のクラスかと思います。メソッドも主要なものしか表示していません。
形態素解析時のシーケンス図
主要クラスを把握したら、次は解析の流れです。クラス図のとおり model が viterbi を所有していますが、model()->viterbi()->analyze(lattice)という形で tagger から model 経由で viterbi の analyze メソッドを呼んで lattice に解をセットしています。
比較的複雑な主要メソッド
bool Viterbi::viterbi(Lattice *lattice)
ラティスの構築を行うメソッド。
- begin_node_list: 指定した位置から始まる単語(ノード)を保持するリスト。同じ位置のノードは bnext で繋がっている。
- end_node_list: 指定した位置で終わる単語(ノード)を保持するリスト。同じ位置のノードは enext で繋がっている。
template <bool IsAllPath> bool connect(size_t pos, Node *rnode, …)
viterbi メソッドの中で呼ばれるメソッド。viterbi メソッドで取得した現在位置に対する全ノード (right_node) に対して、一つ手前の全ノードとの連接コストを matrix.bin から取得し、累積コストが最小になる左側のノード (best_node) を rnode->prev に格納しておく。lnode->cost には BOS からの最小累積コストが格納されている。単語の長さに応じて end_node_list に各ノードを格納する。
bool Viterbi::buildBestLattice(Lattice *lattice)
viterbi メソッドで構築したラティスの EOS ノードから prev を辿っていくことで最適パスを求める。prev は connect 関数でセットされた累積コストを最小とする一つ手前のノード。
N *Tokenizer<N, P>::lookup(const char *begin, const char *end, …)
指定された位置に対して候補となる全ての単語を sys.dic とユーザ辞書から取得する。
未知語処理もこのメソッドで行う。未知語のコストは unk.dic に登録されている値を使う。
おまけ 〜 Doxygen によるドキュメント生成〜
EXTRACT_PRIVATE = YES にすると、かなり詳細なクラス図が生成されるのでオススメです。
% brew install doxygen graphviz
% cd /path/to/mecab/mecab/src/
% doxygen -g
% cat <<EOF >> Doxyfile
heredoc> EXTRACT_ALL = YES
heredoc> HAVE_DOT = YES
heredoc> UML_LOOK = YES
heredoc> EXTRACT_PRIVATE = YES
heredoc> EOF
% doxygen
% open html/index.html