CLOVER🍀

That was when it all began.

Lucene Kuromojiの辞書を、IPA辞書からNAIST辞書に切り替える

Luceneに同梱されている形態素解析のKuromojiですが、以下の3種類の辞書を取ることができます。

IPA辞書はこちら。
http://mecab.googlecode.com/files/mecab-ipadic-2.7.0-20070801.tar.gz

NAIST辞書はこちら。
http://sourceforge.jp/projects/naist-jdic/

UniDicはこちら。
http://sourceforge.jp/projects/unidic/

で、今回、全パターンを試してみようと思ったのですが、UniDicは使えませんでした。辞書のビルドに失敗します。

ライセンス上の理由で、現在はIPA形式の辞書のみの対応だとか。

Japanese Tokenizer (Kuromoji) cannot build UniDic dictionary
https://issues.apache.org/jira/browse/LUCENE-4056

まあ、今回そこまで頑張る気はないので、UniDicはとりあえずいいかな…。

で、辞書を変えるということはLucene Kuromoji自体をビルドすることになります。

というわけで、まずはLucene 4.5.1のタグをエクスポート。

$ svn export http://svn.apache.org/repos/asf/lucene/dev/tags/lucene_solr_4_5_1/

ちょっと時間がかかりますが、しばし待ちましょう。

なお、この後のビルドにはAntとIvyが必要です。Ivyは「ant ivy-bootstrap」で入るのかもしれませんが、確認する前にAntとIvy合わせちゃいました。

エクスポートできたら、とりあえずLuceneをビルド。Solrはビルドしなくていいですからね。

$ cd lucene_solr_4_5_1/lucene/
$ ant compile

久々にantコマンド実行しましたね〜。依存ライブラリは、Ivyがダウンロードしてきてくれます。

antよろしく、以下のようなメッセージが出ればビルドは成功です。

compile-core:

BUILD SUCCESSFUL
Total time: 1 minute 10 seconds

IPA辞書を使ってビルド

続いて、Kuromojiをビルドしましょう。まずは、普通にIPA辞書を使ってビルド。

$ cd analysis/kuromoji/
$ ant regenerate

この手順では、辞書のみのビルドになります。辞書自体は、Ivyが取得してきてくれます。

途中、こんなのが出たり

[ivy:retrieve] :: resolution report :: resolve 85ms :: artifacts dl 1ms
	---------------------------------------------------------------------
	|                  |            modules            ||   artifacts   |
	|       conf       | number| search|dwnlded|evicted|| number|dwnlded|
	---------------------------------------------------------------------
	|      ipadic      |   1   |   0   |   0   |   0   ||   1   |   0   |
	---------------------------------------------------------------------
[ivy:retrieve] :: retrieving :: org.apache.lucene#analyzers-kuromoji

こういう表示が出ます。

     [java] dictionary format: IPADIC
     [java] input directory: /xxxxx/lucene_solr_4_5_1/lucene/build/analysis/kuromoji/mecab-ipadic-2.7.0-20070801
     [java] output directory: /xxxxx/lucene_solr_4_5_1/lucene/analysis/kuromoji/src/resources
     [java] input encoding: euc-jp
     [java] normalize entries: false
     [java] 
     [java] building tokeninfo dict...
     [java]   parse...
     [java]   sort...
     [java]   encode...
     [java]   53645 nodes, 253185 arcs, 1716191 bytes...   done
     [java] done
     [java] building unknown word dict...done
     [java] building connection costs...done

もちろん、こういう表示が出たらビルド完了です。

BUILD SUCCESSFUL
Total time: 27 seconds

この後、IPA辞書を使ってKuromojiをビルドします。

$ ant jar-core

こんな感じで、JARファイルができあがります。

jar-core:
      [jar] Building jar: /xxxxx/lucene_solr_4_5_1/lucene/build/analysis/kuromoji/lucene-analyzers-kuromoji-4.5.1-SNAPSHOT.jar

BUILD SUCCESSFUL
Total time: 6 seconds

このJARファイルを、どこかに取っておきましょう。というか、これってデフォルトのKuromojiなので、別になくてもいいんですけどね…。

自分は、こんな名前で保存しておきました。

lucene-analyzers-kuromoji-4.5.1-mecab-ipadic.jar

NAIST辞書を使ってビルド

続いて、NAIST辞書を使うようにします。

最初に、前回のビルド結果を削除。

$ ant clean
Buildfile: /xxxxx/lucene_solr_4_5_1/lucene/analysis/kuromoji/build.xml
     [echo] Building analyzers-kuromoji...

