Elasticsearch 5.6.5
少し古い記事の「検索に悩む」で紹介した「Elasticsearch」ですがWordPressやMediawikiの対応状況により多少古いバージョンである「2.4.6」を使用してきました。Mediawikiが1.29系へバージョンアップするとエクステンション「CirrusSearch」と「Elastica」の最新バージョンが「Elasticsearch 5.x」以降のみの対応となり待った無しでバージョンアップ対応の必要が出てきました。
「Mediawiki 1.29」と「Elasticsearch 5.x」の組み合わせは特に問題なくいつでも移行可能に思えましたが「WordPress」のプラグイン「Fantastic Elasticsearch」は5.x対応していないことが判明し対応もかなり広範囲の変更が必要そうで「Fantastic Elasticsearch」継続を断念。新たにプラグインライブラリから「ElasticPress」をチョイスしてインストールしました。「ElasticPress」自身は「Elasticsearch 5.x」対応しているのですが日本語には全く対応しておらずこのままでは使えません。途中で候補とした「WP Simple Elasticsearch」は「Elasticsearch 5.x」対応が未知で、ググっても「Elasticsearch 5.x kuromoji settings」などでは情報はほぼ皆無な状態。ほとんどの記事が「お弁当」の検索に際して「お」「弁」「当」による検索で我慢しているように思えるし百歩譲っても「お」「弁当」での検索のようだった。以前の記事でも書きましたが「お弁当」で検索したら「お弁当」で拾ってくるのは当然として「弁当」でも拾って欲しい、が「お」では拾って欲しくない。これを「WordPress Elasticsearch 5.x Kuromoji」で解決しているサイトを見つけられなかったので自分で解決するしかない。
まずは「Elasticsearch」のバージョンアップから。「/etc/yum.repos.d」の「elasticsearch.repo」に以下を追加します。「2.x」用のエントリは「enable=0」とします。
[elasticsearch-5.x] name=Elasticsearch repository for 5.x packages baseurl=https://artifacts.elastic.co/packages/5.x/yum gpgcheck=1 gpgkey=https://artifacts.elastic.co/GPG-KEY-elasticsearch enabled=1 autorefresh=0 type=rpm-md
古いバージョン(2.4.6)を削除する前に「analysis-kuromoji」プラグインを削除します。
./plugin remove analysis-kuromoji --> プラグインを削除します yum remove elasticsearch --> Elasticsearch 2.4.6を削除します
新しいバージョン(5.6.5)をインストールします。ちなみに本日時点の最新は「6.1」ですが「Mediawiki」も「WordPress」も対応していません。
yum install elasticsearch --> 5.6.5のインストール ./elasticsearch-plugin install analysis-kuromoji --> 対応したanalysis-kuromojiのインストール
「Elasticsearch 5.x」はこれまで保持していた「下位互換」を全て取り除いたバージョンで古いプラグインはそのままでは全く動きません。「Fantastic Elasticsearch」を諦めたのもコード全体が古いバージョンを前提に書かれていたためです。「ElasticPress」は日本語こそ対応していませんが「Elasticsearch 5.x」との互換性があったので使用しています。スペックの低いサーバーで稼働させるにはJVMメモリ周りの設定を少し修正する必要があります。今回のバージョンからJVMメモリ設定は別ファイルとされています。
# Xms represents the initial size of total heap space # Xmx represents the maximum size of total heap space -Xms128m <-- 2gから削減する -Xmx128m <-- 2gから削減する
ありえない低スペック(1core/512MB)での稼働なのでここまで極端に減らさないと「Elasticsearch」そのものが起動しませんw Elasticsearchが稼働してしまえば「Mediawiki」では1.29用のextensionsに置換えるだけです。「WordPress」の場合はかなりの修正が必要です。その前にそもそも「Elasticsearch」でどのようにしたいのかの確認です。デフォルトでは以下のような解析結果になります。これでは検索結果が汚くなり目的の結果を得られません。
curl localhost:9200/_analyze?pretty "お弁当" { "tokens" : [ { "token" : "お", "start_offset" : 0, "end_offset" : 1, "type" : "<HIRAGANA>", "position" : 0 }, { "token" : "弁", "start_offset" : 1, "end_offset" : 2, "type" : "<IDEOGRAPHIC>", "position" : 1 }, { "token" : "当", "start_offset" : 2, "end_offset" : 3, "type" : "<IDEOGRAPHIC>", "position" : 2 } ] }
トークナイザーを指定して再度実行します。以下のような日本語を意識した解析となります。
curl localhost:9200/_analyze?pretty -d '{"tokenizer":"kuromoji_tokenizer", "text":"お弁当"}' { "tokens" : [ { "token" : "お", "start_offset" : 0, "end_offset" : 1, "type" : "word", "position" : 0 }, { "token" : "弁当", "start_offset" : 1, "end_offset" : 3, "type" : "word", "position" : 1 } ] }
アナライザーを指定するとかなり期待値に近い形まで解析結果をまとめることができます。「検索」フィールドに「お弁当」と入力すると「弁当」で検索してくれる状況がこの状態です。「Elasticsearch 2.4.6」と「Fantastic Elasticsearch」で実現していたことの基本的な内容です。
curl localhost:9200/_analyze?pretty -d '{"analyzer":"kuromoji", "text":"お弁当"}' { "tokens" : [ { "token" : "弁当", "start_offset" : 1, "end_offset" : 3, "type" : "word", "position" : 1 } ] }
この状況を「Elasticsearch 5.x」と「ElasticPress」で再現したいと思います。まずはマッピングから。「tokenizer」を「standard」から「kuromoji_tokenizer」へ変更します。
'analysis' => array( 'analyzer' => array( 'default' => array( // 'tokenizer' => 'standard', 'tokenizer' => 'kuromoji_tokenizer', 'filter' => array( 'ja', 'standard', 'ewp_word_delimiter', 'lowercase', 'stop', 'ewp_snowball' ),
追加「filter」である「ja」は以下の定義を追加します。
'filter' => array( 'ja' => array( 'type' => 'ja_stop', 'stopwords' => ['_japanese_'], ),
日本語検索対象フィールド「post_title」「post_excerpt」「post_content」に「kuromoji」を追加します。
'post_title' => array( 'type' => 'text', 'fields' => array( 'post_title' => array( 'type' => 'text', // 'analyzer' => 'standard', 'analyzer' => 'kuromoji', ), 'post_excerpt' => array( 'type' => 'text', 'analyzer' => 'kuromoji', ), 'post_content' => array( 'type' => 'text', 'analyzer' => 'kuromoji', ),
マッピングの修正は以上です。次は検索を修正します。検索「お弁当」を「お」と「弁当」に解析したら「弁当」で検索するための修正です。「fuzzines」はあいまい検索の設定です。最初は「あいまい検索」出来た方が良い結果を得られると思っていましたが逆に検索結果を汚くしていたのがこの設定でした。どちらの「fuzzines」もコメントアウトします。
array( 'multi_match' => array( 'query' => '', 'fields' => $search_fields, 'boost' => apply_filters( 'ep_match_boost', 2, $search_fields, $args ), // 'fuzziness' => 0, 'operator' => 'and', ) ), array( 'multi_match' => array( 'fields' => $search_fields, 'query' => '', // 'fuzziness' => apply_filters( 'ep_fuzziness_arg', 1, $search_fields, $args ), ), )
これで検索結果が絞り込まれた形で出力されるようになります。「お弁当」で検索すると「弁当」で検索して一致した記事のみ検索結果として表示します。「お」では検索しません。ただし「お弁当を持って」で検索すると「お」「弁当」「を」「持っ」「て」で検索するようです。だいたい当初狙った検索結果が出るようになったので良しとします。一般的なサイトでの対応は以上ですがこのサイトでは「カテゴリー制限をかける」で説明したように公開か非公開をカテゴリーで調整しています。ところが「ElasticPress」が古いプラグインである「Allow Categories」に対応できず「検索結果一覧」に「非公開記事」が含まれてしまいます。「single-post」状態では制限がかかるのですが「美しい検索結果」を求めるこのサイトの主旨には合いません。以下のように対応することにしました。
function include_catagory($query) { if ( !is_user_logged_in() && $query->is_search() ) { $query->set( 'category__in', array("公開カテゴリID") ); } return $query; } add_filter('pre_get_posts', 'include_category');