postgresql-data-model.md 8.21 KB

PostgreSQL 数据模型 / 当前 song-centric 4 表方案

更新:2026-06-04
关联 SQL:acr-engine/sql/acr_pg_schema_songcentric_v1.sql


1. 一页结论

当前默认只认 4 张核心物理表:

media_entity -> audio_object -> feature_fact -> set_membership

逻辑语义这样理解:

song -> asset -> window -> fingerprint / embedding

这套设计的核心价值:

  • song-centric:最终稳定返回 song_id
  • 融合优先:减少 recording/work/version 首阶段理解成本
  • 特征统一:exact lane 和 semantic lane 统一落到 feature_fact
  • 模型可替换:换 model_name/model_version/feature_set_name 不必重拆 schema
  • 证据可回溯:任何召回都能回查到具体 window -> asset -> song

2. 为什么现在收敛成 4 表

当前目标不是先建一个最完整的音乐版权知识图谱,而是先把下面这件事做稳:

收到一个录音/BGM/片段/翻唱相关查询后,能够快速定位它最可能对应哪个 song_id

因此当前优先级是:

  1. 先固定 song 作为最终归属对象
  2. 保留 asset,支持同一 song 下多个音频文件
  3. 保留 window,支持切片级 evidence 与 offset
  4. 用一张 feature_fact 同时承载 fingerprint 与 embedding
  5. 用一张 set_membership 管理 reference/eval/hot 集合

3. 4 张表分别解决什么问题

当前主要 type 解决的问题
media_entity song 最终归属对象是谁
audio_object asset, window 实际音频文件是什么、切成了哪些窗口
feature_fact fingerprint, embedding 每个窗口/对象用了哪个模型、产出了什么特征
set_membership reference_set, eval_set, hot_set 哪些 song/asset/window/feature 属于哪个集合

4. 切片 / 模型 / feature 分别在哪张表

业务对象 物理表 关键字段 用途
song media_entity entity_type='song' 最终返回 song_id
asset audio_object object_type='asset' 存原始音频文件元数据
window audio_object object_type='window', parent_object_id=<asset_id> 存切片范围、offset、evidence
fingerprint feature_fact feature_type='fingerprint', fingerprint_value exact lane 检索
embedding feature_fact feature_type='embedding', embedding_uri/vector_table_name, embedding_dim semantic lane 检索
model identity feature_fact model_name, model_version 区分 MERT / MuQ / ECAPA / fallback
feature set identity feature_fact feature_set_name, feature_schema_ver 区分特征配置、窗口策略、schema 版本
reference routing set_membership set_type, set_name 控制 reference/eval/hot 范围

4.1 一个关键设计点

当前 模型信息不单独放 registry 表作为默认主链依赖,而是先直接沉淀在 feature_fact

  • 这样 Phase-1 更轻
  • 更适合“直接复用开源 encoder,不先训练/微调”的当前策略
  • 后续如果要补 registry,也可以把 feature_fact 中已有事实反向注册

5. 核心流程图

5.1 落库流程

flowchart TD
    A[media_entity\nentity_type=song] --> B[audio_object\nobject_type=asset]
    B --> C[audio_object\nobject_type=window]
    C --> D1[feature_fact\nfeature_type=fingerprint]
    C --> D2[feature_fact\nfeature_type=embedding]
    A --> E[set_membership]
    B --> E
    C --> E

5.2 查询回溯流程

flowchart LR
    A[query audio] --> B[切片成 query windows]
    B --> C[抽 fingerprint / embedding]
    C --> D[命中 feature_fact]
    D --> E[audio_object window]
    E --> F[audio_object asset]
    F --> G[media_entity song]
    G --> H[输出 song_id + evidence]

5.3 表职责视图

flowchart TB
    M[media_entity\n谁] --> A[audio_object\n哪份音频/哪段切片]
    A --> F[feature_fact\n用了哪个模型/产出什么特征]
    M --> S[set_membership\n属于哪个 reference/eval/hot 集]
    A --> S
    F --> R[召回/匹配/聚合]

6. 每张表的设计意图

6.1 media_entity

