係り受け解析はあくまで例なので、これに関して詳しく知りたい人は他をあたってください。本稿はdokku(Bashスクリプトで作られたHerokuライクなオンプレミスPaaS環境)上でCaboChaを用いて係り受け解析をする簡単なAPIを作成する、というシナリオで、システムコマンドをインストールするような複雑なアプリケーションの作成方法を解説するものです。
といっても、その方法はお粗末なものなので、より良い方法があるかもしれません。あくまで手軽に実験することができる、程度で読んでください。
dokkuについて
dokkuはBashスクリプトで作られたHerokuライクなオンプレミスPaaS環境です。Dockerコンテナを作成し、Herokuが提供しているbuildpackを利用してアプリケーションをデプロイします。インストールやHTTPS化などについては以下を御覧ください。
係り受け解析について
係り受け解析というと馴染みのない方もいらっしゃると思います。ある文中の文節間にどのような修飾(係)・被修飾(受)関係があるかを解析するものです。形態素解析では文を品詞に分解するところまでを行いますが、係り受け解析をすることにより、自然言語の文をよりシステムが理解しやすいように落としこむことができます。
日本語ではCaboChaを使うのが一般的ではないかと思います。今回はこのCaboChaを用いて係り受け解析をするAPIサーバを作成する、ということを目標にします。
本題
というわけで、ここからはcabocha-api
という名前のアプリケーションを作成してdokkuにデプロイするまでを解説していきます。Herokuで少し複雑なアプリケーションを作ったことがある方はすぐに理解できるかと思います。
dokkuでheroku-buildpack-multiを使う
buildpackとは、言語やフレームワーク、アプリケーション等を手軽に利用できるようパッケージ化したものです。Herokuによって作られたものや、ユーザによって作られたものが存在します。
通常、Herokuにアプリケーションをデプロイする際は1つのbuildpackが自動的に選択されます。ffmpegやmecab等のbuildpack使いたい場合は言語のbuildpackとあわせて複数のbuildpackを利用できるようにする必要があります。複数のbuildpackを扱うには、buildpackとしてheroku-buildpack-multiを指定します。
$ dokku apps:create cabocha-api $ dokku config:set cabocha-api BUILDPACK_URL=https://github.com/ddollar/heroku-buildpack-multi.git
これでdokkuのアプリケーション作成と複数buildpackを扱う設定がおわりました。
buildpackを設定する
MacにHomebrewがあるのと同じく、LinuxにはLinuxbrewがあります。LinuxbrewはHomebrewのforkです。そのため、Homebrewで入れられるアプリケーションのほとんどはLinuxbrewでも入れることができます。本稿ではLinuxbrewを用いてCaboChaをインストールします。
ところが、本家のLinuxbrewではCaboChaをインストールすることができません。素直にインストールしようとするとlibiconv
がない、とエラーを吐いてデプロイプロセスが強制終了します。そこで、独自のCaboChaインストーラを利用するために修正を施したheroku-buildpack-linuxbrewを用います。また、APIサーバをRubyで書くのでRubyのbuildpackも設定します。
以下を.buildpacks
に記述してください。
https://github.com/masawada/heroku-buildpack-linuxbrew.git https://github.com/heroku/heroku-buildpack-ruby.git
CaboChaのインストールを設定する
heroku-buildpack-linuxbrewは.cellar
というファイルにアプリケーション名を記述するだけで、デプロイ時にそのアプリケーションを自動的にインストールします。ところが、本家のheroku-buildpack-linuxbrewでは独自のHomebrew formulaを利用することができません(brew tapすることができない)。そこでmasawada/heroku-buildpack-linuxbrewではtapをすることができるよう改良を施しています。
CaboChaのformulaにはlibiconvのオプションを設定している箇所があり、これが悪さをしているため、オプションを外した独自formulaをGitHub上に用意し、これを利用することにします。
以下のように.cellar
を記述することで修正したCaboCha formulaを利用することができます。
tap masawada/cabocha-without-iconv install cabocha-without-iconv
環境変数を設定する
ここからはdokkuのアプリケーションに環境変数を幾つか設定していきます。これを行わないとLinuxbrewでのビルドがうまくいかなかったり、サーバに用いるcabocha.gem
のインストールがうまくいかなかったりします。
$ dokku config:set cabocha-api LIBRARY_PATH=/app/.linuxbrew/lib $ dokku config:set cabocha-api LD_LIBRARY_PATH=/app/.linuxbrew/lib $ dokku config:set cabocha-api LD_INCLUDE_PATH=/app/.linuxbrew/include $ dokku config:set cabocha-api C_INCLUDE_PATH=/app/.linuxbrew/include $ dokku config:set cabocha-api CPLUS_INCLUDE_PATH=/app/.linuxbrew/include $ dokku config:set cabocha-api PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/app/.linuxbrew/bin
デプロイ後に環境変数を設定してからrebuildするとうまく設定されないようなので、必ず最初に設定するようにしてください。
APIサーバを書く
ここからはRubyとSinatraを用いてAPIサーバを書いていきます。
- Gemfile: 依存ファイル
- server.rb: 本体
- Procfile: dokku上でアプリケーションを起動するためのスクリプト
web: command
という形式で書くことで、アプリケーションを起動し、リバースプロキシを設定する
また、事前にbundle install
を実行してGemfile.lock
を生成してください。これがない場合、デプロイ時にプロセスが強制終了します。
Gemfile
source 'https://rubygems.org' gem 'sinatra' gem 'cabocha'
server.rb
require 'sinatra' require 'cabocha' get '/' do parser = CaboCha::Parser.new tree = parser.parse(params["q"]) @result = tree.toString(CaboCha::OUTPUT_RAW_SENTENCE) erb :index end __END__ @@index <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> <style>pre { font: normal 14px/20px courier; }</style> </head> <body> <pre> <%= @result %> </pre> </body> </html>
Procfile
web: ruby server.rb -p $PORT
デプロイする
ここまできたらいつもどおりデプロイするだけです。上記までの作業をgit commit
し、git remote add dokku
でdokkuの情報を登録します。
$ git push dokku master
でデプロイが始まります。幾つかのファイルをビルドするので、全作業を終えるのに数分かかります。作業を終えたらサーバにアクセスしてみましょう。ルートに?q=文章
とクエリをつけることで、その文章の係り受け解析を行うことができます。
このように表示されれば成功です。
まとめ
多少手順は複雑でしたが、作業量としてはそんなに多くないのではないかと思います。Herokuの場合でも環境変数の設定をうまく行えば全く同じリポジトリをデプロイできるような気がしますが、なぜか失敗しました。今回はdokkuで動かすまで、ということでここまでにしておきます。
最後に、ここで作成したアプリケーションを以下のリポジトリに置いていますので、よろしければご活用ください(そのまま使うのは良くないです、アクセス制限をかける、入力文字列を制限するなどしたほうが良いかもしれません)。