kuromoji.jsの辞書に単語を追加する


# やりたいこと
[kuromoji.js](https://github.com/takuyaa/kuromoji.js)を使って、提供されている辞書に単語を追加したい。

# 環境
- OS X Yosemite 10.10.5

# 手順
1. mecab, mecab-ipadicをインストール
2. 追加したい単語の辞書用CSVファイルを作る
3. mecab-ipadicのモデルファイルからコストの自動推定をする
4. kuromoji.jsで辞書を作成する
5. 確認


## 1. mecab, mecab-ipadicをインストール

[Node.jsでmecab-ipadic-NEologdを使う](https://blog.knjcode.com/neologd-on-nodejs/)を参考に、mecabとmecab-ipadicをインストールする。

```bash
$ brew install mecab mecab-ipadic xz

$ echo '施行期日' | mecab
施行	名詞,サ変接続,*,*,*,*,施行,シコウ,シコー
期日	名詞,一般,*,*,*,*,期日,キジツ,キジツ
EOS
```

## 2. 追加したい単語の辞書用CSVファイルを作る

[MeCab システム辞書への単語追加（mecab-ipadic-neologd）](https://blog.apar.jp/linux/2796/)を参考に、追加したい単語の辞書用CSVファイルを作る。

```bash
$ mkdir dic_work
$ cd dic_work
```

次のようなaddwords_nocost.csvをdic_work以下に作る。kuromoji.jsの辞書ファイルはeuc-jpなので、addowrds_nocost.csvもeuc-jpにする。

```addwords_nocost.csv
施行期日,,,,名詞,一般,*,*,*,*,施行期日,シコウキジツ,シコウキジツ,（追加単語）
```

## 3. mecab-ipadicのモデルファイルからコストの自動推定をする

引き続き[MeCab システム辞書への単語追加（mecab-ipadic-neologd）](https://blog.apar.jp/linux/2796/)を参考に。

まずは辞書ファイルを取得して展開する。

```bash
$ wget http://mecab.googlecode.com/files/mecab-ipadic-2.7.0-20070801.tar.gz
$ tar xvzf mecab-ipadic-2.7.0-20070801.tar.gz

$ cd xvzf mecab-ipadic-2.7.0-20070801
$ ./configure 
checking for a BSD-compatible install... /usr/bin/install -c
checking whether build environment is sane... yes
checking whether make sets $(MAKE)... yes
checking for working aclocal-1.4... missing
checking for working autoconf... found
checking for working automake-1.4... missing
checking for working autoheader... found
checking for working makeinfo... found
checking for a BSD-compatible install... /usr/bin/install -c
checking for mecab-config... /usr/local/bin/mecab-config
configure: creating ./config.status
config.status: creating Makefile

$ /usr/local/Cellar/mecab/0.996/libexec/mecab/mecab-dict-index -f euc-jp -t utf-8        
reading ./unk.def ... 40
emitting double-array: 100% |###########################################| 
./model.def is not found. skipped.
reading ./Adj.csv ... 27210
reading ./Adnominal.csv ... 135
reading ./Adverb.csv ... 3032
reading ./Auxil.csv ... 199
reading ./Conjunction.csv ... 171
reading ./Filler.csv ... 19
reading ./Interjection.csv ... 252
reading ./Noun.adjv.csv ... 3328
reading ./Noun.adverbal.csv ... 795
reading ./Noun.csv ... 60477
reading ./Noun.demonst.csv ... 120
reading ./Noun.nai.csv ... 42
reading ./Noun.name.csv ... 34202
reading ./Noun.number.csv ... 42
reading ./Noun.org.csv ... 16668
reading ./Noun.others.csv ... 151
reading ./Noun.place.csv ... 72999
reading ./Noun.proper.csv ... 27327
reading ./Noun.verbal.csv ... 12146
reading ./Others.csv ... 2
reading ./Postp-col.csv ... 91
reading ./Postp.csv ... 146
reading ./Prefix.csv ... 221
reading ./Suffix.csv ... 1393
reading ./Symbol.csv ... 208
reading ./Verb.csv ... 130750
emitting double-array: 100% |###########################################| 
reading ./matrix.def ... 1316x1316
emitting matrix      : 100% |###########################################| 

done!
```

コストの自動推定機能を使うのに必要なmecab-ipadicのモデルファイルを取得して展開する。

```bash
$ cd ../
$ wget http://mecab.googlecode.com/files/mecab-ipadic-2.7.0-20070801.model.bz2
$ bzip2 -d mecab-ipadic-2.7.0-20070801.model.bz2
```

モデルファイル、辞書ファイル、単語を追加する辞書のCSVファイル（コスト値指定なし）を元にして、コストの自動推定を行った辞書ファイル（addwords.csv）を作る。ファイルはeuc-jpで。

```bash
$ /usr/local/Cellar/mecab/0.996/libexec/mecab/mecab-dict-index -m ./mecab-ipadic-2.7.0-20070801.model -d ./mecab-ipadic-2.7.0-20070801 -u addwords.csv -a addwords_nocost.csv
./mecab-ipadic-2.7.0-20070801.model is not a binary model. reopen it as text mode...
reading addwords_nocost.csv ... 
done!
```

生成されたaddwords.csvはこちら。

```addwords.csv
施行期日,1285,1285,5078,名詞,一般,*,*,*,*,施行期日,シコウキジツ,シコウキジツ,（追加単語）
```

コスト値が入っている。

## 4. kuromoji.jsで辞書を作成する

kuromoji.jsをgit cloneする。

```bash
$ git clone https://github.com/takuyaa/kuromoji.js.git
$ npm install
```

3.で生成したaddwors.csvをscripts/input以下に配置する。

```bash
$ ls scripts/input/addwords.csv 
scripts/input/addwords.csv
```

scripts/build-dict.jsを編集して、addwords.csvを対象にする。

```build-dict.js
（略）
var tid_files = [
    "Adj.csv",
    "Adnominal.csv",
    "Adverb.csv",
    "Auxil.csv",
    "Conjunction.csv",
    "Filler.csv",
    "Interjection.csv",
    "Noun.adjv.csv",
    "Noun.adverbal.csv",
    "Noun.csv",
    "Noun.demonst.csv",
    "Noun.nai.csv",
    "Noun.name.csv",
    "Noun.number.csv",
    "Noun.org.csv",
    "Noun.others.csv",
    "Noun.place.csv",
    "Noun.proper.csv",
    "Noun.verbal.csv",
    "Others.csv",
    "Postp-col.csv",
    "Postp.csv",
    "Prefix.csv",
    "Suffix.csv",
    "Symbol.csv",
    "Verb.csv",
    "addwords.csv" // ここに追加
];
（略）
```

gulp build-dictを実行して辞書を再生成する。

```bash
$ gulp build-dict
[01:34:36] Using gulpfile ~/work/kuromoji.js/gulpfile.js
[01:34:36] Starting 'build-dict'...
[01:34:53] Finished 'build-dict' after 17 s
```

これでdist/dic以下が更新されるので、この辞書を使う。

## 5. 確認

検証用のソースは以下。

```example.js
"use strict";

var kuromoji = require("..");
var DIC_DIR = "dist/dict/";

// Load dictionaries from file, and prepare tokenizer
kuromoji.builder({ dicPath: DIC_DIR }).build(function (error, tokenizer) {
    var path = tokenizer.tokenize("施行期日");
    console.log(path);
    module.exports = tokenizer;
});
```

単語を追加する前の辞書での結果。

```bash
$ node example/example.js
[ { word_id: 2503170,
    word_type: 'KNOWN',
    word_position: 1,
    surface_form: '施行',
    pos: '名詞',
    pos_detail_1: 'サ変接続',
    pos_detail_2: '*',
    pos_detail_3: '*',
    conjugated_type: '*',
    conjugated_form: '*',
    basic_form: '施行',
    reading: 'シコウ',
    pronunciation: 'シコー' },
  { word_id: 645000,
    word_type: 'KNOWN',
    word_position: 3,
    surface_form: '期日',
    pos: '名詞',
    pos_detail_1: '一般',
    pos_detail_2: '*',
    pos_detail_3: '*',
    conjugated_type: '*',
    conjugated_form: '*',
    basic_form: '期日',
    reading: 'キジツ',
    pronunciation: 'キジツ' } ]
```

単語を追加した新しい辞書での結果。

```bash
$ node example/example.js 
[ { word_id: 3921260,
    word_type: 'KNOWN',
    word_position: 1,
    surface_form: '施行期日',
    pos: '名詞',
    pos_detail_1: '一般',
    pos_detail_2: '*',
    pos_detail_3: '*',
    conjugated_type: '*',
    conjugated_form: '*',
    basic_form: '施行期日',
    reading: 'シコウキジツ',
    pronunciation: 'シコウキジツ' } ]
```

# 感想
[kuromoji.js](https://github.com/takuyaa/kuromoji.js) 素晴らしいです！！！