コンテンツへスキップ
DedicatedPHP 接触

データ変更に強いPHPのテキスト検索を設計する方法

データと整合するPHP検索を設計するには、正本を定め、変更を復旧可能な形で伝播し、権限と反映遅延を管理します。

PHPアプリケーションがデータベースの変更を検索インデックスと同期する概念図

検索が高速でも、削除済みのレコードが表示されたり、直近の変更が反映されなかったり、ユーザーが閲覧できなくなった情報が漏れたりすれば、検索は正しくありません。課題はテキストを見つけることだけではなく、遅延や障害があっても、現在のデータと権限に検索結果を整合させることです。

信頼できるPHPのテキスト検索を設計するには、まずユーザーが何を検索する必要があるのか、どの程度の遅延を許容するのかを決めます。そのうえで、クエリを実行する場所と、派生インデックスを維持する方法を選びます。データベースを正本とし、検索インデックスは編集先ではなく、再構築可能な表現として扱うべきです。

検索要件から始める

検索要件から始める — guía visual de DedicatedPHP

技術を選ぶ前に、実際のクエリを具体化しましょう。タイトルや説明文の単語、フレーズ、接頭辞、複数フィールドのどれを検索しますか?状態、カテゴリ、日付、言語、所有者によるフィルターはありますか?誤字への許容度、同義語、関連度、日付順の並べ替えは重要ですか?

運用上の目標も定義します。許容できるレイテンシ、更新頻度、想定データ量、検索を利用できない場合の動作です。「最新」の意味は、変更が即座に表示されることかもしれませんし、数秒後に表示されることかもしれません。この違いはアーキテクチャに影響するため、明確にする必要があります。

代表的なクエリを使って検索品質を検証しましょう。一般的な語と出現頻度の低い語、フィールドが空のレコード、アクセント記号、異なる言語、権限の異なるユーザーを含めます。期待する結果が表示されるかだけでなく、並び順とフィルターが妥当かも確認してください。

SQLで十分か判断する

データセットとクエリが扱いやすく、フィルターが単純で、データベースの検索機能で要件を満たせる場合は、SQLクエリで十分なことがあります。エンジンと設定が重要です。テキスト検索機能、正規化、関連度の扱いは、すべてのシステムで同じではありません。実際のデータとクエリで制約を確認してください。

SQLには実用的な利点があります。データと検索を同じ整合性モデルに参加させられます。また、初期段階で追加サービスを運用したり、別のインデックスを同期したりする必要もありません。ただし、戦略なしに列への部分一致検索をすべてのクエリで行うという意味ではありません。実行計画、利用可能なインデックス、フィルターのコストを確認しましょう。

SQLではうまく対応できない機能がクエリに必要な場合、検索のレイテンシや負荷が主要な処理に影響する場合、あるいは関連度、ファセット、テキスト分析を独立して進化させたい場合は、専用インデックスを検討してください。これはアーキテクチャ上の判断であり、アプリケーションがSaaSであることや、レコード数が多いことだけを理由に必須となるものではありません。

正本を維持し、インデックスを定義する

トランザクションデータベースを、作成、変更、削除、権限の正本にするべきです。インデックス対象のエンティティとフィールド、その変換方法、元のレコードを特定する識別子を文書化します。インデックスには正規化したテキストやフィルター用フィールドを含めてもかまいませんが、明確な整合プロセスなしに、編集可能な複製として扱ってはいけません。

権限には特に注意が必要です。インデックスに認可用フィールドを保存するのか、アプリケーションが各結果を正本と照合するのかを決めます。どちらの方法でも、ドキュメントがインデックスに残っているという理由で検索がアクセス権を与えてはなりません。サーバー側でアクセスフィルターを適用し、所有者、公開範囲、ロールの変更も伝播すべき変更として扱います。

権限変更の遅延に対して最大限の安全性が必要なら、結果を取得する際に認可を再確認してください。その結果、一部が破棄されることになっても同様です。その確認に失敗した場合の動作も設計に含めます。未検証の結果を代わりに返すべきではありません。

変更を復旧可能な形で伝播する