用途:

  • 作为 song 主实体表
  • 统一承载 song_id
  • 后续如需要,也允许保留 work/recording type,但当前默认只把 song 当主语义

当前最常用字段:

  • entity_id
  • entity_type
  • biz_key
  • title
  • artist_name
  • metadata_json

设计意图:

  • 不再把 song 相关字段散落到多张表
  • 先把最终归属对象固定下来

6.2 audio_object

用途:

  • 同时管理 assetwindow
  • parent_object_id 建立 asset -> window 父子关系

当前最常用字段:

  • object_type
  • song_id
  • parent_object_id
  • storage_uri
  • checksum
  • duration_ms
  • start_ms
  • end_ms

设计意图:

  • 同一 song 下可有多个音频文件
  • 同一音频文件可切成多个检索窗口
  • 查询命中后可以回查具体 offset

6.3 feature_fact

用途:

  • 统一存 exact lane 和 semantic lane 的特征事实
  • 统一挂模型信息、特征集信息、特征载荷位置

当前最常用字段:

  • feature_type
  • object_id
  • song_id
  • model_name
  • model_version
  • feature_set_name
  • embedding_dim
  • fingerprint_value
  • embedding_uri
  • vector_table_name

设计意图:

  • 避免为不同模型建一堆平行 embedding 表
  • 未来换 MERT / MuQ / 其他 encoder 时只增 feature rows,不改主 schema
  • exact / semantic 两条 lane 可以共用同一归属链

6.4 set_membership

用途:

  • 统一管理 reference_set / eval_set / hot_set
  • member 可以是 song/asset/window/feature

设计意图:

  • reference 范围不硬编码到 song 表里
  • 评测集、热集、灰度集能共用一张关系表

7. 为什么“切片数据 + 模型 + feature”这样分布最合理

切片数据放 audio_object

因为切片本质是音频对象的一种:

  • 它有父 asset
  • 它有 start_ms/end_ms
  • 它需要被回溯和复用

模型信息放 feature_fact

因为模型是“某次特征计算”的属性:

  • 同一个 window 可能被多个模型重复编码
  • 同一个模型也可能有多个版本
  • 模型名和版本应该和 feature 结果绑定,而不是只和 asset 绑定

feature 放 feature_fact

因为 feature 是事实:

  • 某个对象
  • 用某个模型
  • 以某个 feature set
  • 产出某个结果

这正好就是一条事实记录。


8. 第一个阶段如何服务 100w 音频 / 30w 歌曲

建议的落盘顺序

  1. 先写 media_entity(song)
  2. 再写 audio_object(asset)
  3. 再批量切 audio_object(window)
  4. 再按模型批次写 feature_fact
  5. 最后写 set_membership(reference_set/hot_set/eval_set)

为什么这样落

因为这能把“音频对象生命周期”和“模型计算生命周期”解耦:

  • 音频先入库
  • 切片先固定
  • exact lane 可先跑
  • semantic lane 之后补跑也不影响主链

9. Phase-1 推荐策略

9.1 exact lane

  • 默认:ChromaprintMatcher
  • 落到:feature_fact(feature_type='fingerprint')

9.2 semantic lane

  • 当前优先:MERT
  • challenger:MuQ
  • 当前 host 若 runtime 不可用,保留 fallback
  • 落到:feature_fact(feature_type='embedding')

9.3 为什么不是 ECAPA-TDNN 主导

  • ECAPA 更偏 speaker/audio identity 方向
  • 当前目标是版权保护 / song-level ACR
  • MERT / MuQ 更适合作为 song semantic baseline/challenger

10. 当前方案解决的问题

这套 4 表设计,当前主要解决:

  • 同一 song 下多音频文件管理
  • 切片级 evidence 管理
  • fingerprint 与 embedding 统一落库
  • 模型切换时不重构主 schema
  • reference/eval/hot 集统一治理
  • 检索命中后快速回到 song_id

11. 当前不刻意解决的问题

Phase-1 暂不强求:

  • 复杂 work / recording / version 治理
  • 完整权利层图谱
  • 训练/微调闭环
  • 重型 registry-first 体系

这些都可以后续逐步加,但不该反向阻塞当前主链。


12. 相关文档