【Rで自然言語処理】Rからjuman++を動かし形態素解析の結果を受け取る on Windows10

いまから半年くらい前ですか。juman++をインストールしようとしてどうしてもうまくいかなかったのでした。
wanko-sato.hatenablog.com
が、ここ最近ふと思いついてあれこれ試してみた結果・・・

ついにうまくいきました!!!

といっても、実際にやっていることはかなり面倒なことなんですが。。。
いやいや、最初の設定が面倒なだけで、設定が済んだらあとは大したことないですよ、うん。

というわけで、実際にどんなことをしているのか、と、そこに至る設定の方法を書いていきます。

そもそも何をやっているのか

まず大前提として、juman++はwindows上では動作しません。
基本的にLinux上で動作することを想定しているようです。したがって、Windows上でどうにかしようと思った場合、Windows上でLinuxが動く環境が必要になります。つまり、仮想マシンです。
次に、仮想マシンに外部からアクセスする必要があります。R上から動かしたいので、コマンドプロンプトから動かせる状態が望ましい。通常、仮想マシンとはいえ異なるマシンが立ち上がっていることになっているわけで、アクセスにはパスワード認証が必要になります。Rではそこで躓いてしまうため、パスワード認証が不要なアクセス、つまりSSHの公開鍵認証方式をとる必要があります。WindowsコマンドプロンプトはそのままではSSHができませんから、openSSHを使うことになります。
で、そこまで設定ができたら、あとはRのsystem()関数で仮想マシンへのアクセスとコマンド投入を実行すれば、必要な結果がかえって来る、という仕掛けです。

つまり

  1. juman++が動作する仮想マシンWindows上に構築する
  2. 仮想マシンに公開鍵方式でSSHできる環境を作る
  3. Rから仮想マシンに投げるコマンドを生成する
  4. かえってきた結果をごにょごにょする

という流れです。
仮想化とかネットワークとかをしっかりわかっている方でしたら、たぶん上記の流れでやることはだいたい分かろうかとは思いますが、せっかく頑張ってあれこれやったので手順を残しておきたいと思います。

手順

環境

  • Windows10 Home
  • VMware player
  • Ubuntu 16.04 LTS
  • juman++ 1.02
  • openSSH v0.0.19.0
  • R 3.4.0
  • RStudio 1.0.143

たぶんこれだけです。SSH接続確認のためにTeraTermとかputtyとかも入れていますが、実際の作業で使うことはないです。
※接続検証用にTeraTermを一回だけ使う箇所があります。そこは飛ばしてもらっても大丈夫、なはず。

ちなみに、ある程度Linuxのコマンドがわかっていること、viでもnanoでも構わないのでターミナル上でテキストの編集ができること、が前提です。
Linuxなんて全く触ったことがない、という方は、どうせ仮想マシンですし、最悪OSがクラッシュしても仮想マシンを削除すれば良いだけなので、思い切ってやってみるのも手かと思います。

手順1. VMwareをインストールする

VMware WorkStation Player

フリーのVMwareのダウンロードは↑こちらから。
Windows 64bitをダウンロードしてください。
基本的に指示に従っていけば問題なくインストールできるはずです。

手順2. VMwareにUbuntu16.04をインストールする

次にVMware上にUbuntu仮想マシンを構築します。

VMWareを用いたUbuntu16.04仮想マシンの構築 — Choreonoid ホームページ

こちらが丁寧に解説してくださっています。
インストールする際、ディスクとメモリは大目にとっておいた方が良いです。
後でいくらでも変更は可能ですが、最初にやっておいた方があとあと面倒がないので。

手順3. juman++をインストールする

手順通りインストールすると、UbuntuGUIが立ち上がるはずです。このままだとコマンドが打てないので、ctrl+alt+Tでターミナルを表示します。これでコマンドを打ち込めるようになります。juman++のインストールはコマンドから行います。

qiita.com

こちら、OS XとかVirtualBoxが前提になっていますが、最初のところを飛ばせばあとは同じ手順でVMware上のUbuntuにjuman++をインストールできます。

$ sudo apt install libboost-dev # Boostインストール
$ sudo apt install build-essential # gcc等ビルドツールをインストール

手順にはbuild-essentialもインストールしていますが、自分がやったときはbuild-essentialは最新版になっていました。

$ wget http://lotus.kuee.kyoto-u.ac.jp/nl-resource/jumanpp/jumanpp-1.02.tar.xz
$ tar xJvf jumanpp-1.02.tar.xz
$ cd jumanpp-1.02/
$ ./configure
$ make
$ sudo make install

