ある開発チームがOpenSearchとSQLite FTS5を組み合わせたことで、レイテンシを20ms未満に抑えたまま、ビデオ検索における結果ゼロの割合を11.4%から2.1%に削減することに成功しました。これにより、ユーザーが「blackpink jenny solo stag」と入力しても、空のリストが表示される代わりに、正しい「BLACKPINK Jennie SOLO stage」が表示されるようになりました。
なぜ変更が必要だったのか
動画配信プラットフォームの検索ログから、ある共通の問題が明らかになりました。ラテン文字のタイトルにおけるたった一つのタイポ(打ち間違い)が、すべてのマッチングを消失させてしまうという問題です。SQLiteのFTS5拡張機能は、中国語・日本語・韓国語(CJK)のテキストにおける部分一致能力には定評がありますが、ファジーマッチング(曖昧検索)には対応していません。名前や曲名の一文字の綴り間違いが、クエリ全体を台無しにしてしまいます。
既存のパイプラインでは、SQLiteを唯一のインデックスとして扱っていました。CJKのクエリにはうまく対応していましたが、ラテン文字のタイポに対するセーフティネットがありませんでした。そのためチームは、実績のあるFTS5レイヤーを破棄することなく、タイポ耐性を提供できる補完的な検索エンジンを探しました。
OpenSearchの導入方法
OpenSearchをフロントラインの検索サービスとして稼働させ、SQLiteを「信頼できる唯一の情報源(source of truth)」として残しました。これら2つのシステムは並行して動作します。まずOpenSearchがユーザーのクエリを受け取り、十分に迅速に応答できればその結果を表示します。OpenSearchがタイムアウトまたはエラーになった場合、リクエストはSQLite FTS5インデックスへとフォールバックされます。この「フェイルセーフ」設計により、ネットワークの一時的な不具合によって検索バーが空のままになることを防いでいます。
マルチフィールド・マッピング
各ビデオタイトルは、OpenSearch内で3つの方法でインデックス化されます。
- title.std – ASCII foldingを備えた標準アナライザーによって処理されます。これにより、アクセント付き文字が正規化され、ほとんどのラテン文字のタイポに対応できます。
- title.cjk – ビグラム(2文字のトークン)を作成するCJKアナライザーによって処理されます。これにより、FTS5がアジア言語に対して提供していた部分一致の強みが維持されます。
- title.keyword – 完全一致検索とソートのために、変更せずに保存されます。
フィールドを分けることで、トークン化戦略を混在させることなく、各スクリプトに対して適切な解析をクエリに適用できます。
ブースト階層
単一の巨大なクエリではなく、結果を自動的にランク付けする階層型クエリを構築しました。
title.keywordに対する完全なフレーズ一致には最も高いブースト値が割り当てられ、完全一致の結果がリストの上位を占めるようにします。title.cjkに対するCJKビグラム一致には中程度のブーストが与えられ、アジア言語検索の品質を維持します。title.stdに対するラテン文字のファジーマッチには低いブーストが与えられ、完全一致の結果を覆い隠すことなく、タイポ耐性のある結果を表示させます。
この階層的なアプローチにより、チューニングが容易になります。一つのブースト値を調整するだけで、そのクラスに属する一致結果全体の相対的な重要度を変更できます。
スマートなファジー性
ファジー性(限られた回数の文字編集を許容すること)は、ラテン文字フィールドにのみ適用されます。CJKでは一文字の変化が意味を完全に変えてしまうことが多いため、チームは title.cjk のファジー性を無効にしました。ラテン文字テキストの場合、クエリはOpenSearchの AUTO ファジー設定を使用します。これは単語の長さに応じて許容される編集距離を調整し、許容度と関連性のバランスを取るものです。
パフォーマンスとフォールバック・ロジック
検索ルーチンは、OpenSearchの呼び出しを try-catch ブロックでラップしています。
- OpenSearchが400ms以内に返答すれば、その結果が表示されます。
- 呼び出しが例外をスローするかタイムアウトを超えた場合、システムは直ちにSQLite FTS5に対してクエリを再実行します。
これにより、ネットワークの遅延やサービスの停止がユーザー体験を損なうことがないようにしています。検索レイテンシは20ms未満を維持しました。
測定可能なインパクト
- ラテン文字クエリにおける結果ゼロの割合が**11.4%から2.1%**に低下しました。
- CJKクエリの検索品質は変わらず、新しいCJKアナライザーが元のFTS5インデックスの強みを維持していることが確認されました。
- エンドツーエンドのレイテンシは目標の20msを十分に下回ったままとなり、追加されたレイヤーがUIの速度を低下させなかったことを意味しています。
教訓とトレードオフ
- 折りたたみ(folding)とファジー性(fuzziness)の分離 – 折りたたみ(文字の正規化)とファジー性(タイポの処理)は、異なる問題に対処します。これらを別々のフィールドに保持することで、意図しない相互作用を避けることができます。
- 検索インデックスを「信頼できる唯一の情報源」として扱わない – SQLiteは正本(canonical store)であり、OpenSearchはそこから派生した、更新可能なビューです。これにより、インデックスの乖離(drift)を防ぎ、障害発生後の復旧を簡素化できます。
- ブースト階層によるチューニングの簡素化 – 関連する一致結果を単一のブースト係数でグループ化することで、調整が必要なパラメータの数を減らすことができます。
次に注目すべき点
この実験により、小規模なOpenSearchレイヤーを導入するだけで、SQLite FTS5の定評あるCJK機能を損なうことなく、多言語の動画タイトルに対するタイポ耐性を劇的に向上させられることが証明されました。検索の関連性が視聴時間に直接影響を与えるプラットフォームにとって、この改善はユーザー体験の具体的な向上へと直結します。
