2015年4月28日火曜日

Mroongaを使ったタグクラウドの作り方

Mroongaを使って全文検索を導入した。
レスポンスが早くなった気がするので満足。

http://www.direc.biz/search?q=%E8%AA%BF%E6%9F%BB

しかし該当箇所を強調するためのsnippet機能は使えなかった


MronngaのトークナイザーにはMecabを使った。Mecabを使って文字列を形態素解析で
単語に分解できる。この機能を使って登録済みのテキストから自動でタグクラウドを作る仕組みを紹介。



単語への分解


DBに保存した文字列をMroongaを通してMecabで形態素解析にかけるには下記のようなSQLを実行する。

mysql> SELECT mroonga_command("tokenize TokenMecab '我思う故に我あり'");
+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| mroonga_command("tokenize TokenMecab '我思う故に我あり'") |
+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| [{"value":"我","position":0},{"value":"思う","position":1},{"value":"故","position":2},{"value":"に","position":3},{"value":"我","position":4},{"value":"あり","position":5}] |
+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.07 sec)


Mroongaのmroonga_commandはgroongaのコマンドを呼び出しているので実際は、

ruby(Rails) → Mroonga → Groonga → Mecab

という流れ。


上記で「我思う故に我あり」になっている部分にテーブルに入ったデータを入れれたらいいのだが、できない見たいなので
いったんselectしてからmroonga_commandの実行のために再度SQLを呼び出する形に。


結果をrubyで処理


Mecabは形態素解析の結果をjsonで返すが、
mroonga_commandをActiveRecordを通して実行した結果をrubyに格納すると、文字化けていた。


irb(main):022:0> dum = SitesMroonga.connection.execute %! SELECT mroonga_command("tokenize TokenMecab '我思う故に我あり'")!
(23.1ms) SELECT mroonga_command("tokenize TokenMecab '我思う故に我あり'")
=> #
irb(main):023:0> dum.first.first
=> "[{\"value\":\"\xE6\x88\x91\",\"position\":0},{\"value\":\"\xE6\x80\x9D\xE3\x81\x86\",\"position\":1},{\"value\":\"\xE6\x95\x85\",\"position\":2},{\"valu"


これではこの後処理できない。どうしたものかと結構なやんだがエンコードをUTF-8として読み込めば大丈夫だった。


irb(main):026:0> JSON.parse dum.first.first.force_encoding( "UTF-8" )
=> [{"value"=>"我", "position"=>0}, {"value"=>"思う", "position"=>1}, {"value"=>"故", "position"=>2}, {"value"=>"に", "position"=>3}, {"value"=>"我", "posiあり", "position"=>5}]


形態素解析の結果のjsonをパースし、Hashとしてrubyで読み込めた。


名詞以外を除去


形態素解析の結果は名詞だけではなく、助詞なども含まれるのでこのままでは「は」や「だが」などが出現回数の上位を占める。
「は」や「や」が並ぶタグクラウド見ても ? である。
なので、簡単なフィルタを作ってそれらを除去した。



NOT_NOUNS = %w(

いかに
いる

おり

かしら
かも
から

ください
くらい
けれど

こそ
こと
ことよ

さえ

しか
する


たい
たり
だけ
だに
だの
ため
つつ

です
ても
てよ

# 一部省略
)


# -------------------------------------------------------------
# 文章より以下のルールに従って、タグの候補を抽出する
# ・名詞のみ
# ・3回以上でてくる
# -------------------------------------------------------------
def tag_candidates
wards = self.tokenize
wards = wards.reject{ |w| NOT_NOUNS.include? w }

ret = []
wards.dup.uniq.each do | w |
if wards.count( w ) >= 3
unless [
Moji::HAN_ASYMBOL,
Moji::HAN_JSYMBOL,
Moji::ZEN_ASYMBOL,
Moji::ZEN_JSYMBOL,
].include? Moji.type( w )
ret << w end end end ret end


NOT_NOUNSに助詞など、結果から省く単語を配列で入れておく。
また、?(クエスチョンマーク)などの記号や句読点なども1単語になるためこのままでは結果に含まれてしまう。

mojiを使えば単語が記号かどうかを判定できる。これを使い記号の場合は除外する。


残った単語をタグとしてidと紐付けてテーブルに保存すれば準備よし。あとはテーブルから出てくる回数の多い順に単語をとってくればタグクラウドのできあがり♪

0 件のコメント:

コメントを投稿