(続) mecab で Java Binding

昨日に引き続き。

make test までは通るようになったので、今度は Eclipse + Maven から使えるように環境を準備。昨日のディレクトリで

hyakushiki:mecab-java-0.96 takashi$ jar cvf MeCab-sources.jar org/chasen/mecab/*.java
hyakushiki:mecab-java-0.96 takashi$ mvn install:install-file -Dfile=MeCab.jar -DgroupId=org.chasen.mecab -DartifactId=mecab -Dversion=0.96 -Dpackaging=jar
hyakushiki:mecab-java-0.96 takashi$ mvn install:install-file -Dfile=MeCab-sources.jar -DgroupId=org.chasen.mecab -DartifactId=mecab -Dversion=0.96 -Dpackaging=jar -Dclassifier=sources

とした後、適当なプロジェクトの pom.xml

<dependency>
	<groupId>org.chasen.mecab</groupId>
	<artifactId>mecab</artifactId>
	<version>0.96</version>
</dependency>

を追加して mvn eclipse:eclipse を実行、と。

後は Eclipse の実行時に環境変数を与えるべく、実行クラスのプロパティの Run/Debug Settings の Environment に DYLD_LIBRARY_PATH を設定することと、JRE System Library をビルド時の環境と同様の Java5 に設定すれば、するりと動きました。

で、CJKAnalyzer を見よう見まねで MecabLucene 2.3 用のアナライザを書いてみて、インデックスを作成してみたり。

public class MecabAnalyzer extends Analyzer {

    static {
        try {
            System.loadLibrary("MeCab");
        } catch (UnsatisfiedLinkError e) {
            throw new RuntimeException(e);
        }
    }

    static final String[] stopWords = {""," ", " ", "て","に","を","は","。","、"};

    @Override
    public TokenStream tokenStream(String fieldName, Reader reader) {
        TokenStream stream = new MecabTokenizer(reader);
        return new StopFilter(stream, stopWords);
    }

    protected static class MecabTokenizer extends Tokenizer {

        static Tagger TAGGER;

        static {
            TAGGER = new Tagger();
        }

        Reader reader;

        boolean first = true;

        int offset = 0;

        Node node;

        MecabTokenizer(Reader reader) {
            this.reader = reader;
        }

        @Override
        public Token next() throws IOException {

            if (first) {
                String data = IOUtils.toString(reader);
                this.node = TAGGER.parseToNode(data);
                first = false;
            } else {
                this.node = node.getNext();
            }

            if (this.node == null) {
                return null;
            }

            int start = offset;
            int length = node.getLength();
            String surface = node.getSurface();
            offset += length + 1;
            String text = new String(surface);
            return new Token(text, start, start + length);
        }

        @Override
        public void close() throws IOException {
            IOUtils.closeQuietly(reader);
        }
    }
}
  • ここを参考に、Tagger は static でも良さそうなのと、surface でとった文字列は一度コピーした方がよさげなこと

また、Tagger は Stream をくるくる回すのではなく、一括で文字列を解析するようなので、一旦 IOUtils で reader を読み切ってしまってますが、大きなデータだと、メモリを食ってしまうかも。