kurage.cc マストドンの全文検索に形態素解析器 Sudachi を導入 kurage.cc

ぜま✅クラゲ丼鯖缶 2018年10月8日(月)
 こんにちは。
 Mastodon インスタンスに新しい形態素解析器 Sudachi ( 参考記事 Elasticsearchのための新しい形態素解析器 「Sudachi」 ) を導入したので手順をご紹介します。今回も試行錯誤の末にやっと使えるようになった感じなので書き忘れ・勘違いなどあるかもしれません。おかしいところはご指摘いただければ幸いです。(環境:さくらのクラウド CentOS 非Docker)

 【2018/10/10 ユーザー辞書を使う手順を追加、その他一部内容編集しました】
 【2018/10/12 検索結果に想定外のノイズが混ざる現象に対応しました】

1 必要なもの

 Mastodon は標準で全文検索エンジン Elasticsearch をサポートしています (公式ドキュメント)。Elasticsearch の導入までは完了しているものとします。この記事を書いている時点の最新版は 6.4.2 です。kuromoji は使わないので入れる必要はありません。kibana は入れても入れなくても大丈夫です。  Sudachi をビルドするために Maven が必要です。 Maven が入ってなければインストールします。この記事を書いている時点の最新版は 3.5.4 です。( なお Maven を動かすために Java が必要ですが Elasticsearch 導入の時点で入っているはずなので Java を入れる手順は省略 )
# cd /opt # wget http://ftp.riken.jp/net/apache/maven/maven-3/3.5.4/binaries/apache-maven-3.5.4-bin.tar.gz # tar xzvf apache-maven-3.5.4-bin.tar.gz
 mastodon ユーザーから Maven を使えるように PATH を通します。下記は一例です。
$ vi /home/mastodon/.bash_profile 最下行に追記する PATH=$PATH:/opt/apache-maven/bin 再ログインまたは $ source ~/.bash_profile で反映される

2 Sudachi と Elasticsearch のバージョンを合わせてビルドする

 Sudachi に限りませんが Elasticsearch のプラグインは Elasticsearch とまったく同じバージョン番号のものしかインストールできません。この記事を書いている時点の Sudachi の最新版は 6.4.0 です。Elasticsearch の最新版は 6.4.2 です。だいたい合ってますが「だいたい」ではダメで、やはりインストールできません。このエラーを回避するには Elasticsearch を下げるか、Sudachi を上げてみるかのどちらかになります。 ★ Elasticsearch をダウングレードする場合 ( kibana とか使っている場合はそれもダウングレード必要) (Elasticsearch を下げるのではなく上げる場合は yum update で)
# yum downgrade elasticsearch-6.4.0-1 # systemctl daemon-reload # su - mastodon ログイン $ cd live $ git clone -b release/6.4 git@github.com:WorksApplications/elasticsearch-sudachi.git $ cd elasticsearch-sudachi $ mvn package ビルド完了
★ Sudachi を改変する場合 ( 手作業でバージョン番号を書き換えてしまう荒技なので自己責任で。今回はうまくいきましたが Elasticsearch 側に大きめのアップデートがあった場合はダメでしょう ) ( 参考記事 SudachiをElasticsearch6.1.1で使用する手順(非公式) )
# su - mastodon ログイン $ cd live $ git clone -b release/6.4 git@github.com:WorksApplications/elasticsearch-sudachi.git $ cd elasticsearch-sudachi $ vi pom.xml 15行目のみ書き換え(6.4.06.4.2) $ mvn package ビルド完了

3 ビルドした Sudachi のインストール

 旧バージョンの Sudachi がすでに入っているような場合は消しておく # /usr/share/elasticsearch/bin/elasticsearch-plugin remove analysis-sudachi  インストール # /usr/share/elasticsearch/bin/elasticsearch-plugin install file:///home/mastodon/live/elasticsearch-sudachi/target/releases/analysis-sudachi-elasticsearch6.4-1.1.0.zip  確認 # /usr/share/elasticsearch/bin/elasticsearch-plugin list  「analysis-sudachi」が表示されれば OK

4 システム辞書をインストール

 システム辞書はリポジトリから最新のものをダウンロード・解凍するだけで簡単なんですが、置き場所に注意です。上記参考記事には $ES_HOME/sudachi/ 以下に置くように書いてありますが、私の場合はそこだと (具体的には /usr/share/elasticsearch以下) 辞書が読み込まれず、正常動作していませんでした。これに気づくのが遅れ、えらくハマりました。elasticsearch.yml と同じディレクトリ (/etc/elasticsearch とか) に移したらうまくいきました。( 参考記事 elasticsearch-sudachi で sudachi.json や system_full.dic が読み込まれない場合の対処法 )
