以前mecab-python周りは導入が面倒くさかったのでDockerfileにまとめておこう。
REST APIの部分はこちらを参考にFlaskで実装しました。
ソースはgithubにあります。
ついでにdocker-composeも使ってみたらこれは便利。今回みたいにコンテナ1つだとあまり旨味はないけど。
[2016-10-07 追記] 辞書ファイルの更新について追記。
[2018-03-11 追記] フロントエンドを追加。
Dockerfile
今回の成果物です。
FROM ubuntu:16.04
RUN apt-get update \
&& apt-get install python3 python3-pip curl git sudo cron -y \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /opt
RUN git clone https://github.com/taku910/mecab.git
WORKDIR /opt/mecab/mecab
RUN ./configure --enable-utf8-only \
&& make \
&& make check \
&& make install \
&& ldconfig
WORKDIR /opt/mecab/mecab-ipadic
RUN ./configure --with-charset=utf8 \
&& make \
&&make install
WORKDIR /opt
RUN git clone --depth 1 https://github.com/neologd/mecab-ipadic-neologd.git
WORKDIR /opt/mecab-ipadic-neologd
RUN ./bin/install-mecab-ipadic-neologd -n -y
COPY . /opt/api
WORKDIR /opt/api
RUN pip3 install -r requirements.txt
CMD ["python3", "server.py"]
[2016-10-07 追記]
- 辞書ファイルを自動更新するためにcronをインストール。設定方法は下記を参照。
- ついでにmecab-ipadic-neologdをgit cloneするディレクトリを変更
その他
ディレクトリ構造
.
├── README.md
├── docker-compose.yml
└── flask-mecab
├── Dockerfile
├── requirements.txt
└── server.py
docker-compose.yml
api:
build: ./flask-mecab
volumes:
- "./flask-mecab:/opt/api"
ports:
- "5000:5000"
restart: always
MeCabの出力結果をJSON形式に変換
MeCabの出力フォーマットはカスタマイズできますが、デフォルトでは、
表層形\t品詞,品詞細分類1,品詞細分類2,品詞細分類3,活用形,活用型,原形,読み,発音
となっているので、出力された文字列の各行を'\t'と','で分割してzip()を使って各要素に対応させています。
def mecab_parse(sentence, dic='ipadic'):
dic_dir = "/usr/local/lib/mecab/dic/"
if dic == 'neologd':
dic_name = 'mecab-ipadic-neologd'
else:
dic_name = dic
m = MeCab.Tagger('-d ' + dic_dir + dic_name)
# 出力フォーマット(デフォルト)
format = ['表層形', '品詞','品詞細分類1', '品詞細分類2', '品詞細分類3', '活用形', '活用型','原型','読み','発音']
return [dict(zip(format, (lambda x: [x[0]]+x[1].split(','))(p.split('\t')))) for p in m.parse(sentence).split('\n')[:-2]]
後述する実行例も参照してください。
起動方法
docker-compose.ymlにポートフォワーディングの設定などを書けるので起動はこれだけです。
$ git clone https://github.com/matsulib/mecab-service.git
$ cd mecab-service/
$ sudo docker-compose up -d
実行方法
HTTPリクエスト
POST /mecab/v1/parse-ipadic
POST /mecab/v1/parse-neologd
リクエストヘッダ
Content-Type: application/json
リクエストボディ
{
"sentence": 文字列
}
実行例 ipadic
$ curl -X POST http://localhost:5000/mecab/v1/parse-ipadic \
-H "Content-type: application/json" \
-d '{"sentence": "関数型プログラミング"}' | jq .
{
"dict": "ipadic",
"message": "Success",
"results": [
{
"原型": "関数",
"品詞": "名詞",
"品詞細分類1": "一般",
"品詞細分類2": "*",
"品詞細分類3": "*",
"活用型": "*",
"活用形": "*",
"発音": "カンスー",
"表層形": "関数",
"読み": "カンスウ"
},
{
"原型": "型",
"品詞": "名詞",
"品詞細分類1": "接尾",
"品詞細分類2": "一般",
"品詞細分類3": "*",
"活用型": "*",
"活用形": "*",
"発音": "ガタ",
"表層形": "型",
"読み": "ガタ"
},
{
"原型": "プログラミング",
"品詞": "名詞",
"品詞細分類1": "サ変接続",
"品詞細分類2": "*",
"品詞細分類3": "*",
"活用型": "*",
"活用形": "*",
"発音": "プログラミング",
"表層形": "プログラミング",
"読み": "プログラミング"
}
],
"status": 200
}
実行例 mecab-ipadic-neologd
mecab-ipadic-neologdは固有名詞に強い辞書です。
$ curl -X POST http://localhost:5000/mecab/v1/parse-neologd \
-H "Content-type: application/json" \
-d '{"sentence": "関数型プログラミング"}' | jq .
{
"dict": "neologd",
"message": "Success",
"results": [
{
"原型": "関数型プログラミング",
"品詞": "名詞",
"品詞細分類1": "固有名詞",
"品詞細分類2": "一般",
"品詞細分類3": "*",
"活用型": "*",
"活用形": "*",
"発音": "カンスーガタプログラミング",
"表層形": "関数型プログラミング",
"読み": "カンスウガタプログラミング"
}
],
"status": 200
}
イメージサイズについて
今回のDockerfileから作ったイメージが次のmecabservice_apiなんですが、元のubuntuと比べるととてつもなく巨大になりました。
$ sudo docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
mecabservice_api latest 785bc1295e46 About an hour ago 3.375 GB
ubuntu 16.04 c73a085dc378 4 days ago 127.1 MB
どこで肥大化したのかhistoryサブコマンドで見てみる。
やはり辞書ファイルがすごく大きいみたいだけど、これは仕方ないか。
$ sudo docker history mecabservice_api
IMAGE CREATED CREATED BY SIZE COMMENT
785bc1295e46 About an hour ago /bin/sh -c #(nop) CMD ["python3" "server.py"] 0 B
00339a58f77e About an hour ago /bin/sh -c pip3 install -r requirements.txt 5.852 MB
a397235a8e30 About an hour ago /bin/sh -c #(nop) WORKDIR /opt/api 0 B
436ef40f928d About an hour ago /bin/sh -c #(nop) COPY dir:a4cb3a57cc1f117b07 2.445 kB
12456a11160d 3 hours ago /bin/sh -c ./bin/install-mecab-ipadic-neologd 2.307 GB
18478e2f8d71 3 hours ago /bin/sh -c #(nop) WORKDIR /opt/mecab/mecab-ip 0 B
74e6a0bffa98 3 hours ago /bin/sh -c git clone --depth 1 https://github 114.2 MB
db6a7c716f21 3 hours ago /bin/sh -c #(nop) WORKDIR /opt/mecab 0 B
6980af0a5afd 3 hours ago /bin/sh -c ./configure --with-charset=utf8 106 MB
db32f32c58e6 3 hours ago /bin/sh -c #(nop) WORKDIR /opt/mecab/mecab-ip 0 B
5745385f2342 3 hours ago /bin/sh -c ./configure --enable-utf8-only 11.16 MB
8c601b1fac00 3 hours ago /bin/sh -c #(nop) WORKDIR /opt/mecab/mecab 0 B
d730397e47eb 3 hours ago /bin/sh -c git clone https://github.com/taku9 378.8 MB
2abd825af064 3 hours ago /bin/sh -c apt-get update && apt-get instal 325 MB
d5abec2370fb 3 hours ago /bin/sh -c #(nop) WORKDIR /opt 0 B
c73a085dc378 4 days ago /bin/sh -c #(nop) CMD ["/bin/bash"] 0 B
[2016/10/07 追記] mecab-ipadic-neologdの辞書を自動更新する
mecab-ipadic-neologdの辞書は定期的にサーバー上で更新されていることに気づきました。
- この辞書の更新は開発サーバ上で自動的におこなわれます
- 少なくとも毎週 2 回更新される予定です
- 月曜日と木曜日
さらに、インストール後の辞書に更新を取り込む方法も公式に提示されています。
cron(説明は省略します)などで自動的に更新したい場合に便利なオプションは既にあります。
例えば下記の様な 2 行を crontab などに書いた場合は、火・金曜日の午前 3 時に解析結果を確認せずに(-y)ユーザ権限(-u)で指定した>ディレクリトリに(-p [/path/to/user/directory])ある辞書ファイルが更新されます。
00 03 * * 2 ./bin/install-mecab-ipadic-neologd -n -y -u -p /path/to/user/directory > /path/to/log/file
00 03 * * 5 ./bin/install-mecab-ipadic-neologd -n -y -u -p /path/to/user/directory > /path/to/log/file
稼働中のコンテナをmecabservice_api_1とし、更新ログを/opt/log/mecabに出力する場合は、
以下のように、コンテナにbashで接続して設定できます。
$ sudo docker exec -it mecabservice_api_1 /bin/bash
# mkdir -p /opt/log/mecab
# (crontab -l 2>/dev/null; echo "PATH=$PATH") | crontab -
# (crontab -l 2>/dev/null; echo '00 18 * * 1 /opt/mecab-ipadic-neologd/bin/install-mecab-ipadic-neologd -n -y >/opt/log/mecab/neologd_`date -I`.log 2>/opt/log/mecab/neologd_`date -I`.err') | crontab -
# (crontab -l 2>/dev/null; echo '00 18 * * 4 /opt/mecab-ipadic-neologd/bin/install-mecab-ipadic-neologd -n -y >/opt/log/mecab/neologd_`date -I`.log 2>/opt/log/mecab/neologd_`date -I`.err') | crontab -
# /etc/init.d/cron restart
# exit
ここではJST時間の火・金曜日の午前3時に更新されるようにUTC時間で設定しています。
デフォルトではcrontabのPATHにmecabが含まれないところで一瞬詰まりました。
また、最初はシェルのちょっとしたバグで上記の設定でうまく動かなかったのですが、IssueとPull Requestを投げたらすぐにマージして頂き動くようになりました(*^^)v
[2018/03/11 追記] フロントエンドを追加する
せっかくdocker-composeを使ってるのに1サービスだけでは寂しいので、上記REST APIをフロントエンドから呼び出すWebアプリをdocker-composeに追加しました。フロントのソースはgithubを参照してください。コンテナ間の通信やCORSの設定が詰まりどころでした。
docker-compose.yml
api:
build: ./flask-mecab
volumes:
- "./flask-mecab:/opt/api"
ports:
- "5000:5000"
restart: always
front:
build: ./flask-mecab-front
volumes:
- "./flask-mecab-front:/opt/front"
ports:
- "5001:5001"
restart: always
links:
- api
environment:
FLASK_MECAB_URI: "http://api:5000/mecab/v1"
起動後、ブラウザでhttp://localhost:5001/
にアクセスします。