2026年8月18日
2026年8月18日
WordPressの検索をElasticsearchにする方法(ElasticPress・日本語のkuromoji設定)
WordPress の標準のサイト内検索は、データベース(MySQL・MariaDB)で投稿のタイトル・抜粋・本文に検索語が含まれるかを LIKE で調べる仕組みです。投稿が多いと遅くなりやすく、並び順も「関連の強さ」ではありません。プラグイン ElasticPress を使うと、検索を全文検索エンジンの Elasticsearch に任せられます。
この記事の手順は、2026年11月時点の WordPress 7.1、ElasticPress 5.3.5、Elasticsearch 9.5.5(Docker)で動作を確かめています。
構成と必要なもの
- Elasticsearch のサーバー: 自分で用意する(VPS や Docker)か、ElasticPress の開発元が提供するホスティングサービス ElasticPress.io を使います。共用のレンタルサーバーでは Elasticsearch を動かせないことがほとんどです。
- ElasticPress プラグイン: WordPress の検索クエリ(
WP_Query)を Elasticsearch への問い合わせに置き換えます。公式の要件は WordPress 6.2 以上、PHP 7.4 以上、Elasticsearch 5.2 以上です。
ElasticPress を入れると、投稿の内容が Elasticsearch のインデックスにコピーされ、検索のときはそちらが使われます。投稿を保存・削除したときは、ElasticPress が自動でインデックスを更新します。
Elasticsearchを起動する(Docker・日本語プラグイン入り)
日本語の文章を単語に分けるには、Elasticsearch の公式プラグイン analysis-kuromoji(形態素解析)が必要です。コンテナを作り直しても消えないよう、プラグインを入れたイメージを作ります。作業用のディレクトリに次の2つのファイルを置きます。
Dockerfile:
FROM elasticsearch:9.5.5
RUN bin/elasticsearch-plugin install --batch analysis-kuromoji
compose.yaml:
services:
elasticsearch:
build: .
environment:
- discovery.type=single-node
- xpack.security.enabled=false
- ES_JAVA_OPTS=-Xms512m -Xmx512m
ports:
- "127.0.0.1:9200:9200"
volumes:
- es-data:/usr/share/elasticsearch/data
volumes:
es-data:
docker compose up -d --build
# 起動の確認("status" が green か yellow なら動いている)
curl -s "http://127.0.0.1:9200/_cluster/health?pretty"
# kuromoji が入っているかの確認
curl -s "http://127.0.0.1:9200/_cat/plugins"
この設定は、同じサーバーの WordPress から使う開発・検証用です。
xpack.security.enabled=falseで認証と暗号化を切っているため、portsは127.0.0.1に限定し、外部から接続できないようにしています。インターネットに公開する構成では使わないでください。- 本番では、Elasticsearch の公式文書に沿って認証と HTTPS を有効にし、メモリ(
ES_JAVA_OPTSのヒープの大きさ)やカーネルの設定(vm.max_map_count)を見直します。
Elasticsearch のインストール全般は Elasticsearchのインストール方法 を参照してください。
ElasticPressを入れて同期する
1. プラグインを入れる
「プラグイン」→「プラグインを追加」で「ElasticPress」を検索し、インストールして有効化します。
2. 接続先を設定する
接続先を wp-config.php に書きます(管理画面の ElasticPress の設定画面で入力することもできます)。
<?php
// wp-config.php(「That's all, stop editing!」の行より前)
define( 'EP_HOST', 'http://127.0.0.1:9200/' );
// Elasticsearch の認証を有効にしている場合は、ユーザー名とパスワードを指定する
// define( 'ES_SHIELD', 'ユーザー名:パスワード' );
3. 投稿を同期する
投稿を Elasticsearch に送ります(同期)。管理画面の「ElasticPress」→「Sync」からも実行できますが、投稿が多いサイトでは WP-CLI が確実です。
wp elasticpress status # 接続の確認
wp elasticpress sync --setup --yes # インデックスを作り直して全件を送る
wp elasticpress list-features # 有効な機能(search が含まれていること)
試した環境では Number of posts indexed: 30 と表示され、公開中の投稿と固定ページが送られました。ElasticPress の「検索」機能(search)は有効化した時点で有効になり、フロントのサイト内検索(?s=)が Elasticsearch で処理されます。
--setup はインデックスを削除して作り直す指定です。後で説明する日本語の設定のように、インデックスの設定(マッピング)を変えたときは、--setup 付きで同期し直します。同期の直後は反映に少し時間がかかり、試したところ同期と同じ処理の中ですぐ検索すると結果が0件でした。
日本語を単語に分ける(kuromoji)
ElasticPress は、サイトの言語に合わせて Elasticsearch の言語設定を選びますが、2026年11月時点の ElasticPress 5.3.5 には日本語の対応表がなく、日本語のサイトでも英語用の設定(標準のトークナイザー)が使われます。標準のトークナイザーは漢字を1文字ずつに分けるため、たとえば「京都」で検索すると「東京都」を含む投稿も見つかります。
次のファイルを wp-content/mu-plugins/ep-japanese.php として置くと、投稿のインデックスで kuromoji を使うようになります。
<?php
/**
* Plugin Name: ElasticPress Japanese analyzer
* Description: ElasticPress の投稿インデックスで kuromoji(日本語の形態素解析)を使う。
*/
// 投稿インデックスの既定のアナライザーを kuromoji に置き換える
add_filter( 'ep_post_mapping', function ( $mapping ) {
$analyzer = array(
'type' => 'custom',
'char_filter' => array( 'html_strip' ),
'tokenizer' => 'kuromoji_tokenizer',
'filter' => array(
'kuromoji_baseform',
'kuromoji_part_of_speech',
'cjk_width',
'ja_stop',
'kuromoji_stemmer',
'lowercase',
),
);
$mapping['settings']['analysis']['analyzer']['default'] = $analyzer;
$mapping['settings']['analysis']['analyzer']['default_search'] = $analyzer;
return $mapping;
} );
置いた後に wp elasticpress sync --setup --yes で同期し直します。設定が入ったかは、インデックス名を調べてから、その設定を表示して確かめます(default のアナライザーに kuromoji_tokenizer が出ていれば反映されています)。
wp elasticpress get-indices
# 表示されたインデックス名(例: example-com-post-1)を指定する
wp elasticpress get-index-settings example-com-post-1 --pretty
試した結果は次のとおりです(5件の日本語の投稿で比較)。
| 検索語 | 標準のトークナイザー | kuromoji |
|---|---|---|
| 京都 | 「京都の観光情報」と「東京都」を含む投稿の2件 | 「京都の観光情報」の1件 |
| 速い | 「高速化」を含む投稿の1件 | 「速くなります」を含む投稿も見つかり2件 |
kuromoji は「速く」を基本形の「速い」として扱うため、活用した形でも見つかります。一方で、単語の途中の文字列(例:「東京都」の中の「京都」)では見つからなくなります。どちらが合うかはサイトの内容によるので、実際の投稿で試して決めてください。
特定の投稿を検索から外す
ElasticPress は、初期設定では公開中(publish)の投稿だけを送ります。下書きや非公開の投稿を除くための設定は不要です。それ以外に、たとえばカスタムフィールドで指定した投稿を外したい場合は、全件の同期と、投稿の保存時の同期の両方で除外します。
<?php
// 全件の同期(wp elasticpress sync)で、_myprefix_exclude_search が 1 の投稿を除く
add_filter( 'ep_post_query_db_args', function ( $args ) {
$args['meta_query'] = array(
'relation' => 'OR',
array(
'key' => '_myprefix_exclude_search',
'compare' => 'NOT EXISTS',
),
array(
'key' => '_myprefix_exclude_search',
'value' => '1',
'compare' => '!=',
),
);
return $args;
} );
// 投稿の保存時の同期でも、同じ投稿を送らない
add_filter( 'ep_post_sync_kill', function ( $skip, $post_id ) {
if ( '1' === get_post_meta( $post_id, '_myprefix_exclude_search', true ) ) {
return true;
}
return $skip;
}, 10, 2 );
試したところ、このフィールドを付けた投稿は同期の対象から外れ、本文に検索語を含んでいても検索結果に出ませんでした。なお ep_post_sync_kill は「送らない」だけなので、すでにインデックスに入っている投稿にあとからフィールドを付けた場合は、wp elasticpress sync --setup --yes で同期し直します。
絞り込みと重み付けは管理画面で設定する
ElasticPress には、検索結果の絞り込みや並び順の調整が機能として入っています。独自のクエリを書く前に、まずこれらを使います。
- 絞り込み(Filters 機能): 初期状態で有効で、「Filter by Taxonomy」「Filter by Post Type」「Filter by Metadata」「Filter by Post Date」などのブロックが使えます。検索結果やアーカイブのテンプレートに置くと、カテゴリーやタグなどで結果を絞り込めます。
- 重み付け: 「ElasticPress」→「Search Fields & Weighting」で、タイトル・本文・抜粋・タクソノミーなどのどれを検索対象にし、どれを重く見るかを設定できます。「Add field」でカスタムフィールド(Metadata key)を検索対象に加えることもできます。
うまく動かないとき
wp elasticpress statusがエラーになる:EP_HOSTの URL(http/https、ポート、末尾の/)と、WordPress のサーバーから Elasticsearch に接続できるか(curlで/_cluster/healthが返るか)を確かめます。- 検索結果が変わらない:
wp elasticpress list-featuresにsearchがあるか、同期が終わっているかを確かめます。 - 日本語の設定が効かない:
ep-japanese.phpを置いた後に--setup付きで同期し直したか、Elasticsearch に analysis-kuromoji が入っているか(/_cat/plugins)を確かめます。