メインコンテンツまでスキップ

Meilisearch インデックススキーマ

Meilisearch の subtitles インデックスは 1 ドキュメント = 字幕の 1 セグメント として設計される。 スキーマレスだが searchableAttributes / filterableAttributes / sortableAttributes で宣言されたフィールドのみ検索・絞り込み・ソートの対象になる。

実装は apps/api/src/lib/meilisearch/subtitles-index/subtitle-document.ts を参照。VM / Docker / API キーの運用手順は Meilisearch セットアップ に分離している。

更新タイミングの詳細は Meilisearch 更新タイミング を参照。

ドキュメントフィールド

フィールドsearchablefilterablesortable供給元(Turso)更新タイミング概要
idstring生成({videoId}_{segmentIndex}ドキュメント投入時(primary key)
videoIdstringvideos.id同上
channelIdstringvideos.channel_id同上
titlestringvideos.title同上。オーナーによる動画タイトル変更は再インデックスまで追従しない
textstringTurso には存在しない。字幕本文は Meilisearch が唯一の保存先字幕取得フロー(subtitle-fetch-orchestrator)完了時(T8)
startTimenumber (sec)セグメントの開始秒同上。sortable は「前後 5 秒コンテキスト」取得時の範囲クエリソートに使用
endTimenumber (sec)セグメントの終了秒同上
languagestringセグメントの言語コード同上
publishedAtnumber (Unix 秒)videos.published_at(ISO → Unix 秒変換)同上。sortable は公開日ソートに使用
viewCountnumber | nullvideos.view_count動画の初回取得時のみ。以降は更新されない(更新戦略は別 Issue)
likeCountnumber | nullvideos.like_count動画の初回取得時のみ。以降は更新されない
categoryIdstring | nullvideos.category_id動画の初回取得時
channelCountrystring | nullchannels.country字幕取得フロー時にチャンネルの最新 country を冗長保存。値が変動した場合は該当チャンネルの全ドキュメントを updateDocuments で追従更新(#305 以降)
durationSeconds (※1)number (sec)✅(#84 で追加予定)videos.duration_seconds動画の初回取得時に確定(動画の長さは変動しないため以降の更新不要)
subscriberCount (※1)number | null✅(#84 で追加予定)channels.subscriber_count字幕取得フロー時に channel の最新値を冗長保存。fetchChannelDiff の 24h refresh で値が変動した場合は該当チャンネルの全ドキュメントを updateDocuments(partial update)で追従更新

※1: #84 で新規追加予定のフィールド。本ドキュメントは実装前の設計状態を示す。

インデックス属性設定

Meilisearch 側の制約として filterableAttributes は 1 インデックスあたり 上限 10 個。現在 9 個で残り 1 枠。sortableAttributes には明確な上限なし。

属性現在の値#84 完了後
searchableAttributes["text", "title"]変更なし
filterableAttributes["channelId", "language", "videoId", "startTime", "publishedAt", "viewCount", "likeCount", "categoryId", "channelCountry"](9 / 10)変更なし(#84 の追加フィールドは sortable 限定)
sortableAttributes["publishedAt", "startTime"]["publishedAt", "startTime", "durationSeconds", "subscriberCount"]

冗長保存フィールドの同期戦略

text など一部を除くほぼ全フィールドは Turso の値を冗長保存している。Turso 側が変動した際にどう同期するかは以下の通り。

フィールド供給元の更新トリガードキュメント同期の実装
channelCountrychannels.countryfetchChannelDiff(T7)で変動(#305)同チャンネルの全ドキュメントを updateDocuments で partial update
subscriberCount(#84)channels.subscriber_countfetchChannelDiff で変動同上(変動なしならスキップ)
viewCount / likeCount動画単位の更新戦略が未実装#84 スコープ外。別 Issue で議論予定

updateDocuments は partial update(指定フィールドのみ更新、他フィールドは保持)なので、本文 text を誤って上書きしない設計。

関連資料