アクトインディ開発者ブログ

子供とお出かけ情報「いこーよ」を運営する、アクトインディ株式会社の開発者ブログです

形態素解析エンジンを弄ってみる

こんにちは!!こんにちは!! moriyamaです

この記事は actindi Advent Calendar 2019 の21日目の記事です。

adventar.org

唐突ですが、以前書いた記事で、「いこーよ」という単語は固有名詞として扱われず、
いく」 「」 「(空白文字)」の3単語に分解されていると確認できました。

tech.actindi.net

「いこーよ」は多くの方に認知されているので、辞書を使わずに形態素解析でも1単語にならないかと思い、
そこで今回は、NEologdを使った検索エンジン(Solr)の検証をしてみました。


そもそもNEologdとは?

冒頭でいきなり略語で書きましたが、正式には mecab-ipadic-NEologdと言います。

github.com

NEologdは、多数のWeb上の言語資源から得た新語を追加することでカスタマイズした MeCab 用のシステム辞書です。

作者様の記事によると、

  • 週2回以上更新
  • 新語・固有表現に強い
  • 語彙数が多い
  • オープンソース・ソフトウェア

といった特徴を挙げています。


さっそく使ってみる

何はともあれNEologdの辞書を生成しなきゃ話は始まらないですね。

公式サイトを参考に、3stepです!(簡単!)

# リポジトリをclone
$ git clone --depth 1 https://github.com/neologd/mecab-ipadic-neologd.git

# ディレクトリ移動
$ cd mecab-ipadic-neologd

# インストールと単語リストの更新
# ※ 後続作業のため、"--max_baseform_length 15" のオプションを付与
$ ./bin/install-mecab-ipadic-neologd -n --max_baseform_length 15

完了したら動作確認してみましょう。

mecab -d /usr/local/lib/mecab/dic/mecab-ipadic-neologd/ で実行できるので、 echo して解析してみましょう。

$ echo "いこーよってサイトで見つけたよ!" | mecab -d /usr/local/lib/mecab/dic/mecab-ipadic-neologd/
いこーよ    名詞,固有名詞,一般,*,*,*,いこーよ,イコーヨ,イコーヨ
って  助詞,格助詞,連語,*,*,*,って,ッテ,ッテ
サイト   名詞,一般,*,*,*,*,サイト,サイト,サイト
で 助詞,格助詞,一般,*,*,*,で,デ,デ
見つけ   動詞,自立,*,*,一段,連用形,見つける,ミツケ,ミツケ
た 助動詞,*,*,*,特殊・タ,基本形,た,タ,タ
よ 助詞,終助詞,*,*,*,*,よ,ヨ,ヨ
! 記号,一般,*,*,*,*,!,!,!
EOS

無事に、「いこーよ」と固有名詞の1単語に形態素解析されましたね!

ちなみに、通常の mecab で実行すると今まで通りの結果です。

~ $ echo "いこーよってサイトで見つけたよ!" | mecab
いこ  動詞,自立,*,*,五段・カ行促音便,未然ウ接続,いく,イコ,イコ
ー 名詞,一般,*,*,*,*,*
よ 助詞,終助詞,*,*,*,*,よ,ヨ,ヨ
って  助詞,格助詞,連語,*,*,*,って,ッテ,ッテ
サイト   名詞,一般,*,*,*,*,サイト,サイト,サイト
...

jarファイルを生成する

NEologdの辞書を生成しただけなので、検索エンジンに反映しなければ当然、検索精度は向上しませんね。

そこで、Solrの形態素解析器である、kuromojiのjarファイルを生成してみようと思います。

SolrはAntでコンパイルするので、初期設定(ant ivy-bootstrapの実行)が必要なので注意してください。

# リポジトリをclone
$ git clone git@github.com:apache/lucene-solr.git

# 辞書を反映するため、NEologdの中間生成物を取り込む
# ※ yyyymmddは生成日で変わるので適宜変更してください。
$ cp -Rp [mecab-ipadic-neologd]/build/mecab-ipadic-2.7.0-20070801-neologd-yyyymmdd lucene-solr/lucene/build/analysis/kuromoji/

