Ubuntu10.04にCabochaをインストールする

参考にしたページ

いつもお世話になっているSyo-Takasakiさんのエントリ

[NLP][Ubuntu]UbuntuUTF-8版のcabochaを簡単にインストールする方法
http://d.hatena.ne.jp/Syo-Takasaki/20090528/1243484754

基本手順

基本手順ははSyo-Takasakiさんのエントリ通り

sources.listの書き変え方法

Terminalから以下のコマンドを実行。

$ sudo gedit

Sudoでgeditを実行する。
これで立ち上がったgeditにsources.listをドラッグアンドドロップで読み込み編集。
これで読み取り専用のsources.listの読み書きができるようになる。

あとは、参考にしたページ通りの手順を踏めばUbuntuにcabochaの環境を構築できる。

Cabochaでもexec()を使わずに実行できるのか

cabocha本体の場所

/usr/bin/cabocha

ひとつ前のエントリの書きかえる部分
    public String getClause(String str){
        def String sentence = str;
        sentence = sentence.replaceAll("\"","''");
        def String command = "/usr/bin/cabocha -f1";
        
        return new Pipe("echo ${sentence}").to(command).text();       
    }

commandでf1コマンドを追記した。
でなければ文節の関係図を取得してしまう。

結論

できる。

exec()を使わずに、Javaからmecabを呼べるのか

※前提
mecabを呼ぶ専用のライブラリは使わない。
JavaではなくGroovyを使う!!
環境はVirtualBoxで仮想化したUbuntu10.04、IDEはNetbeans6.8を使った。
Netbeansだと、数クリックでGroovyを有効にできるのでw)

Groovyのコード

import java.util.ArrayList;

/**
 *
 * @author Syu-syu
 */
public class mecab {
    public ArrayList<String> mecabStart(ArrayList<String> list){
        ArrayList <String> result = new ArrayList<String>();
        for(String s : list){
            result.add(this.getMorph(s));
        }      
        return result;
    } 
    
    public String getMorph(String str){
        def String sentence = str;
        sentence = sentence.replaceAll("\"","''");
        def String command = "/usr/bin/mecab";
        
        return new Pipe("echo ${sentence}").to(command).text();       
    }
}

def class Pipe {
    private Process p;

    def Pipe(cmd){
        p = cmd.execute();
        p.out.close();
    }

    def to(cmd){
        def p2 = cmd.execute();
        p2.out << p.in;
        p2.out.close();
        p=p2;
        this;
    }

    def text(){
        p.text;
    }
}

def to(cmd)や、def text()など、returnがないものがあります。
Groovyは最後の表記を勝手にreturnしてくれるので、書かなくてもよい。
書いた方がわかりやすいかも・・・

別のJavaプログラムから、文章のリストArrayListをmecabStartに投げる
mecabStartがgetMorphメソッドのreturnでPipeを動かして、投げられたリストの数分、形態素解析をしてくれます。

結果を受け取るJavaのプログラム

        mecab mecab_result = new mecab();
        ArrayList<String> morphlogical_result = mecab_result.mecabStart(inputdata);

Groovyのコードはstaticじゃないので、newしてあげる。
上記のコードでは、mecab_resultという変数をmecab型で宣言してます。
それで、mecab_result.mecabStart();が実行できる。
mecabStart(inputdata);のinputdataは入力された文章を1文ごとにリスト化したArrayListです。

結論

ライブラリなしでも、exec()使わずにJavaからmecabを呼べる!
※ただし、Groovyに限る。

while((line = br.readLine) != null){}でwhileが終了しない

おまじないを信じたとき

public static String getString(){

        String result_string = new String();

        try{
            BufferedReader br = new BufferedReader(new InputStreamReader(System.in, "UTF-8"));
            String line = new String();

            while((line = br.readLine()) != (null)){
                System.out.println(result_string += line);
            }

            br.close();

        }catch(IOException e){
            
        }

        return result_string;
    }

問題は真ん中らへんのwhileのループ

            while((line = br.readLine()) != (null)){
                System.out.println(result_string += line);
            }

ここが終了しない。

そこで、いろんな書き方を試した

            while((line = br.readLine()) != ("")){
                System.out.println(result_string += line);
            }
            while(!(line = br.readLine()).equals(null)){
                System.out.println(result_string += line);
            }
            while(!(line = br.readLine()).equals("")){
                System.out.println(result_string += line);
            }

br.readLine()がStringなので、String.equals()を使ってみたが、変わらず動作しなかった。
もちろん、lineに代入せず、br.readLine()単体で上記の4パターンを試したが動作しなかった。

