Javaで形態素解析 with Kuromoji

# このページについて
Javaで形態素解析を実行してみよう、というもの。
他の色々な記事で前提になってくることも鑑みて、動作確認までをまとめます。

# 形態素解析って何？
文書を単語など意味のある最小限の単位に分割する処理を指します。
機械に言語を処理させる上で最もよく用いられる手法の一つです。

本稿ではその他にも色々な用語が出てきますが、
一先ず動作確認までを記述し、個々の用語に対しては付録で言及します。

# 開発方針
SpringBoot&Gradleの上にKuromojiライブラリを加える方針とします。
環境構築からの方は以下を参考ください。
⇒[SpringBoot入門...いいから動確だ！](https://qiita.com/ketman55/items/16d1e491a5a493f71c92)

|環境|サービス/バージョン|
|:--|:--|
|実行環境|Windows10|
|開発環境|eclipse Oxygen.2 Release (4.7.2) Java版|
|開発言語|Java 8|
|Framework|SpringBoot 2.1.3|

# プロジェクトにKuromojiを迎え入れる
KuromojiのライブラリはMavenCentralにもある様ですが、
今回はcodelibsから取ってくる方針としました。

以下の様にrepositoriesとdependenciesに追記。
その後、Graldeのリフレッシュを実行して依存関係を更新しましょう。

```gradle:build.gralde
plugins {
	id 'org.springframework.boot' version '2.1.3.RELEASE'
	id 'java'
}

apply plugin: 'io.spring.dependency-management'

group = 'com.lab.app.ketman'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '1.8'

repositories {
	mavenCentral()
	// 追加
	maven {
        url "http://maven.codelibs.org"
    }
    // ここまで
}

dependencies {
	implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
	implementation 'org.springframework.boot:spring-boot-starter-web'
	implementation 'org.mybatis.spring.boot:mybatis-spring-boot-starter:2.0.0'

	// 追加
	implementation 'org.codelibs:lucene-analyzers-kuromoji-ipadic-neologd:7.6.0-20190325'
	// ここまで

	runtimeOnly 'org.springframework.boot:spring-boot-devtools'
	runtimeOnly 'org.postgresql:postgresql'

	testImplementation 'org.springframework.boot:spring-boot-starter-test'
}
```

※Gradleリフレッシュのイメージ
![image.png](https://qiita-image-store.s3.amazonaws.com/0/385780/3ca7d6c6-f2d3-e470-2a82-7d4c3a1f4fdb.png)

# 一先ずコンソールへ出力してみる
解析結果はAttributeオブジェクトに格納されます。
欲しい情報を変数宣言して取得する。

|Attribute|概要|
|:--|:--|
|CharTermAttribute|解析した文そのままの表現|
|ReadingAttribute|形態素の読み|
|OffsetAttribute|形態素が何文字目に出現しているか|
|PartOfSpeechAttribute|品詞情報|
|BaseFormAttribute|原型|
|InflectionAttribute|活用|

```java:KuromojiSample
public class KuromojiSample {
	// returnとしてKuromojiEntityのリストを返すようにする
	public List<KuromojiEntity> kuromojineologd(String src){
		List<KuromojiEntity> keList = new ArrayList<KuromojiEntity>();
		try(JapaneseTokenizer jt =
				new JapaneseTokenizer(null, false, JapaneseTokenizer.Mode.NORMAL)){
			jt.setReader(new StringReader(src));
			jt.reset();
			while(jt.incrementToken()){

				CharTermAttribute ct = jt.addAttribute(CharTermAttribute.class);
				ReadingAttribute ra = jt.addAttribute(ReadingAttribute.class);
				OffsetAttribute oa = jt.addAttribute(OffsetAttribute.class);
				PartOfSpeechAttribute posa = jt.addAttribute(PartOfSpeechAttribute.class);
				BaseFormAttribute bfa = jt.addAttribute(BaseFormAttribute.class);
				InflectionAttribute ifa = jt.addAttribute(InflectionAttribute.class);

				System.out.println(
						ct.toString()
						+ " | " + ra.getReading()
						+ " | " + oa.startOffset()
						+ " | " + posa.getPartOfSpeech()
						+ " | " + bfa.getBaseForm()
						+ " | " + ifa.getInflectionForm()
						+ " | " + ifa.getInflectionType());
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
		return keList;
	}
}

```

```java:KuromojiSample
@Controller
public class SampleKuromojiController {
	KuromojiSample ks = new KuromojiSample();

	@RequestMapping("/kuromoji")
	public String index(Model model) {
		String sentence = "neologd君はゆるキャラを固有名詞として解釈出来ます。";
		ks.kuromojineologd(sentence);
		return "index";
	}
}
```
## 結果
neologd君の辞書ではこんな感じに分割されるらしい。
読みにジッコウイインカイなどと入る点が特徴的ですね。

```text
neologd | ネオログディー | 0 | 名詞-固有名詞-一般 | NEologd | null | null
君 | クン | 7 | 名詞-接尾-人名 | null | null | null
は | ハ | 8 | 助詞-係助詞 | null | null | null
ゆるキャラ | ユルキャラグランプリジッコウイインカイ | 9 | 名詞-固有名詞-人名-一般 | null | null | null
を | ヲ | 14 | 助詞-格助詞-一般 | null | null | null
固有名詞 | コユウメイシ | 15 | 名詞-一般 | null | null | null
として | トシテ | 19 | 助詞-格助詞-連語 | null | null | null
解釈 | カイシャク | 22 | 名詞-サ変接続 | null | null | null
出来 | デキ | 24 | 動詞-自立 | 出来る | 連用形 | 一段
ます | マス | 26 | 助動詞 | null | 基本形 | 特殊・マス
。 | 。 | 28 | 記号-句点 | null | null | null
```
# 付録

## ①Lucene Analyzerとは
[1. Luceneの概要](https://www.techscore.com/tech/Java/ApacheJakarta/Lucene/1/)より抜粋

>LuceneはJakartaプロジェクト1 によって開発された、 100% PureJavaのインデックスを作成するタイプの全文検索エンジンです。 
>（インデックスとは、高速で検索するためにつけられた索引のことです。） 
>Luceneそのものはライブラリであり完結したプログラムではありませんが、 
>Luceneが提供するAPIを用いることで、簡単に使いやすい全文検索プログラムを作ることが出来ます。 
>またJavaで書かれているため、Webアプリケーションへの適応が簡単に行えます。 
>Lucene自体は日本語を解析することが出来ませんが、形態素解析プログラムを利用することで日本語を検索することも可能になります。

## ②ipadic-neologdとは
日夜進化する自然言語において機械に与える情報(辞書)のメンテナンスは課題の一つになります。
Web上をクロールすることでこの課題に取り組もうというもの。
[neologd/mecab-ipadic-neologd](https://github.com/neologd/mecab-ipadic-neologd/blob/master/README.ja.md) より一部抜粋

>mecab-ipadic-NEologd は、多数のWeb上の言語資源から得た新語を追加することでカスタマイズした MeCab 用のシステム辞書です。
>Web上の文書の解析をする際には、この辞書と標準のシステム辞書(ipadic)を併用することをオススメします。
>(中略)
>利点
>MeCab の標準のシステム辞書では正しく分割できない固有表現などの語の表層(表記)とフリガナの組を約312万組(重複エントリを含む)採録しています
>この辞書の更新は開発サーバ上で自動的におこなわれます
>少なくとも毎週 2 回更新される予定です
>月曜日と木曜日
>Web上の言語資源を活用しているので、更新時に新しい固有表現を採録できます
>現在使用している資源は以下のとおりです
>・はてなキーワードのダンプデータ
>・郵便番号データダウンロード
>…
>(中略)
>欠点
>固有表現の分類が不十分です
>例えば一部の人名と製品名が同じ固有表現カテゴリに分類されています
>固有表現では無い語も固有表現として登録されています
>…

## ③解析ポリシの設定について
サンプルコードでは（JapaneseTokenizer.Mode.NORMAL）という引数を与えていたが、
他にもSearchとExtendsモードがあり、それぞれ以下の特徴がある。

[Kuromojiについて](https://qiita.com/syama1127/items/ae081c8fa1c9b2804f83)より抜粋

>ノーマルモード
>通常モード初期化したらデフォルトでこの形式で形態素解析を行いますよーといったもの。
>
>Searchモード
>「日本経済新聞」のような複数の言葉が組み合わさった単語を「日本 | 経済 | 新聞」のように分けて解析してくれる。
>全文検索エンジンと組み合わせて利用する場合に、日本経済新聞が「経済」や「新聞」でも検索可能になるので便利。
>
>Extendsモード
>Searchモードに加えて、未知語をuni-gramとして扱う。
>たとえば「モバゲー」は「モ | バ | ゲ | ー」と1文字ごとに分割される。
>未知語を検索し損ねることを減らしてくれそうな機能。

## ④Gradleへの追加文法
MavenCentralから取得する場合はこの様にすると良いそうな。
[Home » com.atilika.kuromoji » kuromoji-ipadic » 0.9.0]
(https://mvnrepository.com/artifact/com.atilika.kuromoji/kuromoji-ipadic/0.9.0)

```gradle
// https://mvnrepository.com/artifact/com.atilika.kuromoji/kuromoji-ipadic
compile group: 'com.atilika.kuromoji', name: 'kuromoji-ipadic', version: '0.9.0'
```