Windows上で形態素解析Sen

有名な形態素解析ソフトであるChaSenJava移植であるSenを必要に迫られてWindowsに入れていたのですが,最近はあんまりメンテされていないらしく(がんばれ,工藤君),いろいろトラブルがあったので後々のために目盛っておきます.
JavaSDKはインストールされてるとします.

環境変数の設定として,コントロールパネル→詳細設定→環境変数で,以下を設定する.

Pathに{Antを展開したフォルダ}\binを追加
ANT_HOMEに{Antを展開したフォルダ}を設定
JAVA_HOMEにjdkがあるフォルダを設定

Senの辞書メンテに必要なApache Antをダウンロード,インストールする.
http://ftp.riken.jp/net/apache/ant/binaries/apache-ant-1.7.1-bin.zip

同じく必要な,ActivePerlをインストールする.
http://www.activestate.com/activeperl/downloads/

そしてSenのバイナリをダウンロード・展開する.
https://sen.dev.java.net/files/documents/1373/31864/sen-1.2.2.1.zip

ActivePerlが勝手に妙な場所にインストールされるので,
{Senのトップディレクトリ}\dic\build.xml
の中の,

  <property name="perl.bin" value="/usr/bin/perl"/>

の行を修正する.私の場合は,

  <property name="perl.bin" value="c:/Perl/bin/perl.exe"/>

としました.

Senを展開したディレクトリの中のdicに移って,antを実行する.

C:\usr\sen-1.2.2.1\dic> ant
(中略)
     [java] [INFO] MkSenDic - total time = 77[ms]

BUILD SUCCESSFUL
Total time: 1 minute 48 seconds

Windowsのパスにスペースが含まれていると誤動作問題が起こるので,
{Senのトップディレクトリ}\bin\sen.bat
を修正.

@%JAVA_HOME%\bin\java -Dsen.home=%SEN_HOME% -classpath %CLASSPATH% StringTaggerDemo ${1+"$@"}
↓
@"%JAVA_HOME%"\bin\java -Dsen.home=%SEN_HOME% -classpath %CLASSPATH% StringTaggerDemo ${1+"$@"}

SEN_HOMEを,senをダウンロードして展開したトップディレクトリに設定する.
そして{Senを展開したディレクトリ}に移って

C:\usr\sen-1.2.2.1>.\bin\sen.bat
C:\usr\sen-1.2.2.1>rem set classpath
C:\usr\sen-1.2.2.1>SET CLASSPATH=C:\usr\sen-1.2.2.1\lib\sen.jar
C:\usr\sen-1.2.2.1>SET CLASSPATH=C:\usr\sen-1.2.2.1\lib\sen.jar;C:\usr\sen-1.2.1\lib\commons-logging.jar
done.
Please input Japanese sentence:
2009/09/13 19:51:50 net.java.sen.Dictionary <init>
情報: token file = C:\usr\sen-1.2.2.1\dic/token.sen
2009/09/13 19:51:50 net.java.sen.Dictionary <init>
情報: time to load posInfo file = 438[ms]
2009/09/13 19:51:50 net.java.sen.Dictionary <init>
情報: double array trie dictionary = C:\usr\sen-1.2.2.1\dic/da.sen
2009/09/13 19:51:50 net.java.sen.util.DoubleArrayTrie load
情報: loading double array trie dict = C:\usr\sen-1.2.2.1\dic/da.sen
2009/09/13 19:51:52 net.java.sen.util.DoubleArrayTrie load
情報: loaded time = 1.156[ms]
2009/09/13 19:51:52 net.java.sen.Dictionary <init>
情報: pos info file = C:\usr\sen-1.2.2.1\dic/posInfo.sen
2009/09/13 19:51:52 net.java.sen.Dictionary <init>
情報: time to load pos info file = 156[ms]
2009/09/13 19:51:52 net.java.sen.Tokenizer loadConnectCost
情報: connection file = C:\usr\sen-1.2.2.1\dic\matrix.sen
2009/09/13 19:51:53 net.java.sen.Tokenizer loadConnectCost
情報: time to load connect cost file = 1407[ms]
すもももももももものうち
すもも  (すもも)        名詞-一般(0,3,3)        スモモ  スモモ
も      (も)    助詞-係助詞(3,4,1)      モ      モ
もも    (もも)  名詞-一般(4,6,2)        モモ    モモ
も      (も)    助詞-係助詞(6,7,1)      モ      モ
もも    (もも)  名詞-一般(7,9,2)        モモ    モモ
の      (の)    助詞-連体化(9,10,1)     ノ      ノ
うち    (うち)  名詞-非自立-副詞可能(10,12,2)   ウチ    ウチ
バッチ ジョブを終了しますか (Y/N)? y

