Mecabはバインディングで3.1倍速くなる
バインディングのインストール
sudo port install rb-mecab +utf8only
実行例
サンプルとして,Rubyのホームページに載ってるテキストを100回Mecabを通してみます.
require 'Benchmark' text = <<EOT Rubyは、手軽なオブジェクト指向プログラミングを実現するための種々の機能を持つオブジェクト指向スクリプト言語です。本格的なオブジェクト指向言語であるSmalltalk、EiffelやC++などでは大げさに思われるような領域でのオブジェクト指向プログラミングを支援することを目的としています。もちろん通常の手続き型のプログラミングも可能です。 Rubyはテキスト処理関係の能力などに優れ、Perlと同じくらい強力です。さらにシンプルな文法と、例外処理やイテレータなどの機構によって、より分かりやすいプログラミングが出来ます。 まあ、簡単にいえばPerlのような手軽さで「楽しく」オブジェクト指向しようという言語です。どうぞ使ってみてください。 EOT puts Benchmark::measure { 100.times { counter = My::WordCounter.new counter.count2(text) } } puts Benchmark::measure { 100.times { counter = My::WordCounter.new counter.count(text) } }
結果はこんな感じ.
0.670000 0.060000 0.730000 ( 0.732847) # => MeCab::Tagger 0.690000 0.260000 2.300000 ( 2.258337) # => IO.popen
ソース
require 'MeCab' module My class WordCounter MECAB = '/usr/local/bin/mecab' NECESSARY_FEATURE = %w/名詞,固有名詞 名詞,一般 名詞,副詞可能 名詞,サ変接続 名詞,形容動詞語幹 動詞.*五段/ UNNECESSARY_FEATURE = %w/名詞,数 名詞,接尾 名詞,非自立 接頭詞,名詞接続/ def initialize @mecab = MeCab::Tagger.new @result = Hash.new(0) end attr_reader :result # mainループ def count(text) words = split_to_words(text) count_up_result(words) self end def count2(text) words = split_to_words2(text) count_up_result(words) self end # Mecabで単語に分割し,必要な品詞のみ抽出する def split_to_words(text) results = IO.popen(MECAB, 'r+') { |mecab| mecab.puts(text) mecab.close_write mecab.readlines } results.map { |result| necessary?(result) ? result.split.first : nil }.compact end # 単語は全て小文字に変換する def split_to_words2(text) result = [] node = @mecab.parseToNode(text) while node result << node.surface.downcase if necessary?(node.feature) node = node.next end result end # 単語として使うする属性を判断する def necessary?(feature) case feature when Regexp.new(NECESSARY_FEATURE.join('|')) true when Regexp.new(UNNECESSARY_FEATURE.join('|')) false when /名詞/ warn feature false else false end end # 単語数をカウント def count_up_result(words) words.each do |word| @result[word] += 1 end end end end