ferretを試してみる + MeCabでTokenize
ferretというRubyのテキスト検索エンジンライブラリを見つけました。
主要部分はCで書かれていて高速なようです。またチュートリアルを見る限りでは簡単に使えそうです。ただ、日本語用のTokenizerは用意されていないようなので、MeCabを利用して簡単なものを作成しながら試してみました。
インストール
% gem install ferret
そのほか、mecab、mecab-ipadic、mecab-rubyが適切にインストールされているとします。
文字コードはUTF-8を用いました。
使用
チュートリアルに従って一通り試してみたところで、MecabAnalyzer、MecabTokenizerを作りました。
ソースは以下の通りです。
#!/usr/bin/ruby -Kurequire ‘rubygems’ require ‘ferret’ require ‘MeCab’ include Ferret
class MecabAnalyzer def initialize(use_surface=false) @use_surface = use_surface end def token_stream(field, str) return MecabTokenizer.new(str, @use_surface) end end
class MecabTokenizer def initialize(str, use_surface=false) @mecab = MeCab::Tagger.new self.text = str @use_surface = use_surface end def text=(str) @text = str @n = @mecab.parseToNode(text) @n = @n.next # skip EOS @pos = 0 end attr_reader :text def next return nil if @n.stat == MeCab::MECAB_EOS_NODE features = @n.feature.split(/,/) t = @use_surface ? @n.surface : features[6] token = Analysis::Token.new(t, @pos, @pos+@n.rlength) @pos += @n.rlength @n = @n.next return token end end
以下、動作確認用のコード。
index = Index::Index.new(:analyzer => MecabAnalyzer.new)index << {:id=>0, :content=>“寒くて我慢できない。”} index << {:id=>1, :content=>“今日は寒い一日になりそうです。\nそんな予感。”} index << {:id=>2, :content=>“今日もしないとね。“}
check tokenizer
mt = MecabTokenizer.new(index[0].load[:content]) while t = mt.next p t end
query = “寒く” puts “query: #{query}” index.search_each(query) do |id,score| p [id, score, index[id].load] puts index.highlight(query, id, :field => :content, :pre_tag => ”[”, :post_tag => ”]”, :excerpt_length => :all) end
実行結果は以下のようになりました。「寒い」と「寒く」が同一視されていることがわかります。
dara@wasabi:~/ferret$ ruby ferret_test.rb token["寒い":0:6:1] token["て":6:9:1] token["我慢":9:15:1] token["できる":15:21:1] token["ない":21:27:1] token["。":27:30:1] query: 寒く [0, 0.0806559845805168, {:content=>"寒くて我慢できない。", :id=>"0"}] [寒く]て我慢できない。 [1, 0.0537706576287746, {:content=>"今日は寒い一日になりそうです。\nそんな予感。", :id=>"1"}] 今日は[寒い]一日になりそうです。 そんな予感。
課題
次の段階としては、品詞に基づいて抽出する単語を任意に選択できるようにしたいところです。しかし、TokenizerとFilterが分離されているため、形態素解析の結果を利用してフィルタを行うためには、
- Tokenizerにフィルタを組み込む
- Tokenを継承したMecabTokenに品詞情報を付加し、MecabToken用のフィルタを用意する
などの工夫が必要になりそうです。とはいえ、ちょっとした応用ならばMecabTokenizer#nextにコチョコチョと書き加えれば済みそうですので、今回はここまでにしておきます。
Cで書いた方がよかろうという話もありますよね。