データベースを更新してからキューにメッセージを送るという独立した2つの操作は、取りこぼしの可能性を生みます。最初の操作がコミットされ、2つ目が失敗することがあるためです。これを避ける一般的なパターンが、トランザクショナルアウトボックス(アウトボックス)です。トランザクション内で、ビジネス上の変更と未処理イベントを同じデータベースに保存します。別プロセスがイベントを発行または処理し、進捗を記録します。

コンシューマーは非同期でインデックスを更新します。そのためデータが古い状態になる時間が生じるので、目標を明示し、計測する必要があります。書き込み直後の読み取りが必要なケースには、保存したレコードをレスポンスで返す、または一時的に正本へ問い合わせるなど、その要件に対応する方法を用意してください。処理が非同期であるのに、即時の整合性を約束してはいけません。

処理は冪等になるよう設計します。同じイベントを2回受け取っても、ドキュメントが重複したり、データが巻き戻ったりしてはいけません。レコードの安定した識別子と、必要に応じて変更のバージョンや連番を含めます。イベントが順不同で届く可能性があるなら、古いバージョンで新しいデータを上書きしないようにします。再試行は安全に行える必要があります。処理できないメッセージは、黙って消えるのではなく、調査できる状態で残さなければなりません。

削除と再構築を通常のケースとして扱う

削除は明示的に伝播させる必要があります。ワーカーがレコードを参照する前にシステムが物理削除してしまう場合、イベントには対応するドキュメントを削除するために必要な識別情報を含めます。遅延や再試行のあるフローでは、削除マーカー(tombstone)や削除バージョンを使うと、古いイベントによって検索結果が再作成されるのを防げます。

スキーマ変更やインデックス破損に備え、正本から、適切なサイズのバッチで再構築します。進捗地点を記録し、エラーを管理して、データベースへの負荷を制限してください。新しいインデックスの作成中も、その間に発生する変更を伝播し続けます。そうしなければ、インデックスは有効化前に古くなる可能性があります。

新しいインデックスの作成と検証が完了したら、選択した技術と互換性のある設定やエイリアスなどを使い、読み取り先を制御しながら切り替えます。結果を確認している間は、元に戻せる手段を維持してください。段階的な有効化は運用上の判断であり、管理されていない形でユーザーに製品変更を公開することとは異なります。

整合性を計測し、運用に備える

変更のコミットから検索で利用可能になるまでの遅延に加え、未処理イベント、エラー、再試行、恒久的な失敗を監視します。キューが稼働しているように見えても、イベントが滞留している場合があります。鮮度の目標に合ったしきい値でアラートを設定し、再試行やドキュメント修復の手順を定めてください。

整合性確認を定期的に実施します。インデックスされるべきレコードと既存ドキュメントを、一部のサンプル、または可能であれば全件で比較してください。これにより、メッセージの欠落、変換の不具合、反映されなかった削除を検出できます。不整合が見つかった場合に、レコードの再インデックスやインデックスの再構築など、文書化された対応につながるようにします。

本番投入前のチェックリスト

本番投入前のチェックリスト — guía visual de DedicatedPHP
  • 代表的なケースでクエリと関連度の基準を検証しましたか?
  • 正本、インデックス対象フィールド、その変換方法を文書化しましたか?
  • 部分的な障害の後も、変更と削除がインデックスに反映されますか?
  • 重複や順不同のメッセージに耐えられる処理になっていますか?
  • 検索時に権限を適用し、変更時に更新していますか?
  • 遅延を計測し、整合性確認と再構築の手順を用意していますか?
  • 新しいインデックスを検証し、結果が悪化した場合に元に戻す計画がありますか?

信頼できるPHPのテキスト検索は、流行の技術を選ぶことよりも、整合性、権限、復旧方法を定義することにかかっています。計測した要件を満たす最もシンプルな方法から始めましょう。SQLで必要なクエリや性能を満たせなくなったら、同期方法が明示され、可観測で、再構築可能な専用インデックスを導入してください。

これらのアイデアをあなたのプロジェクトに活用してみませんか?あなたのPHPプラットフォームについて話し合いましょう。
関連サービスを見る