ちょっと前に見ていたこちらのエントリ。
Solr + kuromoji で単語の切れ方がおかしかったのでガッツリ調べてみた、理由と調べ方その方法を公開します!
http://blog.yoslab.com/entry/2014/09/12/005207
kuromoji のサイトに行くと、トークナイズの処理を分析することができる。
http://blog.yoslab.com/entry/2014/09/12/005207
Atilika Kuromojiのサイトやkuromoji-serverで、Kuromojiのトークナイズの様子がビジュアル化できるようで、へぇ〜と思っていたのですが、最近Lucene Kuromojiで同じことができそうなことに気付き、ちょっとやってみました。
kuromoji-server
http://atilika.org/kuromoji/
※このページで、「Viterbi」を選んで形態素解析する
オリジナルのkuromoji-serverのソースコードを見る限り、
org.atilika.kuromoji.server.KuromojiServer.java
https://github.com/atilika/kuromoji-server/blob/master/src/main/java/org/atilika/kuromoji/server/KuromojiServer.java
Luceneではこのクラス、
GraphvizFormatter
http://lucene.apache.org/core/5_2_1/analyzers-kuromoji/org/apache/lucene/analysis/ja/GraphvizFormatter.html
そしてグラフ化にはこちらを使えばよいみたいです。
Graphviz
http://www.graphviz.org/
使い方は簡単なようなので、さっくりと。
先に、Graphvizをインストールします。自分の環境はUbuntu Linux 14.04 LTSですが、最新版でなくても別にいいので普通にapt-getでGraphvizをインストール。
$ sudo apt-get install graphviz
確認。
$ dot -V dot - graphviz version 2.36.0 (20140111.2315)
はい。
続いて、プログラム側。まずはビルド定義。
build.sbt
name := "lucene-kuromoji-viterbi" version := "0.0.1-SNAPSHOT" scalaVersion := "2.11.7" organization := "org.littlewings" scalacOptions ++= Seq("-Xlint", "-deprecation", "-unchecked", "-feature") updateOptions := updateOptions.value.withCachedResolution(true) libraryDependencies ++= Seq( "org.apache.lucene" % "lucene-analyzers-common" % "5.2.1", "org.apache.lucene" % "lucene-analyzers-kuromoji" % "5.2.1" )
※kuromojiとcommonで分けているのは、あとでちょっと遊ぶからです
ソースコードは短めです。
src/main/scala/org/littlewings/lucene/kuromoji/KuromojiViterbi.scala
package org.littlewings.lucene.kuromoji import scala.language.postfixOps import scala.sys.process._ import java.io.{File, ByteArrayInputStream, StringReader} import java.nio.charset.StandardCharsets import org.apache.lucene.analysis.ja.dict.ConnectionCosts import org.apache.lucene.analysis.ja.{GraphvizFormatter, JapaneseTokenizer} object KuromojiViterbi { def main(args: Array[String]): Unit = { val word = args.toList.headOption.getOrElse("すもももももももものうち") val graphvizFormatter = new GraphvizFormatter(ConnectionCosts.getInstance) val tokenizer = new JapaneseTokenizer(null, true, JapaneseTokenizer.Mode.NORMAL) tokenizer.setReader(new StringReader(word)) tokenizer.setGraphvizFormatter(graphvizFormatter) tokenizer.reset() Iterator.continually(tokenizer.incrementToken()).takeWhile(identity).foreach(_ => ()) tokenizer.end() tokenizer.close() val dotOutput = graphvizFormatter.finish() "dot -Tgif" #< new ByteArrayInputStream(dotOutput.getBytes(StandardCharsets.UTF_8)) #> new File("out.gif") ! } }
ちょっと普段と違うのは、GraphvizFormatterのインスタンスを作成するところと、
val graphvizFormatter = new GraphvizFormatter(ConnectionCosts.getInstance)
JapaneseTokenizerにGraphvizFormatterのインスタンスを設定するところ、
tokenizer.setGraphvizFormatter(graphvizFormatter)
そしてトークナイズが終わったら、GraphvizFormatter#finishを呼び出して結果の文字列を取得するところです。
あとは、インストールしたdotコマンドに渡して画像に変換します。ここは、外部プロセス起動です。
"dot -Tgif" #< new ByteArrayInputStream(dotOutput.getBytes(StandardCharsets.UTF_8)) #> new File("out.gif") !
今回はGIF画像で、ファイル名は「out.gif」としました。
kuromoji-serverの場合は、SVGで作成してブラウザで表示しているようです。
で、今回のプログラムは形態素解析対象の言葉を起動引数で受け取れるのですが、デフォルトは「すもももももももものうち」としているので、
val word = args.toList.headOption.getOrElse("すもももももももものうち")
候補に挙がった単語や、コストなどがわかって良いですね。
ちょっと言葉を変えてみましょう。
> run 関西国際空港に行こう
なかなか面白いですね。こちらもサーバー化したみたいですけど…どうかな…。
今回作成したソースコードは、こちらに置いています。
https://github.com/kazuhira-r/lucene-examples/tree/master/lucene-kuromoji-viterbi