# cd /etc/elasticsearch ← 辞書を置くディレクトリ # wget https://oss.sonatype.org/content/repositories/snapshots/com/worksap/nlp/sudachi/0.1.1-SNAPSHOT/sudachi-0.1.1-20181002.083840-42-dictionary-core.tar.bz2 # tar xvf sudachi-0.1.1-20181002.083840-42-dictionary-core.tar.bz2

5 設定ファイル(その1) statuses_index.rb を編集

 Mastodon の場合、デフォルトの辞書「system_core.dic」を使う場合は設定ファイル sudachi.json は不要で statuses_index.rb だけ編集すれば動きます。「resources_path:」のところに辞書を置いたディレクトリを書きます。「settings_path:」の行は不要です。  system_core.dic 以外の辞書 (system_full.dic やユーザー辞書) を使う場合は sudachi.json が必要になります(後述)。その場合は「settings_path:」のところに sudachi.json のパスを書きます。  フィルターはお好みで良いと思いますが、私の場合「sudachi_readingform」を使ったら検索結果がおかしくなったので下記では外してあります。 ← 下記の【10/12追記】の編集を行えば各フィルター問題ないと思います
$ vi /home/mastodon/live/app/chewy/statuses_index.rb 3~26行目あたり class StatusesIndex < Chewy::Index settings index: { refresh_interval: '15m' }, analysis: { tokenizer: { sudachi_tokenizer: { type: 'sudachi_tokenizer', mode: 'search', discard_punctuation: true, resources_path: '/etc/elasticsearch', ← 辞書を置いたディレクトリ settings_path: '/etc/elasticsearch/sudachi.json', ← sudachi.json を使う場合のみ }, }, analyzer: { content: { filter: %w( lowercase cjk_width sudachi_part_of_speech sudachi_ja_stop sudachi_baseform ), tokenizer: 'sudachi_tokenizer', type: 'custom', }, }, }

6【10/12追記】設定ファイル(その2) search_service.rb を編集

 ここまでの作業を行っても検索結果に Sudachi の解析と合わないものが多数ヒットする怪現象が多発して悩んでいましたが、マストドン本家のコードに仕掛けがしてあったのが原因だとわかったため、この仕掛けが効かないようにします。これは(おそらく欧米語の検索精度を上げるために)別の解析を併用するようなことらしいのですが、日本語のように単語と単語の間にスペースがない言語には対応できず単語がバラバラに分解されてしまうためです。具体的には「text」フィールドを検索クエリから除外して対処しました。  ついでに、検索結果が日付順 (新しい順) にソートされると便利なのでその1行を付け加えています。この部分は Bal Ballard さんから教えていただきました
$ vi /home/mastodon/live/app/services/search_service.rb 31行目あたり .query(multi_match: { type: 'most_fields', query: query, operator: 'and', fields: %w(text text.stemmed) }) .query(match: { 'text.stemmed': { query: query, operator: 'and'}}) .order(created_at: { order: 'desc' })
system_core.dic 以外の辞書を使わない場合はこれで終わりです。assets:precompile して mastodon 再起動、chewy:deploy して elasticsearch 再起動。これで sudachi が使えるようになったと思います。

7 設定ファイル(その3) sudachi.json を用意する

 system_core.dic 以外の辞書 (system_full.dic やユーザー辞書) を使う場合は設定ファイル sudachi.json というものが必要です。ファイルはここにあるので、これをそのままコピペして先頭だけ書き直す感じで良さそうです。パスはさきほど statuses_index.rb の「settings_path:」に書いたものと合わせます。
$ vi /etc/elasticsearch/sudachi.json { "systemDict" : "/etc/elasticsearch/system_full.dic", ← システム辞書。フルパスで書かないと chewy から読めないっぽい。 "userDict" : [ "/etc/elasticsearch/sudachi_user.dic" ], ← ユーザー辞書を使う場合はここに。複数ファイル可。1つしかなくても必ず [ ] に入れるリスト形式で。 "inputTextPlugin" : [ { "class" : "com.worksap.nlp.sudachi.DefaultInputTextPlugin" }, { "class" : "com.worksap.nlp.sudachi.ProlongedSoundMarkInputTextPlugin", "prolongedSoundMarks": ["ー", "-", "?", "?", "?"], "replacementSymbol": "ー"} ], "oovProviderPlugin" : [ { "class" : "com.worksap.nlp.sudachi.MeCabOovProviderPlugin" }, { "class" : "com.worksap.nlp.sudachi.SimpleOovProviderPlugin", "oovPOS" : [ "補助記号", "一般", "*", "*", "*", "*" ], "leftId" : 5968, "rightId" : 5968, "cost" : 3857 } ], "pathRewritePlugin" : [ { "class" : "com.worksap.nlp.sudachi.JoinNumericPlugin", "joinKanjiNumeric" : true }, { "class" : "com.worksap.nlp.sudachi.JoinKatakanaOovPlugin", "oovPOS" : [ "名詞", "普通名詞", "一般", "*", "*", "*" ], "minLength" : 3 } ] }