現行のjumann++最新版は1.02です。
これでjuman++のインストールが完了したはずです。

$ jumanpp

として、juman++がたちあがれば問題ありません。
ちなみに、

$ echo これはテストです。 | jumanpp

とすると、投げた文の形態素解析の結果がそのまま戻ってきます。Rからコマンドを投げるときはこの方式を使います。

手順4. openSSHの設定をする

次に、仮想マシンにアクセスするためのSSHの設定を行います。

d.hatena.ne.jp

ここでいう「ホストOS」はいま動いているWindows、「ゲストOS」はVMware上に構築したUbuntu仮想マシンのことです。
ここの前半部分、パスワード認証のところまでを行ってください。可能であれば、TeraTermなどでSSHのパスワード認証が通っていることを確認するとなおOKです。

ここで、上記リンク先の公開鍵方式のアクセス設定に移りたいところなのですが、ここに落とし穴がありました。

TeraTermで作ったSSH鍵はopenSSHで使おうとするとパーミッション不正で動きません!

当方、ここで思いっきりはまって2,3時間苦しんでいました。。。
従いまして、上記リンク先で紹介されているTeraTermSSH鍵を生成する方法ではなく、openSSHに同梱されているssh-keygen.exeを使ってSSH鍵を生成します。そうすることでパーミッションの問題をクリアすることができます。

はい、まず上記でUbuntuの設定までできている状態ですね。
次にWindows側のopenSSHを設定します。

github.com

こちらから最新のopenSSHをダウンロードしてください。OpenSSH-Win64.zipで良いでしょう。
インストールは不要ですので、解凍したフォルダをどこか適当なところにおいておいてください。環境変数でパスを通しても良いですし、.exeファイルへのフルパスをコマンドプロンプトに書いても良いです。で、コマンドプロンプトssh-keygen.exeを実行し、公開鍵と秘密鍵を生成したら、公開鍵(.pubがついている方)をUbuntuにコピーし、上記リンク先の「opensshに公開鍵を設定 (Ubuntuでの作業)」以下を行います。
ただし、

$sudo mkdir .ssh
$sudo cat id_rsa.pub>>.ssh/authorized_keys

この部分はsudoでやるとうまくいかなかったので、当方はsudoを外して実行しました。
で、sshd_configの書き換えとリスタートまで完了したら設定は完了。公開鍵方式でうまく仮想マシンにアクセスできるかどうか試してみましょう。
コマンドプロンプトからSSHの公開鍵方式でアクセスするには以下のコマンドを使います。

> ssh.exe [id]@[ip address] -i [秘密鍵のフルパス]

パスを通してあればssh.exeでいけますが、パスを通していない場合はフルパスを書いてください。
[id]は仮想マシンのユーザーIDです。
[ip address]はUbuntuのターミナルでifconfigをしたときに表示される[inet xxx.xxx.xx.xxx]の数字部分です。
[秘密鍵のフルパス]は、ssh-keygen.exeで生成した秘密鍵(.pubがついていない方)のフルパスです。

このコマンドでエラーなく仮想マシンにログインできればOKです。
ちなみに自分の場合、仮想マシン関連一式をDドライブにぶち込んであり、かつパスを通していないので、こんな感じになります。

D:\OpenSSH-Win64\ssh.exe hogehoge@xxx.xxx.xx.xxx -i D:\key\id_rsa

もちろん仮想マシンが立ち上がっていないといけませんので、仮想マシンサスペンドやシャットダウンはしないでおいてくださいね。

手順5. Rから実行するコマンドを生成する

ログインコマンドの後ろにUbuntu上で実行させたいコマンドをくっつければ、そのコマンドを実行してくれます。たとえば、

D:\OpenSSH-Win64\ssh.exe hogehoge@xxx.xxx.xx.xxx -i D:\key\id_rsa ls

とすればlsを実行してファイルとディレクトリのリストがかえってきます。Rからjuman++を実行するのにこの性質を利用します。
ちなみに、Rからコマンドプロンプトにコマンドを投げて実行させる方法は以前、この記事で書きました。

wanko-sato.hatenablog.com

要はsystem()関数にコマンドを投げてやってその結果を受け取る、というものです。上記の記事はWindowsにインストールしたMeCabを動かしていますが、今回は仮想マシン上のjuman++を動かしてやるのです。

testout <- system("cmd.exe",input="D:\\OpenSSH-Win64\\ssh.exe hogehoge@xxx.xxx.xx.xxx -i D:\\key\\id_rsa \"echo これはテストです。 | jumanpp\"", intern=T)

このとき、いくつか注意点があります。
ssh.exeと秘密鍵へのフルパスをinput=""の中で書いていますが、Rでは\はエスケープ文字なので、\\としなければいけません。また、echoからjumanppまでをダブルクォーテーションで囲む必要がありますが、ダブルクォーテーションもエスケープ文字なので、\"と書いてあげる必要があります。そこだけ注意して、後は形態素解析したい文を入れ替えるなりなんなり好きにしてもらえればOKです。さて、これを実行すると、

> testout
 [1] "Microsoft Windows [Version 10.0.14393]"                                                                                                                                                 
 [2] "(c) 2016 Microsoft Corporation. All rights reserved."                                                                                                                                   
 [3] ""                                                                                                                                                                                       
 [4] "C:\\Users\\HogeHoge\\Documents>D:\\OpenSSH-Win64\\ssh.exe hogehoge@xxx.xxx.xx.xxx -i D:\\key\\id_rsa_rsa \"echo これはテストです。 | jumanpp\""                                             
 [5] "縺薙l 縺薙l 縺薙l 謖\x87遉コ隧\x9e 7 蜷崎ゥ槫ス「諷区欠遉コ隧\x9e 1 * 0 * 0 NIL"                                                                                                          
 [6] "縺ッ 縺ッ 縺ッ 蜉ゥ隧\x9e 9 蜑ッ蜉ゥ隧\x9e 2 * 0 * 0 NIL"                                                                                                                                     
 [7] "繝\x86繧ケ繝\x88 縺ヲ縺吶→ 繝\x86繧ケ繝\x88 蜷崎ゥ\x9e 6 繧オ螟牙錐隧\x9e 2 * 0 * 0 \"莉」陦ィ陦ィ險\x98:繝\x86繧ケ繝\x88/縺ヲ縺吶→ 繧ォ繝\x86繧エ繝ェ:謚ス雎。迚ゥ 繝峨Γ繧、繝ウ:謨呵ご繝サ蟄ヲ鄙\x92\""
 [8] "縺ァ縺\x99 縺ァ縺\x99 縺\xa0 蛻、螳夊ゥ\x9e 4 * 0 蛻、螳夊ゥ\x9e 25 繝\x87繧ケ蛻怜渕譛ャ蠖「 27 NIL"                                                                                             
 [9] "縲\x82 縲\x82 縲\x82 迚ケ谿\x8a 1 蜿・轤ケ 1 * 0 * 0 NIL"                                                                                                                                  
[10] "EOS"                                                                                                                                                                                    
[11] ""                                                                                                                                                                                       
[12] "C:\\Users\\HogeHoge\\Documents>"     

おぅふ。。。

でも、こんなときは慌てずに、文字コードを変換してやれば良いのです。

> iconv(testout,"utf8")
 [1] "Microsoft Windows [Version 10.0.14393]"                                                                       
 [2] "(c) 2016 Microsoft Corporation. All rights reserved."                                                         
 [3] ""                                                                                                             
 [4] NA                                                                                                             
 [5] "これ これ これ 指示詞 7 名詞形態指示詞 1 * 0 * 0 NIL"                                                         
 [6] "は は は 助詞 9 副助詞 2 * 0 * 0 NIL"                                                                         
 [7] "テスト てすと テスト 名詞 6 サ変名詞 2 * 0 * 0 \"代表表記:テスト/てすと カテゴリ:抽象物 ドメイン:教育・学習\""
 [8] "です です だ 判定詞 4 * 0 判定詞 25 デス列基本形 27 NIL"                                                      
 [9] "。 。 。 特殊 1 句点 1 * 0 * 0 NIL"                                                                           
[10] "EOS"                                                                                                          
[11] ""                                                                                                             
[12] "C:\\Users\\HogeHoge\\Documents>" 

はい、というわけで無事にjuman++の形態素解析の結果をとってくることができました。
後は必要なところだけ抽出して、煮るなり焼くなりお好きにどうぞ。

応用可能性

ちなみに、この方式ならば仮想マシン上で動くコマンドなら何でもいけるはずなので、例えば最新版のneologdをあてたMeCab形態素解析したり、なんてこともできるはずです。

ならはじめっから全部Linuxでやれよ

というのはおっしゃる通りなのですが、手元にとりあえずWindowsしかなく、間に余計な処理を挟まずにRで最後までやってしまいたいRおじさんにはオススメの手法かと思います。
ちなみに、当方、セキュアなサーバの構築とかはまるっきり不案内ですので、今回の方法がセキュリティ的に大丈夫かどうかまでは検証しておりませんのであしからず。