ベクトル検索
シナリオ: CityDrive は各フレームの埋め込みを TiDB Cloud Lake に直接保持しています。これらのベクトル埋め込みは、動画キーフレームに対して AI モデルが推論を実行し、視覚的な意味特徴を捉えた結果です。意味的類似検索(「これに似たフレームを探す」)は、従来の SQL 分析と並行して実行でき、別個のベクトルサービスは不要です。
frame_embeddings テーブルは、frame_events、frame_metadata_catalog、frame_geo_points と同じ frame_id キーを共有しているため、セマンティック検索と従来の SQL を密接に連携させることができます。
1. 埋め込みテーブルを準備する
本番モデルは通常 512~1536 次元を出力します。以下の例では 512 を使用しているため、DDL を変更せずにそのままデモクラスターへコピーできます。
CREATE OR REPLACE TABLE frame_embeddings (
frame_id STRING,
video_id STRING,
sensor_view STRING,
embedding VECTOR(512),
encoder_build STRING,
created_at TIMESTAMP,
VECTOR INDEX idx_frame_embeddings(embedding) distance='cosine'
);
-- SQL UDF: build 512 dims via ARRAY_AGG + window frame; tutorial placeholder only.
CREATE OR REPLACE FUNCTION demo_random_vector(seed STRING)
RETURNS TABLE(embedding VECTOR(512))
AS $$
SELECT CAST(
ARRAY_AGG(rand_val) OVER (
PARTITION BY seed
ORDER BY seq
ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING
)
AS VECTOR(512)
) AS embedding
FROM (
SELECT seed,
dims.number AS seq,
(RAND() * 0.2 - 0.1)::FLOAT AS rand_val
FROM numbers(512) AS dims
) vals
QUALIFY ROW_NUMBER() OVER (PARTITION BY seed ORDER BY seq) = 1;
$$;
INSERT INTO frame_embeddings (frame_id, video_id, sensor_view, embedding, encoder_build, created_at)
SELECT 'FRAME-0101', 'VID-20250101-001', 'roof_cam', embedding, 'clip-lite-v1', '2025-01-01 08:15:21'
FROM demo_random_vector('FRAME-0101')
UNION ALL
SELECT 'FRAME-0102', 'VID-20250101-001', 'roof_cam', embedding, 'clip-lite-v1', '2025-01-01 08:33:54'
FROM demo_random_vector('FRAME-0102')
UNION ALL
SELECT 'FRAME-0201', 'VID-20250101-002', 'front_cam', embedding, 'night-fusion-v2', '2025-01-01 11:12:02'
FROM demo_random_vector('FRAME-0201')
UNION ALL
SELECT 'FRAME-0401', 'VID-20250103-001', 'rear_cam', embedding, 'night-fusion-v2', '2025-01-03 21:18:07'
FROM demo_random_vector('FRAME-0401');
この配列ジェネレーターは、チュートリアルを自己完結させるためだけのものです。本番では、これをモデルから得た実際の埋め込みに置き換えてください。
まだ SQL 分析ガイドを実行していない場合は、補助となる frame_events テーブルを作成し、このベクトル検索の手順で結合する同じサンプル行を投入してください。
CREATE OR REPLACE TABLE frame_events (
frame_id STRING,
video_id STRING,
frame_index INT,
collected_at TIMESTAMP,
event_tag STRING,
risk_score DOUBLE,
speed_kmh DOUBLE
);
INSERT INTO frame_events VALUES
('FRAME-0101', 'VID-20250101-001', 125, '2025-01-01 08:15:21', 'hard_brake', 0.81, 32.4),
('FRAME-0102', 'VID-20250101-001', 416, '2025-01-01 08:33:54', 'pedestrian', 0.67, 24.8),
('FRAME-0201', 'VID-20250101-002', 298, '2025-01-01 11:12:02', 'lane_merge', 0.74, 48.1),
('FRAME-0301', 'VID-20250102-001', 188, '2025-01-02 09:44:18', 'hard_brake', 0.59, 52.6),
('FRAME-0401', 'VID-20250103-001', 522, '2025-01-03 21:18:07', 'night_lowlight', 0.63, 38.9),
('FRAME-0501', 'VID-MISSING-001', 10, '2025-01-04 10:00:00', 'sensor_fault', 0.25, 15.0);
ドキュメント: ベクトル型 および ベクトルインデックス。
2. コサイン検索を実行する
あるフレームの埋め込みを取得し、HNSW インデックスで最も近い近傍を返します。
WITH query_embedding AS (
SELECT embedding
FROM frame_embeddings
WHERE frame_id = 'FRAME-0101'
)
SELECT e.frame_id,
e.video_id,
COSINE_DISTANCE(e.embedding, q.embedding) AS distance
FROM frame_embeddings AS e
CROSS JOIN query_embedding AS q
ORDER BY distance
LIMIT 3;
出力例:
frame_id | video_id | distance
FRAME-0101| VID-20250101-001 | 0.0000
FRAME-0201| VID-20250101-002 | 0.9801
FRAME-0102| VID-20250101-001 | 0.9842
距離が小さいほど、より類似しています。VECTOR INDEX により、数百万フレーム規模でもレイテンシーを低く保てます。
ベクトル比較の前後で、従来の述語(ルート、動画、センサービュー)を追加して候補集合を絞り込めます。
WITH query_embedding AS (
SELECT embedding
FROM frame_embeddings
WHERE frame_id = 'FRAME-0201'
)
SELECT e.frame_id,
e.sensor_view,
COSINE_DISTANCE(e.embedding, q.embedding) AS distance
FROM frame_embeddings AS e
CROSS JOIN query_embedding AS q
WHERE e.sensor_view = 'rear_cam'
ORDER BY distance
LIMIT 5;
出力例:
frame_id | sensor_view | distance
FRAME-0401| rear_cam | 1.0537
オプティマイザは、sensor_view フィルターを適用しつつ、引き続きベクトルインデックスを使用します。
3. 類似フレームを拡張する
上位の一致結果を具体化し、その後 frame_events で拡張して下流の分析に利用します。
WITH query_embedding AS (
SELECT embedding
FROM frame_embeddings
WHERE frame_id = 'FRAME-0102'
),
similar_frames AS (
SELECT frame_id,
video_id,
COSINE_DISTANCE(e.embedding, q.embedding) AS distance
FROM frame_embeddings e
CROSS JOIN query_embedding q
ORDER BY distance
LIMIT 5
)
SELECT sf.frame_id,
sf.video_id,
fe.event_tag,
fe.risk_score,
sf.distance
FROM similar_frames sf
LEFT JOIN frame_events fe USING (frame_id)
ORDER BY sf.distance;
出力例:
frame_id | video_id | event_tag | risk_score | distance
FRAME-0102| VID-20250101-001 | pedestrian | 0.67 | 0.0000
FRAME-0201| VID-20250101-002 | lane_merge | 0.74 | 0.9802
FRAME-0101| VID-20250101-001 | hard_brake | 0.81 | 0.9842
FRAME-0401| VID-20250103-001 | night_lowlight | 0.63 | 1.0020
埋め込みがリレーショナルテーブルの隣に存在するため、「見た目が似ているフレーム」から、「hard_brake タグ、特定の天候、または JSON 検出結果も持つフレーム」へと、データを別サービスへエクスポートすることなく分析を展開できます。
ベクトル検索中にロールが取得できるドキュメントを制限するには、行アクセスポリシー を適用してください。これにより、可視性はクエリにドキュメント ID を詰め込むのではなく、エンジンによって強制されます。