clean:
   [delete] Deleting directory /xxxxx/lucene_solr_4_5_1/lucene/build/analysis/kuromoji

BUILD SUCCESSFUL
Total time: 1 second

続いて、Kuromojiのbuild.xmlを修正します。この部分を

  <!-- default configuration: uses mecab-ipadic -->
  <property name="ipadic.type" value="ipadic"/>
  <property name="ipadic.version" value="mecab-ipadic-2.7.0-20070801" />

  <!-- alternative configuration: uses mecab-naist-jdic
  <property name="ipadic.type" value="naist"/>
  <property name="ipadic.version" value="mecab-naist-jdic-0.6.3b-20111013" />
  -->

こうなるように修正します。

  <!-- default configuration: uses mecab-ipadic -->
  <!--
  <property name="ipadic.type" value="ipadic"/>
  <property name="ipadic.version" value="mecab-ipadic-2.7.0-20070801" />
  -->

  <!-- alternative configuration: uses mecab-naist-jdic -->
  <property name="ipadic.type" value="naist"/>
  <property name="ipadic.version" value="mecab-naist-jdic-0.6.3b-20111013" />

要は、コメントアウトを入れ替えただけですね。

では、先ほどと同じ手順を実施。

$ ant regenerate

途中表示。こちらも、辞書はIvyが取得してきてくれます。

[ivy:retrieve] :: resolution report :: resolve 105ms :: artifacts dl 9ms
	---------------------------------------------------------------------
	|                  |            modules            ||   artifacts   |
	|       conf       | number| search|dwnlded|evicted|| number|dwnlded|
	---------------------------------------------------------------------
	|       naist      |   1   |   0   |   0   |   0   ||   1   |   0   |
	---------------------------------------------------------------------
[ivy:retrieve] :: retrieving :: org.apache.lucene#analyzers-kuromoji

同じく。

     [java] dictionary format: IPADIC
     [java] input directory: /xxxxx/lucene_solr_4_5_1/lucene/build/analysis/kuromoji/mecab-naist-jdic-0.6.3b-20111013
     [java] output directory: /xxxxx/lucene_solr_4_5_1/lucene/analysis/kuromoji/src/resources
     [java] input encoding: euc-jp
     [java] normalize entries: false
     [java] 
     [java] building tokeninfo dict...
     [java]   parse...
     [java]   sort...
     [java]   encode...
     [java]   58670 nodes, 289550 arcs, 1974184 bytes...   done
     [java] done
     [java] building unknown word dict...done
     [java] building connection costs...done

以下の表示が見れたら

BUILD SUCCESSFUL
Total time: 41 seconds

Kuromoji本体をビルドします。

$ ant jar-core

JARファイルは、IPA辞書の時と同じところにできるので、取っておくようにしてください。

こちらは、こういう名前にしました。

lucene-analyzers-kuromoji-4.5.1-mecab-naist-jdic.jar

使ってみる

動作確認のため、こんなソースを用意。

build.sbt

name := "lucene-kuromoji-dict"

version := "0.0.1-SNAPSHOT"

scalaVersion := "2.10.3"

organization := "littlewings"

libraryDependencies ++= Seq(
  "org.apache.lucene" % "lucene-core" % "4.5.1",
  "org.apache.lucene" % "lucene-analyzers-common" % "4.5.1"
)

sbtの依存関係には、Kuromojiは含めていません。Kuromojiは、libディレクトリに入れます。

src/main/scala/LuceneKuromojiDict.scala

import org.apache.lucene.analysis.ja.JapaneseAnalyzer
import org.apache.lucene.analysis.tokenattributes.CharTermAttribute
import org.apache.lucene.util.Version

object LuceneKuromojiDict {
  def main(args: Array[String]): Unit = {
    val luceneVersion = Version.LUCENE_45
    val analyzer = new JapaneseAnalyzer(luceneVersion)

    for (text <- Array("すもももももももものうち。",
                       "メガネは顔の一部です。",
                       "日本経済新聞でモバゲーの記事を読んだ。",
                       "Java, Scala, Groovy, Clojure",
                       "LUCENE、SOLR、Lucene, Solr",
                       "アイウエオカキクケコさしすせそABCXYZ123456",
                       "Lucene is a full-featured text search engine library written in Java.",
                       "このComputerは、10回に1回の割合で起動中に青い画面が表示されます。")) {
      println(s"Original[$text]")

      val tokenStream = analyzer.tokenStream("", text)
      val charTermAttribute = tokenStream.addAttribute(classOf[CharTermAttribute])

      tokenStream.reset()

      println {
        Iterator
          .continually(tokenStream)
          .takeWhile(_.incrementToken())
          .map(t => charTermAttribute.toString)
            .mkString("Tokenize[", " ", "]")
      }

      tokenStream.close()

      println()
    }
  }
}

