Skip to content

[Crop][CCIP] 画像領域単位の特徴量抽出・類似検索を実装する #618

Description

@hmjn023

Parent: #612

Depends on: #615, #617, #620

背景

現行CCIPはmediaごとに1 embeddingを持ち、全体画像同士だけを検索する。人物crop単位で抽出・検索しながら、結果はユーザーが扱う親mediaへ集約する必要がある。また「同一人物」のthresholdを裸の定数にすると、model・前処理・metric更新時に意味が変わる。

設計方針

  • 全体画像は kind=full、cropはbbox付きregionとして同じembedding基盤を使う
  • 検索scopeは原則 full → fullcrop → crop に分ける
  • pgvector cosineで候補取得後、既存Rust CCIP distanceで再rankingする
  • 同じ親mediaの複数regionは最良distanceの1件へ集約し、重複排除後にtopKを適用する
  • responseへmatched region/bbox、cosine distance、CCIP distanceを含める
  • boolean判定を行う場合、thresholdをmodel・embedding version・region kind・render profile・policy versionと一緒に管理する

スコープ

  • region対応の抽出/status/stale判定/API schema
  • full/crop類似検索、親media集約、検索UI
  • model/version/revision別の再抽出
  • version付きthreshold policyと適用policyの追跡

非スコープ

受け入れ条件

  • full検索とcrop検索のscopeが混在しない
  • 同一親mediaの複数cropは最良match 1件になる
  • bbox・元画像・model更新後はembeddingがstaleになる
  • responseからmatched regionと使用policyを追跡できる
  • 既存の全体画像検索とRust再rankingを維持する
  • server/Tauri共通の検索状態・UI契約を維持する

主な参照

  • packages/application/src/services/ccip-vector-service.ts:153
  • packages/application/src/ports/ccip-vector-store.ts:1
  • apps/server/src/infrastructure/ai/rust-ai-client.ts:247
  • apps/server/src/infrastructure/api/routers/media-router.ts:56
  • packages/ui/src/hooks/use-search-page.ts:176

評価反映(2026-07-18)

Status・依存関係

本IssueはDeferred / Experimentalとし、今回のPostgres + pgvector移行およびLanceDB cutoverの完了条件には含めない。

#620ではregionを対象にできるprocessing-state基盤、revision、claim token、retry/fencingを先に確立する。crop CCIPの実際の抽出・検索を#620の初期完了条件にはせず、本Issueでその基盤を使用して実装する。

再開条件

次を満たすまで実装を開始しない。

  • #617のregion lifecycle、idempotency、source revision更新時の扱いが実データで安定している
  • #620でregion taskのatomic claim、heartbeat、retry、requested/completed revision、lost-lease fencingが利用できる
  • 誤検出、小領域、遮蔽、複数人物を含む評価セットが用意されている
  • region kind、coverage、score、model/version、render profile別の抽出対象とthreshold評価方法が定義されている
  • 同じ親mediaに属する複数regionの集約・tie・topK規則が固定されている

full embeddingは置換せず維持する。crop embeddingは、複数人物またはfull画像と十分異なるなど、評価で有用と判断されたregionだけを対象にする。

Capacity / performance gate

2026-07-18時点では画像mediaが88,184件あり、768次元vectorをfull画像へ1件ずつ保存した場合でもvector payloadだけで概算約259MiBとなる。cropは1 media対複数件となるため、bulk抽出を有効にする前に件数・容量・検索性能を再計測する。

再開時に次のgateを追加する。

  • mediaあたりregion数の分布と、抽出対象policy適用後の総embedding件数を見積もる
  • exact cosineについてsource/kind/model/version filter込みのp50/p95/p99、同時実行時のDB負荷、WAL・storage増加を計測する
  • bulk抽出throughputと再抽出時の所要時間を計測する
  • 合意したSLOをexact検索で満たさない場合だけHNSW/IVFFlatを比較し、top-K recallと親media集約後の結果を評価する
  • 最大region数、topK、検索scope、bulk concurrencyに運用上限を設ける

Rollout

実装後もexperimental flag配下で開始し、既定検索はfull → fullのまま維持する。評価セット、capacity gate、server/Tauri parityを満たしてからcrop検索を利用可能にする。

追加受け入れ条件

  • #620のregion processing-stateを使用し、generic jobへ新たに依存しない
  • full embeddingを維持し、有用性policyを満たすcropだけを抽出する
  • 評価セット上で抽出policy・threshold・親media集約の指標を記録する
  • bulk有効化前にcapacity/performance gateを通過する
  • experimental flag無効時は既存full検索の挙動が変化しない
  • server/Tauriで検索scope・結果集約・matched region表示が一致する

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions