DatabricksにMeCabとNEologdを「恒久的に」インストールしてみた
本記事は,Japan Digital Design Advent Calendar 2023の6日目の記事になります.
三菱UFJフィナンシャル・グループの戦略子会社であるJapan Digital Design株式会社でデータサイエンティストをしている高田珠武己 (たかだかぶき) です.
本記事では,DatabricksにMeCabとNEologdをインストールする方法を紹介します.ただし,単にインストールするのではなく,Databricksの利用時に毎回インストールする必要がないようにします.
MeCabは日本語の形態素解析を行う最も有力なエンジンの1つであり,日本語の自然言語処理において土台となるツールです.NEologdはMeCabを利用するための辞書の1つであり,Web上に存在する新語が採録されていることが特徴です (ただし,例えばZenn > [自然言語処理] NEologdを自前で改造して使っている話に記載されているように,2020年9月を最後にNEologdの更新が止まっていることには注意が必要です).
一度インストールしたMeCabとNEologdは,ローカルな環境であればアップデートしない限り使い続けることができます.一方,弊社の分析環境として利用しているDatabricksでは,デフォルトでインストールされていないライブラリを使う場合クラスター (計算リソース) の再起動ごとにインストールする必要があります.
Databricksはクラウド上で大量データを分析するためのプラットフォームであり,ボタンクリックで計算リソースを簡単に確保することができます.デフォルトでインストールされていないライブラリはノートブック (Jupyter Notebookと同じようなUIです) 内やクラスターの設定などでインストールすることが可能です.多くのPythonライブラリはpipでインストールすることができ,あまり時間はかかりません.
しかし,MeCabとNEologdの場合pipではインストールできません.正確には,辞書として例えばUnidic Liteを用いるなら,MeCabのPythonラッパーであるmecab-python3とともにpipでインストールすることでMeCabを利用することができます.一方,NEologdのインストール時にはMeCab本体 (Pythonラッパーではありません) が必要となり,MeCab本体とNEologdはpipでインストールすることはできません.加えて,NEologdのインストールは時間を要するため (そのときによって異なりますが10分前後のことが多いです),毎回インストールすることは避けたいと考えられます.
そこで,本記事ではインストールしたMeCabとNEologdを「なるべく壊さずに」DBFSに保存することで,毎回のインストールを不要にする方法を説明します.DBFS (Databricks File System) はDatabricksで利用可能なクラウド上のファイルストレージです.
DBFSに直接MeCabをインストールしたいところですが,直接インストールしようとすると途中で失敗します.これはソフトウェア内で使われているシンボリックリンクをDBFS上に作成できないためです.
以下では,一旦ディレクトリ /databricks/driver (以下ではDriverと呼びます) の配下にMeCabとNEologdをインストールし,シンボリックリンク以外のファイルをDBFSにコピーする方針をとります.Driverはクラスターごとに割り当てられるディレクトリとなっており,クラスターの再起動でリセットされるため,Driver配下に永続的にファイルを保存することはできません.したがって,インストールしたMeCabとNEologdを利用する際は,DBFSからDriverに再コピーしてシンボリックリンクを作成し直すことにします.
以下の実験はDatabricks Runtime Version 13.3 LTS MLで行いました.
Driverへのインストール
MeCabとIPA辞書 (mecab-ipadic),NEologd辞書 (mecab-ipadic-NEologd) をDriver配下の /databricks/driver/opt/mecab にインストールする方法を説明します.主に以下の記事を参照しました.
なお,データブリックス・ジャパン株式会社の方が以下の記事においてapt-getによるMeCabのインストールを紹介されていますが,同じ手順を試したところMeCabの動作確認でエラーが発生したため,下記ではソースコードから make install する方法を実施しています.apt-getが失敗する詳しい原因は未調査ですが,弊社の環境のDatabricksノートブックで %sh yes | apt-get install mecab を実行したところインストールが成功しませんでした.
MeCabのインストール
MeCabのインストール方法は公式サイトに記載されています.今の状況に合わせてコードを次のように変更します.
%sh -e
mkdir -p /databricks/driver/source/mecab
cd /databricks/driver/source/mecab
wget '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
./configure --prefix=/databricks/driver/opt/mecab --with-charset=utf8
make
make check
sudo make install
デフォルトのインストール先である /usr/local には他のソフトウェアが初めからインストールされているので,後程DBFSにMeCabと辞書をコピーする際のコピー対象をわかりやすくするためにインストール先を別の場所に指定します.具体的には,./configure でインストール先ディレクトリ (--prefix) として,Driver配下に作成したディレクトリを指定します.また,--with-charset=utf8 で文字コードをUTF-8に指定します.
仮にインストール先としてDBFS配下を指定して上記のコードを実行した場合,一見成功したように見えますが,sudo make install の出力の中に下記のメッセージが現れ失敗していることがわかります.ln -s はシンボリックリンクを作成するコマンドであり,MeCabインストール先の lib ディレクトリにおいて,共有ライブラリ libmecab.so.2.0.0 へのシンボリックリンク libmecab.so.2, libmecab.so を作成しようとしています (注釈1を参照).後続手順を進めようとしても,sudo ldconfig を実行すると /sbin/ldconfig.real: Can't link /dbfs/FileStore/tables/ANY_DIR/lib/libmecab.so.2 to libmecab.so.2.0.0 と表示されたり,mecab-ipadicの make で /dbfs/FileStore/tables/ANY_DIR/libexec/mecab/mecab-dict-index: error while loading shared libraries: libmecab.so.2: cannot open shared object file: No such file or directory と表示されたりしてうまくいきません.
libtool: install: (cd /dbfs/FileStore/tables/ANY_DIR/lib && { ln -s -f libmecab.so.2.0.0 libmecab.so.2 || { rm -f libmecab.so.2 && ln -s libmecab.so.2.0.0 libmecab.so.2; }; })
ln: failed to create symbolic link 'libmecab.so.2': Function not implemented
ln: failed to create symbolic link 'libmecab.so.2': Function not implemented
libtool: install: (cd /dbfs/FileStore/tables/ANY_DIR/lib && { ln -s -f libmecab.so.2.0.0 libmecab.so || { rm -f libmecab.so && ln -s libmecab.so.2.0.0 libmecab.so; }; })
ln: failed to create symbolic link 'libmecab.so': Function not implemented
ln: failed to create symbolic link 'libmecab.so': Function not implemented
環境変数 PATH と共有ライブラリ格納先の更新
MeCabの利用に必要な辞書をインストールする前に,環境変数 PATH と共有ライブラリ格納先の設定を更新します.
まずは環境変数 PATH にMeCabインストール先の bin ディレクトリを追加します.環境変数を設定する方法として以下の方法を試しましたが,その中で唯一うまくいった方法がPythonの os.environ (最後の方法) でした.環境変数 PATH の設定がノートブック内で反映されているかどうかは %sh echo $PATH で確認することができます.
ノートブック内で %sh export を使って変数を定義すると,同一セル内では変数の値が反映されましたが,他のセルでは反映されませんでした.
環境変数を export するShell Scriptをノートブック内で %sh source または %sh . で実行すると,同一セル内では変数の値が反映されましたが,他のセルでは反映されませんでした.
環境変数を export するShell ScriptをInit Scriptsに追加してクラスターを立ち上げても,ノートブックでは変数の値が反映されませんでした.
クラスター設定のAdvanced options > Spark > Environment Variablesで追加した環境変数は PATH 以外の名前ならノートブックに反映されましたが,PATH を設定しようとするとクラスターが立ち上がりませんでした (Global init script failure: Global init script Enforce BucketOwnerFullControl failed: Script exit status is non-zero というメッセージが表示されました).
ノートブック内で os.environ を使って環境変数 PATH を更新したところ,他のセルにも変数の値が反映されました (別の名前の環境変数も設定できました).なお,os.environ を使って更新した環境変数はノートブックのClear Stateでリセットされます.
結果として環境変数 PATH の更新は次のコードで行いました.
import os
os.environ['PATH'] += ':/databricks/driver/opt/mecab/bin'
次に,mecab-config --libs-only-L でMeCabインストール先の lib ディレクトリパス (すなわち /databricks/driver/opt/mecab/lib) を出力 (echo) し,それを sudo tee で /etc/ld.so.conf.d/mecab.conf に書き込みます (mecab-config の動作についてはGitHubを参照).なお,mecab.conf の格納先はMeCabインストール先の配下ではないことに注意してください.sudo ldconfig を実行すると,共有ライブラリ格納先の設定が更新されます (注釈2, 3を参照).
%sh -e
mecab-config --libs-only-L | sudo tee /etc/ld.so.conf.d/mecab.conf
sudo ldconfig
IPA辞書のインストール
IPA辞書 (mecab-ipadic) のインストールは,MeCab公式サイトの方法にオプションを追加すれば実行できます../configure において --prefix をMeCabインストール先と同じパスにし,--with-mecab-config (mecab-config が存在するディレクトリ) をMeCabインストール先の bin ディレクトリに設定します.また,--with-charset=utf8 を指定します (NEologd公式日本語マニュアルによると,NEologd辞書をインストールするためにはIPA辞書の文字コードがUTF-8である必要があります).
%sh -e
mkdir -p /databricks/driver/source/mecab-ipadic
cd /databricks/driver/source/mecab-ipadic
wget '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
./configure \
--prefix=/databricks/driver/opt/mecab \
--with-mecab-config=/databricks/driver/opt/mecab/bin/mecab-config \
--with-charset=utf8
make
sudo make install
NEologd辞書のインストール
NEologd辞書 (mecab-ipadic-NEologd) のインストールは公式日本語マニュアルに記載されている方法にオプションを追加して行います.
%sh -e
cd /databricks/driver/source
git clone --depth 1 https://github.com/neologd/mecab-ipadic-neologd.git
cd mecab-ipadic-neologd
./bin/install-mecab-ipadic-neologd -n -a -y -p /databricks/driver/opt/mecab/lib/mecab/dic/neologd
install-mecab-ipadic-neologd の各オプションは以下の意味を持ちます.
-n: 最新の辞書を取得
-a: 全部入りの辞書を取得 (デフォルトでは全部入りになっていません)
-y: --forceyes の意味 (このオプションを付けないと,Databricksノートブックでは Do you want to install mecab-ipadic-NEologd? Type yes or no. というメッセージに対して yes をタイプできずインストールが途中で終了します)
-p: インストール先を指定
また,install-mecab-ipadic-neologd を sudo で実行すると mecab is not found. と表示されてインストールが途中で止まるので,sudo は付けません.実際,%sh mecab -v はバージョン情報を表示しましたが,%sh sudo mecab -v を実行すると command not found と表示されました.
全般の注意
上記のインストール作業における全般的な注意を以下に記載しておきます.
DatabricksノートブックでShell Scriptを表すマジックコマンドは %sh ですが,これを %sh -e と書くと,異常終了 (Shell Scriptにおけるゼロでない終了状態) に対してエラーを発生させることができます (Databricks Documentation > Develop code in Databricks notebooksを参照).
Databricksノートブックで %sh cd DIR_NAME を実行すると,他のセルにディレクトリ移動が反映されない一方で,cd DIR_NAME は他のセルに反映されるため,コマンドごとにセルを分ける場合は cd のみ %sh (または %sh -e) を除く必要があります.
DBFSへのコピー
以上でMeCabと辞書をDriver配下へインストールすることができましたが,Driver配下に保存したファイルはクラスター終了とともに消えるため,インストールしたソフトウェアをDBFSにコピーします (Databricksのクラスターは起動時間に比例して料金がかかるため,弊社では最後にクラスターが動いてから2時間で自動終了する設定にすることが多いです).ただし,シンボリックリンクをDBFSにコピーすることはできないため,その他のファイルをDBFSにコピーしておき,シンボリックリンクはMeCabの利用時に再作成します.
今回の場合MeCabインストール先の lib ディレクトリに格納されている libmecab.so.2, libmecab.so が libmecab.so.2.0.0 へのシンボリックリンクとなっています.このことは,%sh ls -lh /databricks/driver/opt/mecab/lib の出力が次のようになることから確認できます (mmm dd HH:MM にはインストール日時が入ります).
total 4.8M
-rw-r--r-- 1 root root 2.9M mmm dd HH:MM libmecab.a
-rwxr-xr-x 1 root root 974 mmm dd HH:MM libmecab.la
lrwxrwxrwx 1 root root 17 mmm dd HH:MM libmecab.so -> libmecab.so.2.0.0
lrwxrwxrwx 1 root root 17 mmm dd HH:MM libmecab.so.2 -> libmecab.so.2.0.0
-rwxr-xr-x 1 root root 2.0M mmm dd HH:MM libmecab.so.2.0.0
drwxr-xr-x 3 root root 4.0K mmm dd HH:MM mecab
したがって,上記のシンボリックリンクを unlink で削除し,Driver配下のインストール先ディレクトリをDBFS配下へコピーします.
%sh -e
unlink /databricks/driver/opt/mecab/lib/libmecab.so.2
unlink /databricks/driver/opt/mecab/lib/libmecab.so
mkdir -p /dbfs/FileStore/tables/ANY_DIR
cp -r /databricks/driver/opt/mecab/. /dbfs/FileStore/tables/ANY_DIR/
なお,仮に libmecab.so.2, libmecab.so を削除せずに cp -r でインストール先ディレクトリをDBFSへコピーしようとしても,下記のメッセージが表示されてシンボリックリンクがコピーされません.また,libmecab.so.2, libmecab.so を削除しなくても cp -Lr (-L は --dereference の意味) なら以下のメッセージが表示されずコピーされますが,この場合シンボリックリンクではなく参照先の実体ファイル (すなわち libmecab.so.2.0.0) がコピーされてしまいます.
cp: cannot create symbolic link '/dbfs/FileStore/tables/ANY_DIR/lib/libmecab.so.2': Function not implemented
cp: cannot create symbolic link '/dbfs/FileStore/tables/ANY_DIR/lib/libmecab.so': Function not implemented
MeCabの利用
では,MeCabを実際に使ってみましょう.クラスターを再起動または別のクラスターを利用し,MeCabが動作するかを確認します.
Driverへの再コピーと環境変数設定
MeCabの利用時はDBFSからDriver配下 (インストール先として指定したディレクトリ) へソフトウェアをコピーします (以下のコードでは念のためコピー先のディレクトリをあらかじめ削除しています).DBFSにはシンボリックリンクを保存しなかったため,ln -s を利用し,libmecab.so.2, libmecab.so を libmecab.so.2.0.0 へのシンボリックリンクとして作成します.
%sh -e
rm -rf /databricks/driver/opt/mecab/
mkdir -p /databricks/driver/opt/mecab
cp -r /dbfs/FileStore/tables/ANY_DIR/. /databricks/driver/opt/mecab/
cd /databricks/driver/opt/mecab/lib
ln -s libmecab.so.2.0.0 libmecab.so.2
ln -s libmecab.so.2.0.0 libmecab.so
MeCabが動作するようにするため,環境変数 PATH を更新します.mecab.conf 作成と ldconfig 実行を行わなくても (なぜか) MeCabは動作しましたが,インストール時と同じ状態にするために一応行います.
import os
os.environ['PATH'] += ':/databricks/driver/opt/mecab/bin'
%sh -e
mecab-config --libs-only-L | sudo tee /etc/ld.so.conf.d/mecab.conf
sudo ldconfig
DBFSへのコピーとDriverへの再コピーを行いましたが,MeCabで設定されているインストール先が /databricks/driver/opt/mecab のままであることは次のコードで確認できます.
%sh -e
mecab-config --prefix
次に,環境変数 MECABRC を設定します (Qiita > Mecabをホームディレクトリ下にインストールする方法を参照).これを行わないと,下記でPythonを使ってMeCabを実行した際に no such file or directory: /usr/local/etc/mecabrc というメッセージのエラーが発生します.
os.environ['MECABRC'] = '/databricks/driver/opt/mecab/etc/mecabrc'
PythonでMeCabを利用するため,Pythonラッパーをインストールします.ノートブック内で次を実行するか,またはクラスターに mecab-python3 をインストールしておきます.
!pip install mecab-python3
あとは次のようにインポートすればPythonでMeCabを利用できます.
import MeCab
バージョン確認
初めの動作確認として,MeCabのバージョン確認を行います.
入力:
%sh
mecab -v
出力:
mecab of 0.996
Shell Scriptでの動作確認
Shell ScriptでMeCabの動作確認を行います.まずはデフォルトのIPA辞書 (mecab-ipadic) を利用します.MeCab設定ファイルの /databricks/driver/opt/mecab/etc/mecabrc の中に dicdir = /databricks/driver/opt/mecab/lib/mecab/dic/ipadic と記載されているため,mecabrc を書き換えなければデフォルトの辞書はIPA辞書になります.
入力:
%sh
# 以下の2つは同じ出力
echo "三菱UFJ銀行のアプリで振込できるよ!" | mecab
echo "三菱UFJ銀行のアプリで振込できるよ!" | mecab -d /databricks/driver/opt/mecab/lib/mecab/dic/ipadic
出力:
三菱 名詞,固有名詞,組織,*,*,*,三菱,ミツビシ,ミツビシ
UFJ 名詞,一般,*,*,*,*,*
銀行 名詞,一般,*,*,*,*,銀行,ギンコウ,ギンコー
の 助詞,連体化,*,*,*,*,の,ノ,ノ
アプリ 名詞,一般,*,*,*,*,*
で 助詞,格助詞,一般,*,*,*,で,デ,デ
振込 名詞,サ変接続,*,*,*,*,振込,フリコミ,フリコミ
できる 動詞,自立,*,*,一段,基本形,できる,デキル,デキル
よ 助詞,終助詞,*,*,*,*,よ,ヨ,ヨ
! 記号,一般,*,*,*,*,!,!,!
EOS
辞書をNEologd (mecab-ipadic-NEologd) に変えると,「三菱UFJ銀行」が1つの単語にまとめられていることがわかります.
入力:
%sh
echo "三菱UFJ銀行のアプリで振込できるよ!" | mecab -d /databricks/driver/opt/mecab/lib/mecab/dic/neologd
出力:
三菱UFJ銀行 名詞,固有名詞,一般,*,*,*,三菱UFJ銀行,ミツビシユーエフジェーギンコウ,ミツビシユーエフジェーギンコー
の 助詞,連体化,*,*,*,*,の,ノ,ノ
アプリ 名詞,固有名詞,一般,*,*,*,アプリ,アプリ,アプリ
で 助詞,格助詞,一般,*,*,*,で,デ,デ
振込 名詞,サ変接続,*,*,*,*,振込,フリコミ,フリコミ
できる 動詞,自立,*,*,一段,基本形,できる,デキル,デキル
よ 助詞,終助詞,*,*,*,*,よ,ヨ,ヨ
! 記号,一般,*,*,*,*,!,!,!
EOS
Pythonでの動作確認
PythonでMeCabを利用する場合は次のコードを実行すると,IPA辞書とNEologd辞書それぞれについてShell Scriptと同じ結果が出力されます.
# IPA辞書の場合 (2つとも同じ出力)
tokenzier = MeCab.Tagger('')
print(tokenzier.parse('三菱UFJ銀行のアプリで振込できるよ!'))
tokenzier = MeCab.Tagger('-d /databricks/driver/opt/mecab/lib/mecab/dic/ipadic')
print(tokenzier.parse('三菱UFJ銀行のアプリで振込できるよ!'))
# NEologd辞書の場合
tokenzier = MeCab.Tagger('-d /databricks/driver/opt/mecab/lib/mecab/dic/neologd')
print(tokenzier.parse('三菱UFJ銀行のアプリで振込できるよ!'))
まとめ
本記事では,Databricks環境で形態素解析エンジンのMeCabとNEologd辞書をインストールする方法を紹介しました.Databricksではクラスターをボタンクリックで立ち上げることで簡単に計算リソースを確保することができるため,データサイエンティストにとって使いやすい分析環境となっています.一方で,MeCabのようなソフトウェアはインストール後に完全な形で (シンボリックリンクを含めて) 保存しておくことができないため,シンボリックリンクを除いてDBFSに保存しておき,利用時にシンボリックリンクを復活させる方法を説明しました.また,Databricksノートブックにおける環境変数や共有ライブラリ格納先の設定方法も説明しました.これで毎回クラスターを立ち上げてからインストールを待つ必要はありません.
本記事の実験を行うにあたり,初めデータサイエンティストの蕭喬仁さんがDatabricksへのMeCabとNEologdのインストールを行い,その後高田がクラスター立ち上げ毎のインストールを不要にするための修正を行いました.蕭さん,ありがとうございました!蕭さんはAdvent Calendar 4日目の記事としてKaggle LLMコンペまとめを執筆していますので,ぜひそちらもご覧ください.
最後までお読みいただきありがとうございました.
Japan Digital Design株式会社では,一緒に働いてくださる仲間を募集中です.カジュアル面談も実施しておりますので下記リンク先からお気軽にお問合せください.
この記事に関するお問い合わせはこちら.
M-AIS
Kabuki Takada (高田珠武己)
注釈
libmecab.so.2.0.0, libmecab.so.2, libmecab.so のようなファイル名はLinuxの共有ライブラリで標準的です (Program Library HOWTO > Shared Librariesを参照).
libmecab.so.2.0.0 (lib<LIBRARY_NAME>.so.<VERSION_NUMBER>.<MINOR_NUMBER>.<RELEASE_NUMBER> の形式) はreal nameと呼ばれます.
libmecab.so.2 (lib<LIBRARY_NAME>.so.<VERSION_NUMBER> の形式) はsonameと呼ばれ,通常real nameへのシンボリックリンクです.
libmecab.so (lib<LIBRARY_NAME>.so の形式) はlinker nameと呼ばれ,通常sonameまたはreal nameへのシンボリックリンク (MeCabの場合real nameへのシンボリックリンク) です.
共有ライブラリ格納先の更新方法として,環境変数 LD_LIBRARY_PATH にMeCabインストール先の lib ディレクトリパスを追加する方法が紹介されている記事もあります (例えばQiita > Mecabをホームディレクトリ下にインストールする方法やSaintSouth.NET > MeCabとmecab-ipadic-NEologdとPython3で形態素解析 (ユーザーローカル環境版) を参照).これは,Linuxにおける共有ライブラリの探索が,LD_LIBRARY_PATH に記述されたパス,/etc/ld.so.conf に記述されたパス,通常ライブラリが置かれるディレクトリ (/lib と /usr/lib) の順に行われるためです (例えばLinuxやってみる! > ldconfigでライブラリパスを更新を参照).しかし,LD_LIBRARY_PATH はあくまでデバッグ用であり使用をなるべく避けた方がよいという意見があるため,mecab.conf 作成と ldconfig 実行を行うことにしました (Program Library HOWTO > Shared Librariesを参照).
Databricksの環境では /etc/ld.so.conf に include /etc/ld.so.conf.d/*.conf と記載されているため,ディレクトリ /etc/ld.so.conf.d 配下に mecab.conf を格納します.