【実務・中級編】wp_postsのpost_contentカラムに格納されるHTMLデータの検索負荷を軽減する手法 – WordPress 内部コア・データベース構造とパフォーマンス最適化解析バイブル

wp_postsの呪縛を解け:全文検索のボトルネックを解消する「外部オフロード」のアーキテクチャ

WordPressの `wp_posts.post_content` は、いわば「ゴミ溜め」に近い。リッチテキスト、ショートコード、埋め込みタグが混沌と混ざり合うこのカラムに対し、`LIKE ‘%keyword%’` を用いたSQLクエリを発行するのは、現代のWebアプリケーションにおいて「死」を意味する。

テーブルスキャン(全件走査)が発生し、データベースのI/Oを枯渇させ、結果としてサイト全体がスローダウンする。我々エンジニアがやるべきことは、「WPのコアを破壊せずに、検索責任を剥離すること」だ。

今回は、この呪縛から逃れるための「オフロード設計」と、実務で耐えうる堅牢な実装パターンを伝授する。

—

1. なぜ「SQL LIKE検索」は敗北するのか

WordPressのデータ構造上、`wp_posts` は万能だが、検索には向いていない。

  • インデックスの不在: `post_content` は `LONGTEXT` 型であり、B-Treeインデックスが効かない。
  • 非正規化の弊害: 全文検索のためにフルスキャンが走ると、`wp_options` や `wp_postmeta` のキャッシュヒット率まで悪影響を受ける。

我々が目指すべきは、「検索エンジンへのデータストリーミング(非同期)」と「読み取り専用インデックスの分離」である。

—

2. アーキテクチャ戦略:同期と非同期の分離

運用負荷とパフォーマンスのバランスを取るため、以下の構成を推奨する。

1. データストア: ElasticSearch (または Algolia / Meilisearch) を採用する。
2. データ抽出: `save_post` フックをトリガーに、非同期(Action Scheduler)でインデックスを更新する。
3. 検索実行: WP_Query を経由せず、REST API または直接インデックスエンジンへクエリを投げる。

—

3. 実践コード:Action Schedulerを用いた堅牢なオフロード

`save_post` で直接APIを叩いてはいけない。リクエストがタイムアウトした場合、投稿保存自体が失敗する可能性があるからだ。`Action Scheduler` を使い、バックグラウンド処理としてキューイングする。

/

  • 投稿保存時に検索用インデックスへデータを同期する設計

/
add_action(‘save_post’, function ($post_id, $post, $update) {
// リビジョンや自動保存をフィルタリング(必須)
if (wp_is_post_revision($post_id) || wp_is_post_autosave($post_id)) {
return;
}

// 非同期キューへタスクを登録(Action Scheduler)
// これにより、保存処理のレスポンスをブロックしない
as_enqueue_async_action(‘sync_post_to_external_search’, [$post_id]);
}, 10, 3);

/

  • 非同期ワーカー:外部検索エンジンへのデータ送信

/
add_action(‘sync_post_to_external_search’, function ($post_id) {
$post = get_post($post_id);

// post_contentの不要なショートコードやHTMLタグを除去して正規化
$clean_content = wp_strip_all_tags(do_shortcode($post->post_content));

$data = [
‘id’ => $post_id,
‘title’ => $post->post_title,
‘content’ => $clean_content,
‘url’ => get_permalink($post_id),
];

// ここで外部API(ElasticSearch等)へPOSTリクエストを送信
$response = wp_remote_post(‘https://search-engine.internal/index’, [
‘body’ => json_encode($data),
‘headers’ => [‘Content-Type’ => ‘application/json’],
‘timeout’ => 5, // APIの遅延に引きずられないようタイムアウトを厳格に設定
]);
});

—

4. プロダクション環境での重要注意点

A. データ整合性の担保(Reconciliation)

非同期処理は「失敗」する可能性がある。外部インデックスとDBのデータが乖離し始めた際、数万件のデータを再同期させるための CLIコマンド(`wp-cli`)を必ず実装しておくこと。

// WP-CLIで全データ再同期
if (defined(‘WP_CLI’) && WP_CLI) {
WP_CLI::add_command(‘search-sync’, function() {
$posts = get_posts([‘posts_per_page’ => -1]);
foreach ($posts as $post) {
as_enqueue_async_action(‘sync_post_to_external_search’, [$post->ID]);
}
WP_CLI::success(‘Sync queued.’);
});
}

B. コンテンツの正規化(Normalizer)

`wp_strip_all_tags` だけでは、埋め込みコードやCSS/JSの断片が残る。検索精度を上げるには、`strip_shortcodes()` を適用した上で、さらに `preg_replace` で不要な記号を排除する独自の Normalizer 関数を噛ませるべきだ。検索エンジンに「ゴミ」を食わせると、ノイズだらけの検索結果しか得られない。

—

5. 結論

WordPressを「データベース」として使い続けることは、ある一定の規模を超えると限界が来る。`wp_posts` の中のデータは、「表示用」と割り切り、検索という「検索用」の責務は専用エンジンに委譲する。

この設計思想を適用するだけで、データベースの負荷は劇的に下がり、検索速度はミリ秒単位まで短縮される。これこそが、コアコントリビューターが現場で用いる「WordPressを支配する技術」だ。

次にコードを書くとき、`LIKE` を使おうとする己の指を止めてほしい。そのクエリは、本当に必要か? インデックスを分離する準備はできているか? それこそが、一流のエンジニアへの分水嶺である。

タイトルとURLをコピーしました