Ok. Senは現在の配布バージョンでは,デフォルトでIPA辞書の2.6.0を取ってくるので,2.7.0を取るように{Senの展開ディレクトリ}\dic\build.xmlを変更.

  <property name="ipadic.version" value="2.6.0"/><property name="ipadic.version" value="2.7.0"/>

辞書を再作成させるために,古い辞書を削除.

rm {Senの展開ディレクトリ}\dic\*.csv
(connect.csvとdic.csvが削除されるはず)

Senの辞書フォルダに移動してantコマンドを実行する.

C:\usr\sen-1.2.2.1\dic>ant
Buildfile: build.xml
(中略)
download:
      [get] Getting: http://chasen.aist-nara.ac.jp/stable/ipadic/ipadic-2.7.0.tr.gz
      [get] To: C:\usr\sen-1.2.2.1\dic\ipadic-2.7.0.tar.gz
melt:
   [gunzip] Expanding C:\usr\sen-1.2.2.1\dic\ipadic-2.7.0.tar.gz to C:\usr\sen-
.2.2.1\dic\ipadic-2.7.0.tar
    [untar] Expanding: C:\usr\sen-1.2.2.1\dic\ipadic-2.7.0.tar into C:\usr\sen-
.2.2.1\dic
   [delete] Deleting: C:\usr\sen-1.2.2.1\dic\ipadic-2.7.0.tar
(中略)
     [java] [ERROR] DictionaryMaker - can't find morpheme type
     [java] [ERROR] DictionaryMaker - input string is here:
     [java] [ERROR] DictionaryMaker - ruleList size=1145
     [java] [ERROR] DictionaryMaker - 動詞,自立,*,*,五段・ラ行,体言接続特殊2,召捕る,
(中略)
     [java] [INFO] MkSenDic - (7/7): building Double-Array (size = 325254) ...
     [java] [INFO] DoubleArrayTrie - save time = 0.812[s]
     [java] [INFO] MkSenDic - total time = 72[ms]

BUILD SUCCESSFUL
Total time: 1 minute 31 seconds

一見,出来たように見えても(というか,激しくエラーが既に出てますが...),エラーが出ます.

C:\usr\sen-1.2.2.1>.\bin\sen.bat
C:\usr\sen-1.2.2.1>rem set classpath
C:\usr\sen-1.2.2.1>SET CLASSPATH=C:\usr\sen-1.2.2.1\lib\sen.jar
C:\usr\sen-1.2.2.1>SET CLASSPATH=C:\usr\sen-1.2.2.1\lib\sen.jar;C:\usr\sen-1.2.2.1\lib\commons-logging.jar
done.
Please input Japanese sentence:
2009/09/13 20:31:10 net.java.sen.Dictionary <init>
情報: token file = C:\usr\sen-1.2.2.1\dic/token.sen
2009/09/13 20:31:10 net.java.sen.Dictionary <init>
情報: time to load posInfo file = 219[ms]
2009/09/13 20:31:10 net.java.sen.Dictionary <init>
情報: double array trie dictionary = C:\usr\sen-1.2.2.1\dic/da.sen
2009/09/13 20:31:10 net.java.sen.util.DoubleArrayTrie load
情報: loading double array trie dict = C:\usr\sen-1.2.2.1\dic/da.sen
2009/09/13 20:31:11 net.java.sen.util.DoubleArrayTrie load
情報: loaded time = 1.204[ms]
2009/09/13 20:31:11 net.java.sen.Dictionary <init>
情報: pos info file = C:\usr\sen-1.2.2.1\dic/posInfo.sen
2009/09/13 20:31:12 net.java.sen.Dictionary <init>
情報: time to load pos info file = 156[ms]
2009/09/13 20:31:12 net.java.sen.Tokenizer loadConnectCost
情報: connection file = C:\usr\sen-1.2.2.1\dic\matrix.sen
2009/09/13 20:31:12 net.java.sen.Tokenizer loadConnectCost
情報: time to load connect cost file = 688[ms]
 すもももももももものうち
java.lang.ArrayIndexOutOfBoundsException: -321
        at net.java.sen.Tokenizer.getCost(Tokenizer.java:172)
        at net.java.sen.Viterbi.calcConnectCost(Viterbi.java:160)
        at net.java.sen.Viterbi.analyze(Viterbi.java:97)
        at net.java.sen.StringTagger.analyze(StringTagger.java:180)
        at StringTaggerDemo.main(StringTaggerDemo.java:42)

仕方がないので,辞書を作り直します.*.csv,*.senを削除してbuild.xmlを修正.

  <property name="ipadic.version" value="2.7.0"/><property name="ipadic.version" value="2.6.0-2.7.0"/>

