Rust初心者がRustで全文検索サーバを作ってみたの続きです。
この記事では、Rust製の日本語形態素解析器の開発を引き継いだ経緯と、その使い方を簡単に紹介します。
開発を引き継ぐことになった経緯
冒頭でも書きましたが、Rust初心者がRustで全文検索サーバを作っています。全文検索サーバを作り始めると、日本人なのでどうしても日本語のドキュメントをインデックスして検索したくなります。日本語を上手く検索インデックスに登録するには日本語形態素解析器を利用するのが一般的です。
日本語形態素解析器、どれを使おうかな?とユーザの立場でいたのが、いつの間にか開発を引き継ぐことになりました。
日本語形態素解析器といえば、大御所のMeCabがあります。歴史も長く、Python、Ruby、JavaからMeCabを利用するためのバインディングも用意されています。
OSSの検索エンジンの世界ではLucene/Solr、Elasticsearchが多くの企業や団体で採用されていますが、その中で日本語を扱うために利用されているのがJava製の日本語形態素解析器Kuromoji(Atilika版/Lucene版)です。MeCabとは異なり、形態素辞書をJarの中に同梱し、Jarファイルの配布によって簡単にデプロイできるのも特徴の一つです。最近ではSudachiというJava製の日本語形態素解析器も登場し、一部ではElasticsearchで利用され始めているようです。KuromojiがLuceneにコントリビュートされる前は、Senや、lucene-gosenを別途ダウンロードしてクラスパスを通して使っていました。
Java以外でも、Python実装のJanome、Go実装のKagome、JavaScript実装のkuromoji.jsなど、多くのプログラミング言語で日本語形態素解析器は開発されています。
では、Rustはどうなのかというと、もちろんRustで実装された日本語形態素解析器も既に存在します。
Yoinとkuromoji-rsはどちらもIPADICを形態素辞書として組み込んだFST(Finite-state transducer)を利用した日本語形態素解析器のようです。
特にkuromoji-rsはトークナイザにKuromojiのsearchモードと同じ機能を実装しているようです。
sudachi.rsはJava製の形態素解析器SudachiのRust実装です。詳しくはこちら(Rustによる自然言語処理ツールの実装: 形態素解析器「sudachi.rs」)を参照してください。
kuromoji-rsの開発者Paul Masurel氏は、Rust製の全文検索ライブラリTantivyの開発者でもあります。
既にTantivyを使って全文検索サーバを開発しているので、同じ人が開発しているなら、これにしてみようと言うことでkuromoji-rsを使ってみることにします。
kuromoji-rsはライブラリとして提供されているため、まずはその使い方を理解するため、MeCabのようなCLIを作ってみる事から始めます。
CLIを作り始める際にCargo.toml
にkuromoji-rsへの依存を記述しようとしたのですが、どうやらまだcrates.ioに登録されていいないようです。crates.ioへ登録する予定はないかとGitHubで問い合わせしますが、次のような返事をもらいます。
Would you take over the project :) ?
思わぬ返事に戸惑いましたが、ふと昨年末のKuromoji忘年会に参加した帰りのツイートを思い出します。
エンジニアの嗜みとして形態素解析器少しくらい触ったほうがいいかな?
— Minoru OSUKA (@minoru_osuka) December 17, 2019
興味はあったものの、なかなか手を出せないでいた形態素解析器。エンジニアの嗜みとして少しはかじっていたほうがいいのは?とも考えていたので、自信はなかったのですが、kuromoji-rsの開発を引き継ぐことにしました。
元々、kuromoji-rsはPoC的なプロジェクトらしく、作ってはみたものの、開発者自身があまり時間を割くことができず、以前からプロジェクトを引き継いてくれる人を探していたようでした。
引き継ぐにあたっては次のことだけお願いされました。
- MIT Licenseでの公開
- Licenseに自分の名前を残すこと
- Kuromojiという名前をプロジェクト名に使用しない (Kuromojiのプロジェクト名ハイジャックで彼らに迷惑をかけないため)
上記のことを守ってくれさえすれば好きにしてくれていいとのことでした。
Lindera
さて、開発を引き継ぐにあたって、プロジェクトに新しい名前が必要です。いろいろ案を考えましたが、最終的に「Lindera」と名付けました。
クロモジ属がプロジェクト名の由来です。
Linderaは次のOrganizationで開発を行っています。
Linderaは形態素解析のライブラリとコマンドを提供するプロジェクトです。次のリポジトリから構成されています。
- lindera: Tokenizer、Formatter
- lindera-core: Dictionary struct、Viterbi algorithm
- lindera-dictionary: Dictionary Loader
- lindera-ipadic: IPADIC Loader
- lindera-ipadic-builder IPADIC Builder
- indera-cli: Command-line interface
CLIを使ってみる
Lindera(旧kuromoji-rs)ですが、先述したようにライブラリターゲットでの提供だったので、ちょっと試したいと思ってもRustでコーディングしないといけません。そこで、このLinderaを簡単に試したりできる、デモンストレーションを行えるCLIを用意しました。
まだ、各プラットフォーム(Windows、OS X、Linux)向けにコンパイル済みの実行可能なバイナリターゲットの提供はできていません(後でバイナリターゲットの提供を予定してます)。面倒ですが、Cargoをインストールして、ソースコードからビルドするか、Cargoからインストールする必要があります。
RustとCargoのインストールはこちらを参照してください。
https://doc.rust-lang.org/cargo/getting-started/installation.html
Cargoからインストールする場合は次のコマンドでインストールできます。cargo install
した場合は${HOME}/.cargo/bin/lindera
にバイナリがインストールされます。
% cargo install lindera-cli
ソースからビルドする場合は次のコマンドでビルドできます。ビルドされたバイナリはリポジトリのディレクトリ以下のbin/lindera
にバイナリがコピーされます。
% cd ${HOME}
% git clone https://github.com/lindera-morphology/lindera-cli.git
% cd lindera-cli
% make build
インストール、またはビルドしたバイナリをパスの通ったところにおいてもらうと、以下の例が実行しやすいです。
では、早速使ってみましょう。lindera
コマンドはデフォルトでIPADICの形態素辞書を内包していますので追加で辞書をインストールする必要はありません。次のようにすぐに実行できます。
% echo "関西国際空港限定トートバッグ" | lindera
関西国際空港 名詞,固有名詞,組織,*,*,*,関西国際空港,カンサイコクサイクウコウ,カンサイコクサイクーコー
限定 名詞,サ変接続,*,*,*,*,限定,ゲンテイ,ゲンテイ
トートバッグ UNK,*,*,*,*,*,*,*,*
EOS
トークナイズモード
Linderaにはnormal
とdecompose
の2つのトークナイズモードを指定することができます。モードの切替は--mode
または-m
で行えます。
normal
モードは、形態素辞書に登録されている単語に沿ってトークナイズします。--mode
または-m
を省略するとnormal
モードでのトークナイズとなります。
% echo "関西国際空港限定トートバッグ" | lindera -m normal
関西国際空港 名詞,固有名詞,組織,*,*,*,関西国際空港,カンサイコクサイクウコウ,カンサイコクサイクーコー
限定 名詞,サ変接続,*,*,*,*,限定,ゲンテイ,ゲンテイ
トートバッグ UNK,*,*,*,*,*,*,*,*
EOS
decompose
モードは、分割可能な複合語を更に細かく分割します。Kuromojiのsearch
モードと同じです(名前を変えました)。
% echo "関西国際空港限定トートバッグ" | lindera -m decompose
関西 名詞,固有名詞,地域,一般,*,*,関西,カンサイ,カンサイ
国際 名詞,一般,*,*,*,*,国際,コクサイ,コクサイ
空港 名詞,一般,*,*,*,*,空港,クウコウ,クーコー
限定 名詞,サ変接続,*,*,*,*,限定,ゲンテイ,ゲンテイ
トートバッグ UNK,*,*,*,*,*,*,*,*
EOS
同じ関西国際空港限定トートバッグ
というテキストをトークナイズしていますが、normal
とdecompose
では関西国際空港
の分割のされ方が違います。decompose
モードは、検索エンジンなどで再現率(recall)の向上を目的とする場合に適したモードです。
用途に合わせてトークナイズモードを使い分けていただければと思います。
出力フォーマット
Linderaはmecab
、wakati
、json
フォーマットで解析結果を出力することができます。出力フォーマットの切り替えは--output
または-o
で行えます。
mecab
は解析結果をMeCabに似たフォーマットで出力します。出力モードを省略したときのデフォルトです。トークンに付随する情報がカンマ(,
)区切りで出力されます。MeCabで馴染みのある出力フォーマットです。
% echo "関西国際空港限定トートバッグ" | lindera -o mecab
関西国際空港 名詞,固有名詞,組織,*,*,*,関西国際空港,カンサイコクサイクウコウ,カンサイコクサイクーコー
限定 名詞,サ変接続,*,*,*,*,限定,ゲンテイ,ゲンテイ
トートバッグ UNK
EOS
wakati
はトークンに付随する情報は省略して、トークンのテキストだけを空白(
)区切りで出力します。分割のされ方だけ確認するならこれで十分ですね。
% echo "関西国際空港限定トートバッグ" | lindera -o wakati
関西国際空港 限定 トートバッグ
json
は解析結果をJSONフォーマットで出力します。MeCabには無い出力モードです。CLIなどで実行結果をJSON出力し、結果を加工して利用することが簡単になります。
Linderaで解析した結果から特定の品詞だけをフィルタするなど、grep
、sed
やawk
だけでなくjq
コマンドとも組み合わせられると便利かなと思い追加しました。
% echo "関西国際空港限定トートバッグ" | lindera -o json
[
{
"text": "関西国際空港",
"detail": [
"名詞",
"固有名詞",
"組織",
"*",
"*",
"*",
"関西国際空港",
"カンサイコクサイクウコウ",
"カンサイコクサイクーコー"
]
},
{
"text": "限定",
"detail": [
"名詞",
"サ変接続",
"*",
"*",
"*",
"*",
"限定",
"ゲンテイ",
"ゲンテイ"
]
},
{
"text": "トートバッグ",
"detail": [
"UNK"
]
}
]
mecab
やjson
フォーマットで出力されるトークンに付随する情報については、使用している辞書のビルダのリポジトリに記載しています。
デフォルトのIPADICを使用した際のフォーマットは、次のページを参照してください。
辞書の切り替え
kuromoji-rsは内包するIPADICしか使用できませんでしたが、Linderaではいくつかの日本語形態素辞書をサポートしています。
Lindera向けの形態素辞書の構築と、使用する方法を紹介します。
UniDic
UniDicについてはこちらを参照してください。
このUniDicをLinderaから利用できるようにするためには、事前に辞書をビルドする必要があります。UniDicをビルドするためのリポジトリはこちらです。
% git clone https://github.com/lindera-morphology/lindera-unidic-builder.git
% cd lindera-unidic-builder
% make lindera-unidic
上記コマンドを実行すると、Lindera向けにビルドされた辞書がlindera-unidic-2.1.2
というディレクトリの下に作成されます。
辞書のあるディレクトリを指定する場合は--dictionary-directory
または-d
フラグを使用します。
% echo "関西国際空港限定トートバッグ" | lindera -d ./lindera-unidic-2.1.2
関西 名詞,固有名詞,地名,一般,*,*,カンサイ,カンサイ,関西,カンサイ,関西,カンサイ,固,*,*,*,*
国際 名詞,普通名詞,一般,*,*,*,コクサイ,国際,国際,コクサイ,国際,コクサイ,漢,*,*,*,*
空港 名詞,普通名詞,一般,*,*,*,クウコウ,空港,空港,クーコー,空港,クーコー,漢,*,*,*,*
限定 名詞,普通名詞,サ変可能,*,*,*,ゲンテイ,限定,限定,ゲンテー,限定,ゲンテー,漢,*,*,*,*
トート 名詞,普通名詞,一般,*,*,*,トート,トート,トート,トート,トート,トート,外,*,*,*,*
バッグ 名詞,普通名詞,一般,*,*,*,バッグ,バッグ-bag,バッグ,バッグ,バッグ,バッグ,外,*,*,*,*
EOS
IPADIC-NEologd
IPADIC-NEologdについてはこちらを参照してください。
こちらもUniDicと同様に事前に辞書のビルドを行います。IPADIC-NEologdをビルドするためのリポジトリはこちらです。
% git clone https://github.com/lindera-morphology/lindera-ipadic-neologd-builder.git
% cd lindera-ipadic-neologd-builder
% make lindera-ipadic-neologd
上記コマンドを実行すると、Lindera向けにビルドされた辞書がlindera-ipadic-2.7.0-20070801-neologd-20200130
というディレクトリの下に作成されます。
% echo "関西国際空港限定トートバッグ" | lindera -d ./lindera-ipadic-2.7.0-20070801-neologd-20200130
関西国際空港 名詞,固有名詞,組織,*,*,*,関西国際空港,カンサイコクサイクウコウ,カンサイコクサイクーコー
限定 名詞,サ変接続,*,*,*,*,限定,ゲンテイ,ゲンテイ
トートバッグ 名詞,固有名詞,一般,*,*,*,トートバッグ,トートバッグ,トートバッグ
EOS
いかがでしょうか。辞書を切り替えると同じテキストでもトークナイズのされ方、付随する品詞情報など違うと思います。
形態素辞書も用途に合わせて切り替えることをお勧めします。
番外編
日本語形態素解析をするためにLinderaの開発をしていますが、実は辞書ソースのフォーマットが同じであれば、少し手を加えるだけでLinderaで利用できるようになります。
日本語以外でも扱うことができます。
ko-dic
ko-dicは、韓国語の形態素辞書です。辞書のソースフォーマットは基本的に他のMeCab向け形態素辞書と同じなのでLinderaから利用できるようにしてみました。
ko-dicについてはこちらを参照してください。
こちらも他の辞書と同様に事前に辞書のビルドを行います。ko-dicをビルドするためのリポジトリはこちらです。
% git clone https://github.com/lindera-morphology/lindera-ko-dic-builder.git
% cd lindera-ko-dic-builder
% make lindera-ko-dic
上記コマンドを実行すると、Lindera向けにビルドされた辞書がlindera-ko-dic-2.1.1-20180720
というディレクトリの下に作成されます。
% echo "간사이국제공항한정토트백" | lindera -d ./lindera-ko-dic-2.1.1-20180720
간사이 NNG,*,F,간사이,Compound,*,*,간/NNG/*+사이/NNG/*
국제공항 NNG,*,T,국제공항,Compound,*,*,국제/NNG/*+공항/NNG/*
한정 NNG,*,T,한정,*,*,*,*
토트백 NNG,*,T,토트백,Compound,*,*,토트/NNP/인명+백/NNG/*
EOS
精度はわかりませんが、なんとなくうまく解析できていそうな感じです。
Luceneにも韓国語形態素解析器Noriがありますが、Linderaと同じこのko-dicを利用しています。
また、Nori自体はKuromojiをフォークして辞書をko-dicに差し替えたもののようなので、おそらく同じような解析結果が得られるだろうと期待しています。
同様に中国語についても辞書のソースさえ用意できれば、形態素解析が行えるようになるかもしれません。
日本語だけでなく韓国語、中国語までサポートしてみたくなりました。
おわりに
前回同様、個人的なプロジェクトの紹介となって大変恐縮です。今回はLinderaの開発引き継ぎ経緯と使い方の簡単な紹介をさせていただきました。
このような、開発を引き継ぐ機会を与えてくれて、リリースのサポートをしてくれたたPaulさん、開発に協力してくれたjohtaniさん、ikawahaさんに改めて感謝いたします。
最後に、もしLinderaに興味を持っていただけたなら、ぜひ使ってみていただけたらと思います。