feat: 分片指纹存储改造 + 存量指纹重建脚本 #1657 #1669

Merged
xiaoxia merged 2 commits from feat/fingerprint-chunks-1657 into develop 2026-09-03 21:08:37 +08:00
Owner

改动

1. 新建 video_fingerprint_chunks 表(Migration 063)

  • 按时间分片存储 pHash + color_histogram
  • 索引:video_id, project_id, user_id

2. 新增 VideoFingerprintChunkModel

  • packages/adapters/sqlalchemy_impl/models.py

3. 改造 dedup.py 指纹计算

  • compute_fingerprint() 改为按时间分片抽帧
    • 短视频(≤60s):每 2s 一片
    • 长视频(>60s):每 5s 一片
  • VideoFingerprint 新增 chunks 字段(list[FingerprintChunk]
  • 向后兼容:keyframe_phashes/color_histograms 保留
  • to_chunk_models() 方法转换为 SQLAlchemy Model
  • check_duplicate() 优先从分片表读取,回退到 JSON 字段(存量兼容)
  • check_duplicate_task() 写入分片表

4. 改造 dedup_helpers.py

  • create_video_record_and_dedup() 同步写入分片表

5. 存量指纹重建脚本

  • apps/api/scripts/rebuild_fingerprint_chunks.py
  • 支持 --dry-run--batch-size
  • 幂等:已有分片数据的视频跳过

6. 单元测试(11 个)

  • 分片策略:60s→30片,120s→24片
  • to_chunk_models() 输出正确
  • _save_fingerprint_chunks 幂等性
  • to_dict() 向后兼容

技术债务约束

  • 存量重建脚本随本 Issue 一起交付
  • 新代码有单元测试覆盖
  • API 向后兼容:video_fingerprint JSON 字段保留
  • video_fingerprint_chunks 是扩展不是替换

Closes #1657

## 改动 ### 1. 新建 video_fingerprint_chunks 表(Migration 063) - 按时间分片存储 pHash + color_histogram - 索引:video_id, project_id, user_id ### 2. 新增 VideoFingerprintChunkModel - `packages/adapters/sqlalchemy_impl/models.py` ### 3. 改造 dedup.py 指纹计算 - `compute_fingerprint()` 改为按时间分片抽帧 - 短视频(≤60s):每 2s 一片 - 长视频(>60s):每 5s 一片 - `VideoFingerprint` 新增 `chunks` 字段(`list[FingerprintChunk]`) - 向后兼容:`keyframe_phashes`/`color_histograms` 保留 - `to_chunk_models()` 方法转换为 SQLAlchemy Model - `check_duplicate()` 优先从分片表读取,回退到 JSON 字段(存量兼容) - `check_duplicate_task()` 写入分片表 ### 4. 改造 dedup_helpers.py - `create_video_record_and_dedup()` 同步写入分片表 ### 5. 存量指纹重建脚本 - `apps/api/scripts/rebuild_fingerprint_chunks.py` - 支持 `--dry-run` 和 `--batch-size` - 幂等:已有分片数据的视频跳过 ### 6. 单元测试(11 个) - 分片策略:60s→30片,120s→24片 - `to_chunk_models()` 输出正确 - `_save_fingerprint_chunks` 幂等性 - `to_dict()` 向后兼容 ### 技术债务约束 - ✅ 存量重建脚本随本 Issue 一起交付 - ✅ 新代码有单元测试覆盖 - ✅ API 向后兼容:video_fingerprint JSON 字段保留 - ✅ video_fingerprint_chunks 是扩展不是替换 Closes #1657
xiaoxia added 1 commit 2026-09-03 20:41:32 +08:00
feat: 分片指纹存储改造 + 存量指纹重建脚本 #1657
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (pull_request) Successful in 3s
CI/CD Pipeline / Check push changed paths (pull_request) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 2s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 2m19s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 2m43s
CI/CD Pipeline / Integration Tests (pull_request) Successful in 1m22s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 8s
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 7s
CI/CD Pipeline / Build Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Validate - Style (pull_request) Has been cancelled
CI/CD Pipeline / Validate - Security (pull_request) Has been cancelled
CI/CD Pipeline / Validate - Python (mypy + alembic) (pull_request) Has been cancelled
CI/CD Pipeline / Unit Tests (pull_request) Has been cancelled
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been cancelled
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been cancelled
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been cancelled
CI/CD Pipeline / Build Production API Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Web Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been cancelled
CI/CD Pipeline / Deploy Production (pull_request) Has been cancelled
CI/CD Pipeline / Production Browser E2E (pull_request) Has been cancelled
CI/CD Pipeline / ACR Image Cleanup (pull_request) Has been cancelled
CI/CD Pipeline / Canary Release to Production (pull_request) Has been cancelled
CI/CD Pipeline / CI Gate (pull_request) Has been cancelled
AI Code Review / AI Code Review (pull_request) Has been cancelled
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been cancelled
cbca0c3584
## 改动

### 1. 新建 video_fingerprint_chunks 表(Migration 063)
- 按时间分片存储 pHash + color_histogram
- 索引:video_id, project_id, user_id

### 2. 新增 VideoFingerprintChunkModel
- packages/adapters/sqlalchemy_impl/models.py

### 3. 改造 dedup.py 指纹计算
- compute_fingerprint() 改为按时间分片抽帧
  - 短视频(≤60s):每 2s 一片
  - 长视频(>60s):每 5s 一片
- VideoFingerprint 新增 chunks 字段(list of FingerprintChunk)
- 向后兼容:keyframe_phashes/color_histograms 保留
- to_chunk_models() 方法转换为 SQLAlchemy Model
- check_duplicate() 优先从分片表读取,回退到 JSON 字段
- check_duplicate_task() 写入分片表

### 4. 改造 dedup_helpers.py
- create_video_record_and_dedup() 同步写入分片表

### 5. 存量指纹重建脚本
- apps/api/scripts/rebuild_fingerprint_chunks.py
- 支持 --dry-run 和 --batch-size
- 幂等:已有分片数据的视频跳过

### 6. 单元测试(11 个)
- 分片策略:60s→30片,120s→24片
- to_chunk_models() 输出正确
- _save_fingerprint_chunks 幂等性
- to_dict() 向后兼容

Closes #1657

🚀 预览环境已部署

项目 详情
PR号 #1669
预览链接 https://pr-1669.preview.xiaoxiajianji.com
API环境 staging

💡 预览环境使用 staging API 数据,请勿在预览环境中操作重要数据。

🔄 每次提交新代码后预览环境会自动更新。

🗑️ PR 关闭或合并后,预览环境会自动清理。

🚀 **预览环境已部署** | 项目 | 详情 | |------|------| | PR号 | #1669 | | 预览链接 | [https://pr-1669.preview.xiaoxiajianji.com](https://pr-1669.preview.xiaoxiajianji.com) | | API环境 | staging | > 💡 预览环境使用 staging API 数据,请勿在预览环境中操作重要数据。 > > 🔄 每次提交新代码后预览环境会自动更新。 > > 🗑️ PR 关闭或合并后,预览环境会自动清理。
auto-approve-bot added 1 commit 2026-09-03 20:50:40 +08:00
style: auto-format with black + isort + prettier [skip ci-format-check]
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (pull_request) Successful in 2s
CI/CD Pipeline / Check push changed paths (pull_request) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 2s
AI Code Review / AI Code Review (pull_request) Failing after 1m46s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 2m47s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 2m54s
CI/CD Pipeline / Validate - Style (pull_request) Failing after 2m29s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / Integration Tests (pull_request) Successful in 2m6s
CI/CD Pipeline / Build Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 24s
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 22s
CI/CD Pipeline / Retag skipped Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been skipped
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / ACR Image Cleanup (pull_request) Has been skipped
CI/CD Pipeline / Validate - Python (mypy + alembic) (pull_request) Successful in 4m45s
CI/CD Pipeline / Unit Tests (pull_request) Successful in 8m59s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Successful in 10m57s
ACR Cleanup / ACR Image Cleanup (pull_request_target) Successful in 7s
Preview Cleanup / Cleanup Preview Environment (pull_request) Successful in 1m37s
CI/CD Pipeline / Validate - Security (pull_request) Successful in 28m20s
CI/CD Pipeline / Build Production API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been skipped
CI/CD Pipeline / CI Gate (pull_request) Failing after 1s
CI/CD Pipeline / Deploy Production (pull_request) Has been skipped
CI/CD Pipeline / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
244691d335
Collaborator

【阻塞级判定】

  • 是否存在阻塞级问题:是
  • 阻塞级问题数量:3 个

📊 审查概览

  • 整体评价:需修改
  • 建议级问题数量:1 个

🔴 阻塞级问题(必须修复)

  1. [apps/worker/video_processing/dedup.py: 286-293] N+1 查询问题导致严重性能隐患

    • 问题类型:性能问题 / 逻辑bug
    • 问题描述:在 check_duplicate 方法中,循环遍历项目内所有视频(for existing in videos_in_project),并在循环内部调用 self._get_existing_chunks(existing.id, session) 查询数据库。如果一个项目中有 N 个视频,这将产生 1 + N 次数据库查询。对于视频较多的项目,会导致查重任务响应极慢甚至数据库连接耗尽。
    • 修改建议:应在循环前一次性批量查询所有相关视频的 chunks 数据(使用 video_id IN (...)),然后在内存中构建字典进行匹配,避免在循环中进行数据库查询。
  2. [apps/api/scripts/rebuild_fingerprint_chunks.py: 106-122] 数据一致性缺失

    • 问题类型:数据损坏风险
    • 问题描述:重建脚本计算了新的指纹(包含新的 MD5 和新的分片数据),并写入了 video_fingerprint_chunks 表,但未更新 generated_videos 表中的 video_fingerprint JSON 字段。
    • 后果:这会导致数据库中出现数据不一致——JSON 字段中存储的是旧的 MD5(基于旧算法)和旧的采样数据,而 chunks 表中是新算法的数据。当系统进行 MD5 精确匹配时,会使用旧 MD5,导致无法匹配到新算法处理的相同视频,查重功能失效。
    • 修改建议:在 rebuild_one 函数中,除了保存 chunks,还应更新 GeneratedVideoModel.video_fingerprint 字段为 fingerprint.to_dict(),并提交事务。
  3. [apps/worker/video_processing/dedup_helpers.py: 103-107] 关键异常被静默吞噬

    • 问题类型:逻辑bug
    • 问题描述:在保存分片指纹 _save_fingerprint_chunks 时使用了 try...except Exception 并仅记录 warning,未向上抛出异常。
    • 后果:如果保存 chunks 失败(如数据库连接断开、约束冲突),主流程会认为任务成功并继续,导致视频记录存在但分片数据缺失。虽然查重逻辑有回退机制(读取 JSON),但这会导致新功能在静默中失效,且难以排查数据缺失问题。
    • 修改建议:对于此类数据写入失败,应抛出异常或返回错误状态,确保主事务回滚,避免产生脏数据。

💡 改进建议(不阻塞合并)

  1. [apps/worker/video_processing/dedup.py: 286-310] 查重比对逻辑的不对称性风险
    • 具体内容:新算法的分片数量是动态的(基于时长),而旧算法是固定的(约10帧)。在 check_duplicate 中,新视频(可能有30个分片)与旧视频(10个分片)进行比对时,计算 avg(min(hd)) 的逻辑会产生不对称的相似度分数。建议评估是否需要归一化处理,或者确认这种不对称在业务上是否可接受。

良好实践

  • 使用了 bulk_save_objects 进行批量写入,效率较高。
  • 迁移脚本中包含了幂等性检查(existing_count),支持重跑。
  • 数据模型定义清晰,索引覆盖了查询维度。

🤖 由 AI 代码审查机器人自动生成 | 2026-09-03 12:52:38 | 模型:

### 【阻塞级判定】 - 是否存在阻塞级问题:是 - 阻塞级问题数量:3 个 ### 📊 审查概览 - 整体评价:需修改 - 建议级问题数量:1 个 ### 🔴 阻塞级问题(必须修复) 1. **[apps/worker/video_processing/dedup.py: 286-293] N+1 查询问题导致严重性能隐患** - 问题类型:性能问题 / 逻辑bug - 问题描述:在 `check_duplicate` 方法中,循环遍历项目内所有视频(`for existing in videos_in_project`),并在循环内部调用 `self._get_existing_chunks(existing.id, session)` 查询数据库。如果一个项目中有 N 个视频,这将产生 1 + N 次数据库查询。对于视频较多的项目,会导致查重任务响应极慢甚至数据库连接耗尽。 - 修改建议:应在循环前一次性批量查询所有相关视频的 chunks 数据(使用 `video_id IN (...)`),然后在内存中构建字典进行匹配,避免在循环中进行数据库查询。 2. **[apps/api/scripts/rebuild_fingerprint_chunks.py: 106-122] 数据一致性缺失** - 问题类型:数据损坏风险 - 问题描述:重建脚本计算了新的指纹(包含新的 MD5 和新的分片数据),并写入了 `video_fingerprint_chunks` 表,但**未更新** `generated_videos` 表中的 `video_fingerprint` JSON 字段。 - 后果:这会导致数据库中出现数据不一致——JSON 字段中存储的是旧的 MD5(基于旧算法)和旧的采样数据,而 `chunks` 表中是新算法的数据。当系统进行 MD5 精确匹配时,会使用旧 MD5,导致无法匹配到新算法处理的相同视频,查重功能失效。 - 修改建议:在 `rebuild_one` 函数中,除了保存 chunks,还应更新 `GeneratedVideoModel.video_fingerprint` 字段为 `fingerprint.to_dict()`,并提交事务。 3. **[apps/worker/video_processing/dedup_helpers.py: 103-107] 关键异常被静默吞噬** - 问题类型:逻辑bug - 问题描述:在保存分片指纹 `_save_fingerprint_chunks` 时使用了 `try...except Exception` 并仅记录 warning,未向上抛出异常。 - 后果:如果保存 chunks 失败(如数据库连接断开、约束冲突),主流程会认为任务成功并继续,导致视频记录存在但分片数据缺失。虽然查重逻辑有回退机制(读取 JSON),但这会导致新功能在静默中失效,且难以排查数据缺失问题。 - 修改建议:对于此类数据写入失败,应抛出异常或返回错误状态,确保主事务回滚,避免产生脏数据。 ### 💡 改进建议(不阻塞合并) 1. **[apps/worker/video_processing/dedup.py: 286-310] 查重比对逻辑的不对称性风险** - 具体内容:新算法的分片数量是动态的(基于时长),而旧算法是固定的(约10帧)。在 `check_duplicate` 中,新视频(可能有30个分片)与旧视频(10个分片)进行比对时,计算 `avg(min(hd))` 的逻辑会产生不对称的相似度分数。建议评估是否需要归一化处理,或者确认这种不对称在业务上是否可接受。 ### ✅ 良好实践 - 使用了 `bulk_save_objects` 进行批量写入,效率较高。 - 迁移脚本中包含了幂等性检查(`existing_count`),支持重跑。 - 数据模型定义清晰,索引覆盖了查询维度。 --- <sub>🤖 由 AI 代码审查机器人自动生成 | 2026-09-03 12:52:38 | 模型: </sub> <!-- AI_CODE_REVIEW_AUTO_COMMENT -->
xiaoxia merged commit 8ecf381a9d into develop 2026-09-03 21:08:37 +08:00

🗑️ 预览环境已清理

PR #1669 已关闭或合并,对应的预览环境已被清理。

如有需要,可以重新打开 PR 来重新生成预览环境。

🗑️ **预览环境已清理** PR #1669 已关闭或合并,对应的预览环境已被清理。 > 如有需要,可以重新打开 PR 来重新生成预览环境。
Sign in to join this conversation.