# ディレクトリ移動
$ cd lucene-solr/lucene/analysis/kuromoji

NEologdの辞書を反映したいので、build.xml を少し弄って中間生成物を読み込むよう修正します。

<!-- NEologdの中間生成物を読み込むように指定
<property name="ipadic.version" value="mecab-ipadic-2.7.0-20070801" />
-->
<property name="ipadic.version" value="mecab-ipadic-2.7.0-20070801-neologd-yyyymmdd" />

<!-- 文字コードをUTF-8指定に変更
<property name="dict.encoding" value="euc-jp"/>
-->
<property name="dict.encoding" value="utf-8"/>

<!-- "download-dict" targetの実行は不要なので変更
<target name="build-dict" depends="compile-tools, download-dict">
-->
<target name="build-dict" depends="compile-tools">

<!-- 単語数が多いためか、自分の環境だとOut Of Memoryが頻発したので変更
<java fork="true" failonerror="true" maxmemory="1g" classname="org.apache.lucene.analysis.ja.util.DictionaryBuilder">
-->
<java fork="true" failonerror="true" maxmemory="4g" classname="org.apache.lucene.analysis.ja.util.DictionaryBuilder">

ここまで終わればほぼ完了で、あとはビルドするのみです!

# lucene-solr/lucene/analysis/kuromoji 配下で辞書をビルド
$ ant build-dict

# jarファイルの生成
$ ant jar-core

上記コマンドが成功し、
lucene-solr/lucene/build/analysis/kuromoji/ 配下に lucene-analyzers-kuromoji-x.x.x-SNAPSHOT.jar 生成されていれば完了です!

※ ちなみにmecab-ipadic-neologdのインストール時に「--max_baseform_length 15」オプションを付与したものでないと、辞書のビルドに失敗します

...

build-dict:
     [java] dictionary builder
     [java]
     ...
     [java] input encoding: utf-8
     [java] normalize entries: false
     [java]
     [java] building tokeninfo dict...
     [java]   parse...
     [java]   sort...
     [java]   encode...
     [java] Exception in thread "main" java.lang.AssertionError
     [java]     at org.apache.lucene.analysis.ja.util.BinaryDictionaryWriter.put(BinaryDictionaryWriter.java:129)
     [java]     at org.apache.lucene.analysis.ja.util.TokenInfoDictionaryBuilder.buildDictionary(TokenInfoDictionaryBuilder.java:143)
     [java]     at org.apache.lucene.analysis.ja.util.TokenInfoDictionaryBuilder.build(TokenInfoDictionaryBuilder.java:78)
     [java]     at org.apache.lucene.analysis.ja.util.DictionaryBuilder.build(DictionaryBuilder.java:37)
     [java]     at org.apache.lucene.analysis.ja.util.DictionaryBuilder.main(DictionaryBuilder.java:82)

理由としては、kuromojiの仕様が関係しているとのことです。@kazuhira_rさんの記事がとても参考になりました。


Solrへ反映してみる

生成したjarファイルの配置先は、[Solr Home]/server/solr-webapp/webapp/WEB-INF/lib になります。

念の為、既存の lucene-analyzers-kuromoji-x.x.x.jar は削除orリネームしておくと安全ですね。

さてさて、Solrに反映して確認してみると

反映前 反映後
f:id:setsuna82001:20191220165656p:plain:w300 f:id:setsuna82001:20191220165702p:plain:w300

パーフェクトですね!


まとめ

これだけでは大雑把で荒削りな結果なので、詳細な検証が必要ですが、
辞書をビルドして検索エンジンへ反映する一連の作業がわかりました。

検索精度の向上が見られれば、「いこーよ」に組み込んで、良質な検索結果が提供できたら幸いです。

さいごに、アクトインディでは一緒に働きたいエンジニアを募集しています!
是非ご応募ください!

actindi.net