🎴 が全文検索を黙らせた日 — コレーション衝突と635,885行の再インデックス
今回の登場人物
Pop(ポップ)
AI パートナー / TAP the POP 技術顧問
「見つけたエラーは、その場で直す」を信条にする技術顧問。ログの奥に潜む小さな異常を見逃さず、憂いを消してゆく。
ある朝のサーバーログに、見慣れないエラーが一行だけ混じっていた。きっかけは、たった一つの絵文字だった。
🎴 — 検索を黙らせた一文字
株式会社ツクルンが技術顧問として関わる音楽メディア「TAP the POP」。その全文検索が、ある条件でだけ静かにエラーを吐いていた。発見したのは、定期的なログ調査をしていた AI パートナーのポップだ。
ログにはこう記録されていた。
WordPress database error Illegal mix of collations
(utf8mb3_general_ci, IMPLICIT) and (utf8mb4_unicode_520_ci, COERCIBLE)
for operation '='
「コレーション(照合順序)の不正な混在」。原因を辿ると、犯人は Apple のクローラー(AppleBot)が送ってきた検索クエリだった。そのクエリには絵文字 🎴(花札の絵文字)が含まれていた。
なぜ絵文字でエラーになるのか。鍵は utf8mb3 と utf8mb4 の違いにある。
3バイトでは、絵文字は表現できない
MySQL の utf8(正式名 utf8mb3)は、1文字を最大3バイトまでしか扱えない。ところが絵文字や一部の漢字は4バイト必要だ。4バイト文字をちゃんと扱うには utf8mb4 を使わなければならない。
TAP the POP の検索インデックスを支える Relevanssi のテーブルは、古い utf8mb3 のまま残っていた。一方、検索クエリ側は utf8mb4。絵文字を含むクエリが来た瞬間、「3バイトの世界」と「4バイトの世界」が衝突し、MySQL が比較を拒否してエラーになった ── これが事の真相だった。
影響範囲は限定的で、絵文字を含む検索だけが失敗し、サイト表示や通常の検索は正常だった。だが、ポップはこう考えなかった。「実害が小さいから様子見でいい」とは。
「見つけたエラーは、その場で直しておくのが鉄則。憂いは常に消してゆこう。」
これは、プロジェクトオーナーの言葉でもある。見つけたら、消す。それを実行に移した。
635,885行を、入れ替える
修正の核心は「テーブルの文字コードを utf8mb4 に統一する」ことだ。だが、ただ ALTER TABLE を流せばいいという単純な話ではなかった。直接変換しようとすると、別のエラーが立ちはだかった。
ERROR 1062: Duplicate entry
utf8mb3 時代に「3バイトで切り詰められて保存された絵文字混じりの文字列」が、utf8mb4 へ変換した瞬間に、別々だったはずのキーが衝突してしまう。過去のデータの傷が、変換を拒んだのだ。
ここでポップは正攻法を選ぶ。Relevanssi のインデックスは検索用のキャッシュ的な存在で、元データから何度でも作り直せる。だから ──
- バックアップ取得:作業前に、サーバー上へ SQL ダンプ(約 63MB)を退避
- インデックスをクリア:衝突の原因となる古いインデックスを一旦すべて消す
- コレーション変換:関連する3つのテーブルを
utf8mb4_unicode_ciに統一 - 全件再インデックス:元データから検索インデックスをまるごと作り直す
再インデックスはバックグラウンドで約10分。作り直された行数は 635,885行。クリア前の 554,777 行から、取りこぼしなく再構築された。
検索が、声を取り戻した
作業後の確認は、すべてグリーンだった。
- 3テーブルすべてのコレーション →
utf8mb4_unicode_ci✅ - 再インデックス行数 → 635,885行 ✅
- 検索(例:「ビートルズ」)の HTTP ステータス → 200 ✅
- エラーログのコレーションエラー → ゼロ ✅
絵文字一つに黙らされた検索は、声を取り戻した。そしてログからは、その小さな憂いが消えた。
【技術コラム】あなたのDBは、絵文字を飲み込めますか?
この話は WordPress や Relevanssi に限らない。「昔 utf8(utf8mb3)で作ったテーブルが、今も残っていないか」は、多くの現場に潜む地雷だ。普段は動いていても、絵文字や4バイト文字が来た瞬間に牙をむく。
自分の MySQL / MariaDB のコレーションは、こう確認できる。
-- データベース全体のデフォルト
SELECT default_character_set_name, default_collation_name
FROM information_schema.SCHEMATA
WHERE schema_name = 'your_database';
-- utf8mb3 のまま残っているテーブルを洗い出す
SELECT table_name, table_collation
FROM information_schema.TABLES
WHERE table_schema = 'your_database'
AND table_collation LIKE 'utf8mb3%';
もし utf8mb3% のテーブルが出てきたら、それは「いつか絵文字に黙らされる」予備軍だ。変換するなら、今回のポップの手順が参考になる ── ①必ずバックアップ ②直接 ALTER が Duplicate entry で止まるなら、再生成できるテーブル(インデックス・キャッシュ系)は思い切って作り直す。本体データのテーブルは、変換前にデータの重複・切り詰めを点検してから進めるのが安全だ。
そして何より ── ログは、読まなければ何も言わない。見つけたら、その場で消す。それが、憂いを未来に持ち越さないいちばん確実な方法だ。
TAP the POP の全文検索は、今日も絵文字を飲み込んで動いている。その裏側で、一行のエラーを見逃さなかった目があったことを、ここに記しておきたい。