8 ユーザー辞書を作る

 ユーザー辞書を作るには、まず登録したい単語をリストアップします。フォーマット(csv)については公式ドキュメントを参照して下さい。まあだいたい固有名詞がほとんどだろうと思いますのでこんな感じで見出しだけ書き直したようなものをどんどん並べます。
$ vi /etc/elasticsearch/sudachi_user.csv クラゲ丼,4786,4786,5000,クラゲ丼,名詞,固有名詞,一般,*,*,*,クラゲドン,クラゲ丼,*,*,*,*,* ぜま,4786,4786,5000,ぜま,名詞,固有名詞,一般,*,*,*,ゼマ,ぜま,*,*,*,*,* かもすい,4786,4786,5000,かもすい,名詞,固有名詞,一般,*,*,*,カモスイ,かもすい,*,*,*,*,* えのすい,4786,4786,5000,えのすい,名詞,固有名詞,一般,*,*,*,エノスイ,えのすい,*,*,*,*,* 海きらら,4786,4786,5000,海きらら,名詞,固有名詞,一般,*,*,*,ウミキララ,海きらら,*,*,*,*,* 美ら海,4786,4786,5000,美ら海,名詞,固有名詞,一般,*,*,*,チュラウミ,美ら海,*,*,*,*,*
これを保存したらバイナリに変換します。「system_core.dic」のところはシステム辞書名、「sudachi_user.csv」のところは入力する単語リストのファイル名、「sudachi_user.dic」のところは出力するバイナリ辞書のファイル名です。
# cd /etc/elasticsearch # java -Dfile.encoding=UTF-8 -cp /usr/share/elasticsearch/plugins/analysis-sudachi/sudachi-0.1.1-20181002.083840-42.jar com.worksap.nlp.sudachi.dictionary.UserDictionaryBuilder system_core.dic sudachi_user.csv sudachi_user.dic
これでユーザー辞書ができました。assets:precompile して mastodon 再起動、chewy:deploy して elasticsearch 再起動です。お疲れさまでした。  なお、辞書の変更をした程度 (インデックスの設定ファイルに変更がない) 場合に再度 chewy:deploy をしても resetting をスキップしてしまいインデックス再構成を行ってくれません。その場合は chewy:reset で強制的にインデックスを作り直して下さい。ちなみにクラゲ丼の現在の環境で約770万トゥートのインデックス作り直しに3~4時間かかっています。

9 エラー対策:なんかごちゃごちゃしたのでインデックス一度全部消すとき (⚠️危険)

 chewy:deploy が落ちたりして「All shards failed」とか怒られたときとか。
# curl -XDELETE 'http://localhost:9200/*' → 再度 chewy:deploy

10 コンソールで Sudachi の解析結果を見る方法

 Elasticsearch を通す方法。chewy:deploy 後の動作確認などに。
# curl localhost:9200/_cat/indices?v インデックス一覧を表示 「statuses_xxxxxxxxxxxxx」(xxx…は数字) のインデックスがあることを確認 # curl -XGET 'localhost:9200/statuses_xxxxxxxxxxxxx/_analyze?pretty' -H 'Content-Type: application/json' -d '{"analyzer" : "content" , "text" : "すもももももももものうち"}'
 Elasticsearch の検索結果を見たい場合。
# curl -XGET 'localhost:9200/statuses_xxxxxxxxxxxxx/_search?pretty' -H 'Content-Type: application/json' -d '{"query" : {"bool" : {"must" : [{"match" : {"text.stemmed" : {"query" : "キーワード", "operator" : "and"}}}, {"term" : {"searchable_by" : アカウントid }}]}}, "sort" : {"created_at" : {"order" : "desc" }}}'
 Sudachi のコマンドラインツールを使う方法もあります。こちらは sudachi.json が必要ですが Elasticsearch を通さないので chewy:deploy 前に解析結果を見ることができます。
# echo えのすいもかもすいもくらげすげーわ | java -jar /usr/share/elasticsearch/plugins/analysis-sudachi/sudachi-0.1.1-20181002.083840-42.jar -r /etc/elasticsearch/sudachi.json えのすい 名詞,固有名詞,一般,*,*,* えのすい も 助詞,係助詞,*,*,*,* も かもすい 名詞,固有名詞,一般,*,*,* かもすい も 助詞,係助詞,*,*,*,* も くらげ 名詞,普通名詞,一般,*,*,* 海月 すげー 形容詞,一般,*,*,形容詞,終止形-一般 凄い わ 助詞,終助詞,*,*,*,* わ

過去の記事:マストドンに日本語対応の全文検索を導入 クラゲ丼 (kurage.cc)