解決方法

BufferedReader.ready()を使う

public static String getString(){
        String result_string = new String();
       
        try{
            BufferedReader br = new BufferedReader(new InputStreamReader(System.in, "UTF-8"));

            while(br.ready()){
                System.out.orintln(result_string += br.readLine());
            }
            br.close();
        }catch(IOException e){

        }

        return result_string;

    }

このBufferedReader.ready()は、入力可能かどうかを返す関数です。
つまり、最後の行が読み込まれた次のループからfalseを返してくれるんですね。

            while(br.ready()){
                System.out.orintln(result_string += br.readLine());
            }

この書き方でできる・・・とでも思ったのか!!!!

できませんでした

System.inが呼ばれ続けるため、常に入力受付状態が続き、br.readLine()にnullが入らないというオチでした。

つまり、exitとか入力されると、その文字列を判別してwhileをbreakする条件分岐をつくってやればいいということですね。

でもそれだと、もし入力中にexitがあれば〜とか、別のシステムでも利用するとき、わざわざexitと打たなければならないという弊害も発生する。
そのため、別の方法を試した方がよさそうですね。

結論

(line = br.readLine()) != null  でよい。
しかし処理終了の文字を決めて、break()するしかない。

オリジナルのオブジェクト(AllayList)の大小を比較するJavaプログラム

AllayListの中身を別クラスで定義

例)

public class exampleClass {
    public String text;
    public int figure;
}

上記の例の型をAllayListの型に指定し、int型のfigureを比較してStringのtextをソートしたい。

public static ArrayList getSort(ArrayList<exapmleClass> example_array){
    ArrayList<example> result_array = new ArrayList<exampleClass>();
        
        Object[] oa = example_array.toArray();
        Arrays.sort(oa, new Comparator());
        for(int i=0; i<oa.length; i++){
            exampleClass example_1 = (Object)oa[i];
            exampleClass example_2 = new exampleClass();

            example_2.text = example1.text;
            example_2.figure = examaple2.figure;

            result_array.add(example2);
        }

        return result_array;
    }
}

上記のメソッドがソートするメソッド。
このメソッドにArrayListを入れる。

上記メソッド内では比較するメソッド「Comparator()」を呼んでいる。

Comparator()

private static class Comparator implements Comparator {

    /**
     * 順序付けのために 2 つの引数を比較します。
     * 最初の引数が 2 番目の引数より小さい場合は負の整数、
     * 両方が等しい場合は 0、
     * 最初の引数が 2 番目の引数より大きい場合は正の整数を返します。
     */
    public int compare(Object o1, Object o2) {
        exampleClass p1 = (exampleClass) o1;
        exampleClass p2 = (exampleClass) o2;

        //もし、figureの値をdouble型で宣言していれば,(値の分布によって)10〜10000倍して差分をとる

        return (int)((p1.figure) - (int)(p2.figure)) * -1;
    }
}

日本語WordnetのJavaフロントエンドを利用して,類義語の検索を行った.

参考にしたページはこちら.
>>http://w-it.jp/shima/2009/03/wordnet_java_api.html
このJAWJAWというJavaAPIを利用する.

準備

JAWJAWを利用するにあたって,必要なライブラリが3つある.

  1. sqlite-jdbc-3.6.11.jar
  2. nestedvm-1.0.jar
    • Makefileからjarを生成する必要がある.
    • 面倒なのでこちらを利用.→NestedVMテスト
      • もしかしてjarでの配布が許可されていないのかも.
  3. junit-4.0.jar

上記のページではMaven2を利用したjarの生成を勧めているが,Maven2の利用方法がわからなかった(調べなかった)し,3つならネットから拾ってくるのも大した労力じゃないと思ったので,Maven2は利用していない.

実装

日本語Wordnetのページで紹介されていたサンプルを利用した.
以下にサンプルの引用を示す.

public class SimpleDemo {
	private static void run( String word, POS pos ) {
		// ファサードから日本語 WordNet にアクセス
		Set<String> hypernyms = JAWJAW.findHypernyms(word, pos);
		Set<String> hyponyms = JAWJAW.findHyponyms(word, pos);
		Set<String> consequents = JAWJAW.findEntailments(word, pos);
		Set<String> translations = JAWJAW.findTranslations(word, pos);
		Set<String> definitions = JAWJAW.findDefinitions(word, pos);
		// 結果表示(多義語はごっちゃになっています)
		System.out.println( "hypernyms of "+word+" : \t"+ hypernyms );
		System.out.println( "hyponyms of "+word+" : \t"+ hyponyms );
		System.out.println( word+" entails : \t\t"+ consequents );
		System.out.println( "translations of "+word+" : \t"+ translations );
		System.out.println( "definitions of "+word+" : \t"+ definitions );		
	}
	public static void main(String[] args) {
		// "買収"(動詞)という単語から得られる関係の一部をデモします
		SimpleDemo.run( "買収", POS.v );
	}
}