ダウンロードに行かずに,ローカルを参照するように修正.ipadic-2.7.0のフォルダはコピーして名前をipdadic-2.6.0-2.7.0に変更する.

  <target name="download" depends="prepare-proxy,prepare-archive,prepare-dics0,prepare-dics" unless="ipadic.archive.present">
<!--
    for proxy
    <setproxy socksproxyhost="proxyhost" proxyport="8080" />
-->
    <get src="${ipadic.home}/${ipadic.archive}" dest="${ipadic.archive}" />
  </target><target name="download" depends="prepare-proxy,prepare-archive,prepare-dics0,prepare-dics" unless="ipadic.archive.present">
<!--
    for proxy
    <setproxy socksproxyhost="proxyhost" proxyport="8080" />
    <get src="${ipadic.home}/${ipadic.archive}" dest="${ipadic.archive}" />
-->
  </target>

ipadic-2.6.0の中のdicの中の*.chaをipadic-2.6.0-2.7.0にコピーして,{Senのトップディレクトリ}\dicにてantコマンドを実行してmakeする.

C:\usr\sen-1.2.2.1\dic>ant
Buildfile: build.xml
(中略)
dics0:
     [exec] ipadic-2.6.0-2.7.0/Adj.dic ...
(中略)
     [java] [INFO] MkSenDic - (6/7): writing token...
     [java] [INFO] MkSenDic - key size = 378609
     [java] [INFO] MkSenDic - (7/7): building Double-Array (size = 325579) ...
     [java] [INFO] DoubleArrayTrie - save time = 0.797[s]
     [java] [INFO] MkSenDic - total time = 81[ms]

BUILD SUCCESSFUL
Total time: 1 minute 53 seconds
C:\usr\sen-1.2.2.1\dic>

なんかこんな感じで辞書ができる.

2009/09/13  21:19         2,255,818 connect.csv
2009/09/13  21:19        27,152,890 dic.csv
2009/09/13  21:19         8,979,816 matrix.sen
2009/09/13  21:20        21,812,410 posInfo.sen
2009/09/13  21:20         6,057,792 token.sen

この例では,結果は変わらないっぽい.

C:\usr\sen-1.2.2.1>.\bin\sen.bat

C:\usr\sen-1.2.2.1>rem set classpath

C:\usr\sen-1.2.2.1>SET CLASSPATH=C:\usr\sen-1.2.2.1\lib\sen.jar

C:\usr\sen-1.2.2.1>SET CLASSPATH=C:\usr\sen-1.2.2.1\lib\sen.jar;C:\usr\sen-1.2.2
.1\lib\commons-logging.jar
done.
Please input Japanese sentence:
2009/09/13 21:37:30 net.java.sen.Dictionary <init>
情報: token file = C:\usr\sen-1.2.2.1\dic/token.sen
2009/09/13 21:37:31 net.java.sen.Dictionary <init>
情報: time to load posInfo file = 109[ms]
2009/09/13 21:37:31 net.java.sen.Dictionary <init>
情報: double array trie dictionary = C:\usr\sen-1.2.2.1\dic/da.sen
2009/09/13 21:37:31 net.java.sen.util.DoubleArrayTrie load
情報: loading double array trie dict = C:\usr\sen-1.2.2.1\dic/da.sen
2009/09/13 21:37:32 net.java.sen.util.DoubleArrayTrie load
情報: loaded time = 1.031[ms]
2009/09/13 21:37:32 net.java.sen.Dictionary <init>
情報: pos info file = C:\usr\sen-1.2.2.1\dic/posInfo.sen
2009/09/13 21:37:32 net.java.sen.Dictionary <init>
情報: time to load pos info file = 0[ms]
2009/09/13 21:37:32 net.java.sen.Tokenizer loadConnectCost
情報: connection file = C:\usr\sen-1.2.2.1\dic\matrix.sen
2009/09/13 21:37:33 net.java.sen.Tokenizer loadConnectCost
情報: time to load connect cost file = 1031[ms]
すもももももももものうち
すもも  (すもも)        名詞-一般(0,3,3)        スモモ  スモモ
も      (も)    助詞-係助詞(3,4,1)      モ      モ
もも    (もも)  名詞-一般(4,6,2)        モモ    モモ
も      (も)    助詞-係助詞(6,7,1)      モ      モ
もも    (もも)  名詞-一般(7,9,2)        モモ    モモ
の      (の)    助詞-連体化(9,10,1)     ノ      ノ
うち    (うち)  名詞-非自立-副詞可能(10,12,2)   ウチ    ウチ

とりあえずは,すももの分かち書きが出来たので良しとしましょう.