前回の例と、あんまり変わりませんね。

では、まずlibディレクトリにIPA辞書版を入れます。

$ mv lucene-analyzers-kuromoji-4.5.1-mecab-ipadic.jar lib/

実行。

> run
[info] Running LuceneKuromojiDict 
Original[すもももももももものうち。]
Tokenize[すもも もも もも]

Original[メガネは顔の一部です。]
Tokenize[メガネ 顔 一部]

Original[日本経済新聞でモバゲーの記事を読んだ。]
Tokenize[日本 日本経済新聞 経済 新聞 モバゲ 記事 読む]

Original[Java, Scala, Groovy, Clojure]
Tokenize[java scala groovy clojure]

Original[LUCENE、SOLR、Lucene, Solr]
Tokenize[lucene solr lucene solr]

Original[アイウエオカキクケコさしすせそABCXYZ123456]
Tokenize[アイウエオカキクケコ しす そ abcxyz 123456]

Original[Lucene is a full-featured text search engine library written in Java.]
Tokenize[lucene is a full featured text search engine library written in java]

Original[このComputerは、10回に1回の割合で起動中に青い画面が表示されます。]
Tokenize[computer 101 回 割合 起動 中 青い 画面 表示]

[success] Total time: 1 s, completed 2013/11/16 1:41:50

こういう結果になりました。

続いて、IPA辞書版を退避して

$ mv lib/lucene-analyzers-kuromoji-4.5.1-mecab-ipadic.jar ./.

NAIST辞書版と入れ替え。

$ mv lucene-analyzers-kuromoji-4.5.1-mecab-naist-jdic.jar lib/

実行。

> run
[info] Running LuceneKuromojiDict 
Original[すもももももももものうち。]
Tokenize[すもも もも もも]

Original[メガネは顔の一部です。]
Tokenize[メガネ 顔 一部]

Original[日本経済新聞でモバゲーの記事を読んだ。]
Tokenize[日本 日本経済新聞 経済 新聞 モバゲ 記事 読む]

Original[Java, Scala, Groovy, Clojure]
Tokenize[java scala groovy clojure]

Original[LUCENE、SOLR、Lucene, Solr]
Tokenize[lucene solr lucene solr]

Original[アイウエオカキクケコさしすせそABCXYZ123456]
Tokenize[アイウエオカキクケコ しす そ abcxyz 1 2 3 4 5 6]

Original[Lucene is a full-featured text search engine library written in Java.]
Tokenize[lucene i s a full featured text search engine library written i n java]

Original[このComputerは、10回に1回の割合で起動中に青い画面が表示されます。]
Tokenize[computer 1 01 回 割合 起動 中 青い 画面 表示]

[success] Total time: 1 s, completed 2013/11/16 1:43:13

パッと見たところ、変わりはないように見えますが、よくよく見ると

### IPA版
Original[アイウエオカキクケコさしすせそABCXYZ123456]
Tokenize[アイウエオカキクケコ しす そ abcxyz 123456]
### NAIST版
Original[アイウエオカキクケコさしすせそABCXYZ123456]
Tokenize[アイウエオカキクケコ しす そ abcxyz 1 2 3 4 5 6]


### IPA版
Original[Lucene is a full-featured text search engine library written in Java.]
Tokenize[lucene is a full featured text search engine library written in java]
### NAIST版
Original[Lucene is a full-featured text search engine library written in Java.]
Tokenize[lucene i s a full featured text search engine library written i n java]


### IPA版
Original[このComputerは、10回に1回の割合で起動中に青い画面が表示されます。]
Tokenize[computer 10 回 1 回 割合 起動 中 青い 画面 表示]
### NAIST版
Original[このComputerは、10回に1回の割合で起動中に青い画面が表示されます。]
Tokenize[computer 1 0 回 1 回 割合 起動 中 青い 画面 表示]

が異なります。NAIST版は、アルファベットと数字の扱いが違いますね。分解しちゃうというか、ものによっては半角フィルタをかけているはずなのに、全角のままだったりします。

辞書を変えるだけで動きが変わることを、自分で確認できましたね。

形態素解析の辞書って、何を選ぶのがいいんでしょ?