もちろんこれだけでは動かない.
今回は上記のコードを利用して以下のコードを記述した.

package similarword_sample;

import edu.cmu.lti.jawjaw.JAWJAW;
import edu.cmu.lti.jawjaw.pobj.*;
import java.util.Set;

public class SimpleDemo_ {

    private static void run( String word, POS pos ) {
        // ファサードから日本語 WordNet にアクセス
        Set<String> hypernyms = JAWJAW.findHypernyms(word, pos);
        Set<String> hyponyms = JAWJAW.findHyponyms(word, pos);
        Set<String> consequents = JAWJAW.findEntailments(word, pos);
        Set<String> translations = JAWJAW.findTranslations(word, pos);
        Set<String> definitions = JAWJAW.findDefinitions(word, pos);
        // 結果表示
        System.out.println( "hypernyms of "+word+" : \t"+ hypernyms );
        System.out.println( "hyponyms of "+word+" : \t"+ hyponyms );
        System.out.println( word+" entails : \t\t"+ consequents );
        System.out.println( "translations of "+word+" : \t"+ translations );
        System.out.println( "definitions of "+word+" : \t"+ definitions );
    }
    public static void main(String[] args) {
        // TODO code application logic here
        // "買収"(動詞)という単語から得られる関係の一部をデモします
	SimpleDemo_.run( "買収" , POS.v );
    }
}

JAWJAWのsrcディレクトリ内のjavaのパッケージを切り,インポートする.
Netbeansを利用したため以下のようなディレクトリ構成になった.

  • similarword_sample
    • ソースパッケージ
      • edu.cmu.lti.jawjaw
      • edu.cmu.lti.jawjaw.db
      • edu.cmu.lti.jawjaw.deno.demo
      • edu.cmu.lti.jawjaw.pobj
      • similarword_sample
    • data
      • デフォルトパッケージ
        • wnjpn-0.9.db
    • ライブラリ

上記のディレクトリ構成で注意するのが,太字表記したwnjpn-0.9.dbの部分である.
配布されているJAWJAWのコードの相対パスを一部確認したところ

sqlite:./data/wnjpn-0.9.db

となっていたため,dbの名前を変更した.今回利用したdbのバージョンは0.9.1である.
本来はコードを修正するのが望ましいが,すべてのコードを確認するのが面倒時間がなかったので,dbの名前を変えた.

これで利用できた.

検索方法

main関数の

SimpleDemo_.run( "買収" , POS.v );

の中身を変えるだけ.
上記であれば,買収という動詞(v)の類義語などを検索する.
POSの設定はedu.cmu.lti.jawjaw.pobjのPOS.javaで確認できる.

public enum POS {
	a, // adjective
	r, // adverb
	n, // noun
	v; // verb
}

上から

  • 形容詞
  • 副詞
  • 名詞
  • 動詞

である.


以上.

日本語WordnetのDBを,Javaで検索する

2009年3月にWordnetデータベースが公開された.
詳しくはこちら.

>>http://nlpwww.nict.go.jp/wn-ja/

日本語ワードネットは、プリンストン大学で開発された Princeton WordNet やPrinceton WordNetとヨーロッパのEuroWordNetの協会が推進す るGlobal WordNet Gridに 着想を得て開発されました。 ライセンスを保持していただければ、基本的に日本語ワードネットは無償で使用、複写、改変、頒布していただけます。 詳細はライセンスをご参照下さい。

MeCabの形態素解析速度を出力する

MeCab形態素解析する速度を計測して,研究に耐えうるものか計ることになった.
以下に計測方法とその結果を示す.

[user name]@ubuntu-vm:~$ time mecab < ~/mecab-test/100k-ntt.txt > /dev/null

real	0m1.135s
user	0m0.016s
sys	0m0.020s


time mecabというコマンドで実行速度を出力してくれる.

コマンド:time mecab <形態素解析を行うテキストファイル> /dev/null

「~/」はホームディレクトリのこと.


とりあえずメモメモ


問題は

real	0m1.135s
user	0m0.016s
sys	0m0.020s

これの意味がわからない...あとで調べよう.