AWS Lambda でMeCabを動かす (2018年9月時点）

# 概要
AWS Lambdaで[MeCab](http://taku910.github.io/mecab/)を動かそうと思ったら、思いのほか大変だったので今後の自分のために手順をまとめた。
（MeCabとは日本語の自然言語処理によく使われるオープンソースの形態素解析エンジン。詳しくは上記の作者のサイトへ。）

# 参考にさせてもらったサイト
https://shogo82148.github.io/blog/2017/12/06/mecab-in-lambda/
http://marmarossa.hatenablog.com/entry/2017/02/03/223423

他にもたくさん「mecab lambda」で片っ端から検索かけて読み漁ったのだけど、もはやどこを読んだのかも覚えていない。上記二つの記事はとにかく作業スタートから完了するまでの間、ブラウザで開かれていた。

結論から述べると一番上の記事の通りにやればいいだけだったのだが、正直自分が次回この作業をやる時にこの記事を読んだだけでできるとは思えないのでもう少し手取り足取りメモを残そうと思う。


# 大前提
Lambdaで外部のライブラリを利用する場合、そのライブラリをLambda関数と一緒にZipで固めてアップロードしなくてはならない。
Pythonのライブラリであれば、`pip install xxxx -t .`でLambda関数と同じパスにインストールしてやれば良い。MeCabなどのバイナリも同様だが、`pip`ほど簡単にはいかない。
また、MeCabはc/c++で実装されており、Lambdaが動く環境と同じ環境でビルドしないとLambdaでは動かない。


# Mecab、IPA辞書のビルド、Lambdaへのデプロイのポイント
[SageMakerのJupyterノートブックインスタンスにMeCabを入れた](https://qiita.com/rtaguchi/items/1d10d1d4aa09edc40ddf)時には、`yum`でポンとインストールが出来た。今回も`yum install`の際にオプションか何か付ければ所定の場所に入れられるのかなと思い、`yum --installroot=/path install xxxx`を実行してみるも何だかたくさんディレクトリやらファイルやらが出来てしまい、どれが必要なものなのかわからない。参考にしたサイトでは自前でビルドしていたこともあり、私も`yum`ではなく自分でビルドすることにした。

もろもろ検索したり、トライアンドエラーを経たり、で得た知見はまとめると以下の4点に集約される。

1. python-mecabを利用してMeCabを実行する場合、環境変数にMeCabのバイナリ、MeCabで利用するライブラリの場所が含まれている必要がある 
    1. `$PATH`で指定されている場所にmecabのバイナリ
    2. `$LD_LIBRARY_PATH`で指定されている場所に`libmecab.so`など
2. LambdaにアップロードしたzipファイルはLambda実行環境では`/var/task`配下に展開される
3. Lambda実行環境の環境変数にはデフォルトで以下が含まれている
    1. `$PATH`に`/var/task/bin`
    2. `$LD_LIBRARY_PATH`に`var/task/lib`
4. MeCab、IPA辞書の設定ファイル（`mecabrc`など）には、ビルド時（`./configure`実行時）に指定した場所のパスが書かれる

上記4点から考えると、最も簡単なパッケージの作成方法は、パッケージを作成する環境に`/var/task`ディレクトリを作成し、そのディレクトリ内でMecabとIPA辞書のビルドを行い、作成された`/var/task`配下のオブジェクトを全部zipに固めて、Lambdaにデプロイするという方法である。
この方法であれば、`*.so`ファイルの場所や`mecabrc`の設定などはデフォルトのままで問題無くLambda上で動かすことができる。Lambda側の環境変数も追加不要である。

（参考にさせてもらったサイトの1番目をきちんと読み込めば、結局上記と同様のことが書かれているのだが、当初はそれが全くピンとこなかった。）

# 具体的なコマンド
実行環境はAmazon Linux。私はEC2インスタンス建てるのが面倒だったので、AWS SageMakerのノートブックインスタンスで実行した。

### /var/taskの作成
まずは`/var/task`を作成し、あわせて`gcc-c++`のパスを通してやる。2番目の手順が必要な理由は[コチラ](https://qiita.com/rtaguchi/items/1d10d1d4aa09edc40ddf#mecab-python3%E3%81%8C%E5%85%A5%E3%82%89%E3%81%AA%E3%81%84)を参照のこと。

```shell-session
sudo mkdir /var/task
sudo ln -s /usr/libexec/gcc/x86_64-amazon-linux/4.8.5/cc1plus /usr/local/bin/
```
### MeCabのダウンロードとビルド
次にMeCabをGoogleドライブからダウンロードしてビルド。
`--prefix=/var/task`という指定がポイント。ビルドした後にファイルを移動しようと思ってもうまくいかないので注意が必要。
なお、URLは古くなる可能性があるので、最新のダウンロード先は[作者のサイト](http://taku910.github.io/mecab/#download)を確認のこと。

```shell-session
cd ~
curl -L "https://drive.google.com/uc?export=download&id=0B4y35FiV1wh7cENtOXlicTFaRUE" -o mecab-0.996.tar.gz
tar -zxvf mecab-0.996.tar.gz
cd mecab-0.996
sudo ./configure --prefix=/var/task --with-charset=utf8
sudo make
sudo make install
```

### IPA辞書のダウンロードとビルド
同じくIPA辞書をGoogleドライブからダウンロードしてビルド。
`--prefix`の指定だけでなく、`--with-mecab-config`の指定も必要になる。

```shell-session
cd ~
curl -L "https://drive.google.com/uc?export=download&id=0B4y35FiV1wh7MWVlSDBCSXZMTXM" -o mecab-ipadic-2.7.0-20070801.tar.gz
tar -zxvf mecab-ipadic-2.7.0-20070801.tar.gz
cd mecab-ipadic-2.7.0-20070801
sudo ./configure --prefix=/var/task --with-charset=utf8 --with-mecab-config=/var/task/bin/mecab-config
sudo make
sudo make install
```

### mecab-python-3のインストールと動作確認のためのパス設定
`mecab-python-3`を同じく`/var/task`に配置すれば、後はzipに固めるだけでデプロイパッケージの出来上がり。
この環境上で動作確認する場合は、環境変数`PATH`、`LD_LIBRARY_PATH`にそれぞれ`/var/task/bin`、`/var/task/lib`を追加することを忘れないように。
(なお`source activate tensorflow_p36`はSageMakerのノートブックインスタンス上でpython3系の仮想環境に切り替えることを目的に打ったコマンドなので、本筋とは無関係。）

```shell-session
cd ~
mkdir temp && cd temp
source activate tensorflow_p36
pip install mecab-python3 -t .
sudo mv ./* /var/task

export PATH=$PATH:/var/task/bin
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/var/task/lib
```

# 今後の発展
今回の対応ではipadicの辞書を入れただけで終わり。[Neologd](https://github.com/neologd/mecab-ipadic-neologd/blob/master/README.ja.md)も入れたかったけれども、Lambdaのtemp領域の制限でアウト。
以下のように工夫をすればNeologdもイケるそうだけど、今回の用途はちょっと遊ぶ程度のものなのでこの部分はお預け。
https://speakerdeck.com/satorukadowaki/aws-apigateway-plus-python-lambda-plus-neologddezuo-rusabaresuri-ben-yu-xing-tai-su-jie-xi-api

そうこう言っている間にLambdaのtemp領域の制限が一気に3GBくらいになってくれないかな。

### 追記
この記事の続編を書きました。
[AWS Lambda with EFS で MeCab, NEologd & CaboCha を動かす （2020年7月時点）](https://qiita.com/rtaguchi/items/f2b39572299b5399df76)