日本語処理の高速化

分かち書きのプログラムを変更してもあまり速度が変わらない件について、もう少し調べてみた。手元にあった POPFile の履歴から 256 通のサンプルを使って、どこで時間がかかっているのかを Benchmark モジュールを用いて調べてみる。
まず、日本語処理を無効にした場合と有効にした場合とでは、2 倍程度の差が見られた。このことから、日本語処理部分を最適化していくことによる目標は、現在の速度の 2 倍ということになる。
日本語処理のうち、時間がかかっている(通る回数が多い部分)というと、分かち書き処理と、文字コード変換処理あたりか。それぞれの部分でどのくらいの時間がかかっているかを調べると、分かち書きKakasi)処理で全体の約 5%、文字コード変換処理で約 40% 強がかかっていることがわかった。これらをあわせると 45% になるから、日本語処理の大半はこれらの処理にかかっているということになる。
意外だったのは、重いと思っていた分かち書き処理よりも、文字コード変換処理の方が重たい(実に 8 倍以上)ということだ。これでは、分かち書き処理を工夫したところで全体としてはたいして効果がないというのもうなずける(全体の 5% ということは、ここを極限まで最適化したとしても、100/95 ≒ 1.05 で 5% 程度の向上しか見込めないということになる)。それよりも、文字コード変換部分を工夫した方がよっぽど効果があるのかもしれない(もちろん、分かち書きの変更は、速度面だけでなく精度面の向上も期待できるわけだけれど)。
ということで、文字コード変換処理部分の最適化を考えてみた。この処理は大きくわけて、Encode::Guess で文字コードの推測を行う部分と、from_to で実際の変換を行う部分からなる。そして、なんと、前者の推測部分の処理に文字コード変換処理全体の 7 割〜 8 割近くの時間がかかっていた。ここをなんとか速く……とあれこれ試してみたものの、これといって大きなスピードアップはできなかった。
そしてふと、渡された文字列が半角英数字や半角記号のみの場合は何もせずにもどるようにしてみたところ、意外にも大きな効果が現れた。試行錯誤の結果、convert_encoding 関数の最初に


return $string if ( $string =~ /^[\r\n\t\x20-\x7e]*$/ );

という処理を加えることによって、なんと、文字コード変換処理部分の処理時間が約 1/10 に短縮されてしまった。メールヘッダや英文のメールはほとんどすべて上記に該当するだろうからその影響が大きかったということだろうか。日本語で書かれた長いメールなんかだと、よけいな処理が増えた分逆に遅くなってしまうということも考えられるだろうけれど、サンプルに選んだ 256 通のメールで試した限りでは(単純な割には)大きな効果があった(全体の 4 割強の時間がかかっていた処理が、1 割弱にまで短縮されたのだからその効果は大きいだろう。同時に、分かち書き処理にかかっていた時間に近づいたことから、この状態からならば、分かち書き処理変更による効果も(割合では)大きくなるはずだ)。
特に副作用などはないだろうと思うけれど、もう少し調べてみて、問題なさそうであれば MeCab パッチにマージして公開したいと思う(イメージは、分かち書きのデフォルトは Kakasi で、Windowsインストーラでは従前通り Kakasi をインストール。MeCab インストーラはオプションで。切り替えは詳細設定タブから、という感じ)。
速度面はだいたいの傾向はつかめてきたような感じなので、次は精度比較かな。差がわかるような調査方法(しかも、面倒でないもの)がないか考え中。