はじめに
PyKNPを利用して固有表現抽出をやってみたいなと思ってちょっと環境構築を調べてみました.メインで使用しているmacOSにはHomebrew経由で先人の用意したリポジトリuetchy/homebrew-nlp
を使わせてもらうことで準備できました.
ただ,この環境をDockerでイメージ化しておきたいなーという欲求が生まれたので,勉強がてら構築してみることにしました.
結論
忙しい方のためにTL;DR風に先に結論を書いておくことにします.
ファイル構成
開発用のディレクトリ(とはいえただのテスト)の構成は以下のような感じです.近年はrequirements.txt
といったパッケージ関係をどう管理するかについて様々な流儀がありますがこのエントリでは触れないことにします.
% tree
.
├── Dockerfile
├── docker-compose.yml
├── pyknp_test.py
└── requirements.txt
0 directories, 4 files
それぞれのファイルは以下のように用意しました.
FROM python:3.6-slim
# create user as "app"
RUN useradd --user-group --create-home --shell /bin/false app
# set home directory
ENV HOME=/home/app
# copy source file
COPY . $HOME/pyknp_test
# install dependencies
RUN apt-get update && apt-get install -y \
build-essential \
curl \
bzip2 \
libjuman \
libcdb-dev \
zlib1g-dev
RUN pip3 install --requirement $HOME/pyknp_test/requirements.txt
# install juman and KNP and copy .jumanrc file
RUN mkdir $HOME/src && \
cd $HOME/src && \
curl -L -o juman-7.01.tar.bz2 http://nlp.ist.i.kyoto-u.ac.jp/nl-resource/juman/juman-7.01.tar.bz2 && \
tar xf juman-7.01.tar.bz2 && \
cd juman-7.01 && \
./configure && \
make && \
make install && \
cp /usr/local/etc/jumanrc $HOME/.jumanrc
RUN cd $HOME/src && \
curl -L -o knp-4.19.tar.bz2 http://nlp.ist.i.kyoto-u.ac.jp/nl-resource/knp/knp-4.19.tar.bz2 && \
tar xf knp-4.19.tar.bz2 && \
cd knp-4.19 && \
./configure && \
make && \
make install
# delete download cache
RUN rm -rf $HOME/src && \
apt-get purge -y \
build-essential \
curl \
bzip2
# change user
RUN chown -R app:app $HOME/*
WORKDIR $HOME/pyknp_test
USER app
# set CMD
CMD ["python3", "pyknp_test.py"]
version: '3'
services:
pyknp:
build: .
volumes:
- .:/home/app/pyknp_test
# coding: utf-8
import pyknp
import re
# KNP prepairing
knp = pyknp.KNP(option="-tab -dpnd", jumanpp=False)
def make_np_tagged_text(src_text: str):
tagged_text = src_text # copy
result = knp.parse(src_text) # tagging
for tag in result.tag_list():
if "NE:" in tag.fstring: # if fstring has NE phrase
# extract NE phrase
tagged_ne_phrase = re.search("<NE:(.*):(.*)>", tag.fstring).group(0)
ne_phrase = re.search("<NE:(.*):(.*)>", tag.fstring).group(2)
# overwrite to src text
tagged_text = tagged_text.replace(ne_phrase, tagged_ne_phrase)
return tagged_text
def main():
line = "太郎は5月18日の朝9時に花子に会いに行った."
print(line)
print(make_np_tagged_text(line))
if __name__ == "__main__":
main()
pyknp
実行
docker-composeを介して実行してみます.
% docker-compose build
(ガガッとビルドされる)
% docker-compose up
Starting pyknp_test_pyknp_1 ... done
Attaching to pyknp_test_pyknp_1
pyknp_1 | 太郎は5月18日の朝9時に花子に会いに行った.
pyknp_1 | <NE:PERSON:太郎>は5月18日の朝9時に<NE:LOCATION:花子>に会いに行った.
pyknp_test_pyknp_1 exited with code 0
pyknp_test.py
の変数line
を変えて再び実行してみましょう.
line = "ほげほげ〜"
% docker-compose up
Starting pyknp_test_pyknp_1 ... done
Attaching to pyknp_test_pyknp_1
pyknp_1 | ほげほげ〜
pyknp_1 | ほげほげ〜
pyknp_test_pyknp_1 exited with code 0
いい感じですね
構成の説明
環境
ざっくり以下のような環境でテストしています.
OS | macOS 10.13.6 |
Docker | 18.06.1-ce-mac73 |
Dockerfile
いくつかの手順に分解してDockerfile
を読み解いていきます.筆者は,主に個人でのツールやサービス開発でDockerを利用しているのでそのあたりのtipsが入っていると感じる方もいるかも知れません.
元イメージの設定,ユーザ設定
FROM python:3.6-slim
# create user as "app"
RUN useradd --user-group --create-home --shell /bin/false app
# set home directory
ENV HOME=/home/app
# copy source file
COPY . $HOME/pyknp_test
この部分は,構築するイメージの元イメージの設定,実行ユーザの設定,開発ディレクトリのコピーをおこなっています.
最終的に実行するのはappユーザとなるようこのあと準備していきます.
JUMAN, KNPのインストール
最近だとJUMANの代わりにJUMAN++を使用することが多いのでしょうか?解析器に強くないので分かりませんが・・・
その話は置いて,JUMAN, KNPをインストールします.どちらも黒橋・河原研究室から発表されているものです.公開に感謝しながら使っていきます.
では,JUMAN, KNPのインストールを抜粋しながら見ていきます.
ビルド環境・ライブラリ等の準備
# install dependencies
RUN apt-get update && apt-get install -y \
build-essential \
curl \
bzip2 \
libjuman \
libcdb-dev \
zlib1g-dev
この部分は,ビルド環境(build-essential
)とライブラリ等を準備します.
今回は構築するイメージのもととしてpython:3.6-slim
を使用しているので,このあと使用するファイルダウンロードと展開のためcurl
とbzip2
も同時にインストールしています.
pipからのインストール
RUN pip3 install --requirement $HOME/pyknp_test/requirements.txt
この部分は,開発ディレクトリのrequirements.txt
を元にpipからパッケージをインストールしています.Dockerfile
の記述を見ればわかりますが,最初に開発ディレクトリの内容をイメージにコピーしているため実行できます.
JUMAN, KNPのインストール
# install juman and KNP and copy .jumanrc file
RUN mkdir $HOME/src && \
cd $HOME/src && \
curl -L -o juman-7.01.tar.bz2 http://nlp.ist.i.kyoto-u.ac.jp/nl-resource/juman/juman-7.01.tar.bz2 && \
tar xf juman-7.01.tar.bz2 && \
cd juman-7.01 && \
./configure && \
make && \
make install && \
cp /usr/local/etc/jumanrc $HOME/.jumanrc
RUN cd $HOME/src && \
curl -L -o knp-4.19.tar.bz2 http://nlp.ist.i.kyoto-u.ac.jp/nl-resource/knp/knp-4.19.tar.bz2 && \
tar xf knp-4.19.tar.bz2 && \
cd knp-4.19 && \
./configure && \
make && \
make install
この部分は,JUMAN, KNPのソースをダウンロードして展開,make,make installしている部分です.
特徴は,.jumanrc
ファイルをホームディレクトリにコピーしているところです.この処理は現在rootで実行しているのでこの処理をやっておきます.
ちなみに,Dockerの公式ドキュメントを読む感じだとそれぞれのソースはcurlからファイルに保存せずに直接tarに渡して実行するほうが一般的なのかもしれません.
JUMAN++を利用したいと考えている方は,ダウンロードするソースをJUMAN++に変えて実行してください.
ビルド環境等の削除
# delete download cache
RUN rm -rf $HOME/src && \
apt-get purge -y \
build-essential \
curl \
bzip2
この部分は,インストール済みのJUMAN, KNPのソースの削除,ビルド環境等の削除をおこなっています.
イメージを軽くしたいのでcurl等も削除しています.
ユーザ変更と実行コマンドの指定
# change user
RUN chown -R app:app $HOME/*
WORKDIR $HOME/pyknp_test
USER app
# set CMD
CMD ["python3", "pyknp_test.py"]
この部分で,ホームディレクトリの中身の権限をappユーザに変更しています.これにより,コマンドの実行をappユーザとしておこなえるようにしています.
また,ワーキングディレクトリをコピーした開発ディレクトリにしています.docker-compose.yml
側でイメージ内のパス指定をしなくて済むようこうしておくと良いでしょう.
docker-compose.yml
version: '3'
services:
pyknp:
build: .
volumes:
- .:/home/app/pyknp_test
docker-compose.yml
は結構シンプルです.pyknp
というサービス名で先程のDockerfile
をビルドして実行させています.
また,先程設定したワーキングディレクトリ直下に開発ディレクトリの中身をバインドします.これで開発ディレクトリの中身を変更しても再度ビルドすること無く実行できます.
おわりに
何となくいい感じに開発環境ができたのではないでしょうか.
ディレクトリの構成が簡単なのでイメージ公開やらリポジトリ公開までやらなくてもいいかな〜と勝手に思っています.要望あれば挑戦してみようと思いますのでコメントください.
他にも,何か良いプラクティス等あればコメント頂けると幸いです.