Javaで形態素解析と辞書のカスタマイズ

# この記事で紹介すること
 
* この記事は次の２つのトピックについて記載しています。
 
   1. Javaの形態素解析ライブラリKuromojiの使用方法
   2. Kuromojiへのユーザ辞書の追加方法

Kuromojiはatilika社が開発し、Apache Software Foundationへ寄贈されているJava製の形態素解析ライブラリです。ライセンスは「Apache v2 License」となっています。形態素解析に必要な辞書をjarの中に格納しているため、ワンパッケージで形態素解析を行うことができます。また、用意されている辞書は以下のようなものがあります。

 * IPADIC (2.7.0-20070801)
 * IPADIC NEologd (2.7.0-20070801-neologd-20151224)
 * JUMANDIC (7.0-20130310)
 * NAIST jdic (0.6.3b-20111013)
 * UniDic (2.1.2)
 * UniDic Kana Accent (2.1.2)
 * UniDic NEologd (2.1.2-neologd-20151224)

これらの辞書ごとにjarファイルが分かれており、排他的に利用できるようになっています。公式ではとりあえず最初はIPADICを使いアプリケーションに合わせて他の辞書も試してみる。ということが記載されています。
今回はIPADICを利用してみます。

# Kuromojiを使うための準備

KuromojiのjarファイルはMavenのセントラルリポジトリに登録されています。そのため、MavenやGradleを使っていれば設定を記載するだけで利用ができるようになります。Mavenのpomファイルでは、\<dependencies\>ディレクティブに以下を記載してください。

```xml:pom.xml
<dependency>
    <groupId>com.atilika.kuromoji</groupId>
    <artifactId>kuromoji-ipadic</artifactId>
    <version>0.9.0</version>
</dependency>
```

以上でKuromojiを使う準備ができました。

# Kuromojiを動かしてみる

以下がKuromojiを使ったサンプルコードです

```java:KuromojiSample.java
import java.io.IOException;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;


import com.atilika.kuromoji.ipadic.Token;
import com.atilika.kuromoji.ipadic.Tokenizer;
import com.atilika.kuromoji.ipadic.Tokenizer.Builder;

public class KuromojiExample {

	public static void main(String[] args) {
		String input = "一風堂のラーメンが食べたい";
		Tokenizer tokenizer = new Tokenizer();
		List<Token> tokens = tokenizer.tokenize(input);
		tokens
			.stream()
			.map(e -> e.getSurface()+ " "+ e.getAllFeatures())
			.forEach(System.out::println);
		
	}
	
}

```

このプログラムを実行得られる形態素解析の結果は以下のようになります。

```
一風 名詞,一般,*,*,*,*,一風,イップウ,イップー,,
堂 名詞,接尾,一般,*,*,*,堂,ドウ,ドー,,
の 助詞,連体化,*,*,*,*,の,ノ,ノ,,
ラーメン 名詞,一般,*,*,*,*,ラーメン,ラーメン,ラーメン,,
が 助詞,格助詞,一般,*,*,*,が,ガ,ガ,,
食べ 動詞,自立,*,*,一段,連用形,食べる,タベ,タベ,たべ/食/食べ,
たい 助動詞,*,*,*,特殊・タイ,基本形,たい,タイ,タイ,,
```

形態素解析はTokenizer::tokenizeメソッドで実行されます。引数には形態素解析したい文字列が渡されます。形態素解析の結果はTokenオブジェクトのリストとして返されます。
Tokenオブジェクトには形態素解析の詳細な結果が記載されています。このサンプルの中ではToken::getSurfaceにより、形態素解析された文字列を取得しています。また、スペースを挟んでToken::getAllFeatureにより品詞情報や読みといった詳細な情報を取得することができます。これ以外にも幾つかの情報を取得できます。

# ユーザ辞書を作る

前述の結果を見ると気になる点が一つあります。文字列の最初の「一風堂」が「一風」「堂」と別れています。この文脈ではラーメン店の名前である「一風堂」が一つの単語として帰ってくることが期待されます。（期待します）しかしKuromojiの形態素解析では２つの単語として解析さてしまいます。
　これはKuromojiが利用している辞書（今回はIPA辞書）に「一風堂」という単語が記載されていないのが原因だと推測されます。
そこで、ラーメン店名を正しく形態素解析できるようにユーザ辞書を作りたいと思います。
Kuromojiのユーザ辞書はcsv形式で次のようなファイルを作成します。

```cvs:user_dic.csv
#コメント行
# 単語,　形態素解析結果の単語, 読み, 品詞
一風堂,一風堂,イップウドウ,名詞
一蘭,一蘭,イチラン,名詞
元祖長浜,元祖長浜,ガンソナガハマ,名詞
```
上記のように作った辞書を読み込んだTokenizerを作成します。今度は以下のようなサンプルコードになります。

```java:KuromojiExampleUserDic.java
import java.io.IOException;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;


import com.atilika.kuromoji.ipadic.Token;
import com.atilika.kuromoji.ipadic.Tokenizer;
import com.atilika.kuromoji.ipadic.Tokenizer.Builder;

public class KuromojiExampleUserDic{

	public static void main(String[] args) {
		String input = "一風堂のラーメンが食べたい";
		input = filterURL(input);
		input = filterID(input);
		Builder builder = new Tokenizer.Builder();
		Tokenizer tokenizer = null;
		try {
			tokenizer = builder.userDictionary("./userDic.csv").build();
		} catch (IOException e1) {
			
		}
		List<Token> tokens = tokenizer.tokenize(input);
		tokens
			.stream()
			.map(e -> e.getSurface()+ " "+ e.getAllFeatures())
			.forEach(System.out::println);
		
	}
	
}

```

今度はTokenizerオブジェクトをビルダーパターンで取得します。ビルド前にuserDictionaryに先ほどのユーザ辞書のパスを指定します。
実行結果は以下のようになります。

```
一風堂 名詞,*,*,*,*,*,*,イップウドウ,*,*,*
の 助詞,連体化,*,*,*,*,の,ノ,ノ,,
ラーメン 名詞,一般,*,*,*,*,ラーメン,ラーメン,ラーメン,,
が 助詞,格助詞,一般,*,*,*,が,ガ,ガ,,
食べ 動詞,自立,*,*,一段,連用形,食べる,タベ,タベ,たべ/食/食べ,
たい 助動詞,*,*,*,特殊・タイ,基本形,たい,タイ,タイ,,
```

今度は一風堂が期待通りに解析されました。

KuromojiはApach SolrやElasticserchの日本語検索に利用されています。このような手軽に使える形態素解析器があれば、TwitterといったSNSからの情報抽出やBotの構築などにも活用できそうです。