RAG 02 多模态检索 多维主键

上一篇文章讲到了多维主键,这期就来详细讲一讲。 比如我要查找一个视频里面前30s的内容,里面有视频,图片,文字,图表,音频。
如何设计主键,让一次查询就可以知道所有的东西

多维主键是什么?

"多维主键"并不是一个严格的数据库术语,而是工程口语化的叫法 ,用来描述把多个业务维度 同时编码进一个可排序、可前缀匹配、可范围扫描 的键(或主键),从而用"一次索引查找"就能完成多条件过滤、排序和路由。

简单一句话:把原本需要多个 WHERE 子句的过滤条件,压缩进一条键的前缀里


1. 传统视角 vs 多维主键视角

场景 传统做法 多维主键做法
查询最近 1 小时的文本 WHERE ts >= now-1h AND modality='txt' 键前缀 1722843000000:txt: 直接范围扫描
路由到热库 由业务代码或中间件判断 键前缀 202531: 自动落周库
保证唯一性 额外建联合唯一索引 键里自带 scene_hash,天然唯一

2. 一条"多维主键"长什么样?

css 复制代码
{时间戳}:{模态}:{语义ID}:{随机salt}
1722843000000:txt:c8f9e:7b3
  • 时间戳 → 排序、冷热分层
  • 模态 → 过滤、路由到表/分片
  • 语义ID → 业务主键,保证唯一
  • 随机salt → 防止热点写(可选)

3. 为什么叫"多维"?

因为它把时间维、模态维、业务维 等多个查询条件物理地打平到一条键的字节顺序里,数据库只需一次 B+ 树 / LSM-Tree 的前缀匹配就能完成原本需要多条索引才能做的事。

它们底层仍然是一条普通主键,但业务层把"多维"压缩进去,所以口语上就叫"多维主键"。

路线一:Elasticsearch / OpenSearch(最轻量、最通用)

  • 键格式
    _id = {ts_ms}:{modality}:{scene_hash}
    例:1722843000000:txt:c8f9e
  • 优势
    • 天然支持前缀、范围、多条件复合查询。
    • 分片(shard)即天然"路由",一条 DSL 即可同时命中"最近 1 小时 + txt|img"。
    • 冷热分层用 Index Lifecycle Management (ILM) 自动迁移到冷节点。
  • 开源 & 工业级
    • ES/OpenSearch 8.x 单集群 PB 级、腾讯/阿里/滴滴/美团均在用。
  • 注意
    • 单分片建议 ≤ 50 GB;索引按周滚动即可保证 100 GB 上限。

路线二:Cassandra / ScyllaDB(高吞吐、去中心化)

  • 键设计(PRIMARY KEY)

    java 复制代码
    PRIMARY KEY ((year_month), ts_ms, modality, scene_hash)
    • 分区键 year_month 保证时间切库
    • 聚簇列 ts_ms, modality 保证时间+模态顺序扫描
    • scene_hash 保证唯一性。
  • 优势

    • 线性扩展、无单点、写吞吐百万级 QPS。
    • 二级索引 / SASI 索引可额外按 modality 过滤。
  • 开源 & 工业级

    • Apple iCloud、Netflix、Instagram 均跑在 Cassandra;ScyllaDB 兼容协议,C++ 重写后性能 ×10。
  • 注意

    • 必须避免分区热点,可把 year_month 再细粒度化成 year_month_day

路线三:TiDB / CockroachDB(兼容 MySQL 协议,HTAP)

  • 键设计

    java 复制代码
    CLUSTERED INDEX (ts_ms, modality, scene_hash)
    • 聚簇索引天然按前缀排序 ,范围扫描 ts_ms BETWEEN ... 走索引不回表。

    • 二级分区:

      sql 复制代码
      PARTITION BY RANGE (ts_ms) (
        PARTITION p_hot VALUES LESS THAN (unix_timestamp('2024-11-01')),
        PARTITION p_cold VALUES LESS THAN MAXVALUE
      )
  • 优势

    • MySQL 语义零成本迁移;支持在线扩缩容;冷热分区自动搬迁。
  • 开源 & 工业级

    • TiDB 在知乎、美团、Shopee 已跑数百节点;CockroachDB 在 Comcast、Bose 落地。

总结工业界怎么用?

  • Elasticsearch_id = 1722843000000:txt:c8f9e
  • CassandraPRIMARY KEY ((ym), ts, modality, sid)
  • TiDBCLUSTERED INDEX(ts, modality, sid)
  • 搜索/日志/快速 PoCElasticsearch/OpenSearch
  • 高并发写、去中心化、跨地域Cassandra/ScyllaDB
  • 在线交易+分析混合、MySQL 生态TiDB/CockroachDB

以上三种均已开源,可直接落地。

多模态RAG,如何设计多维主键?

向量存储的条件

  • 文本部分用 Sentence-BERT 得到 768 维向量 e_txt。
  • 图像部分用 CLIP 得到 768 维向量 e_img(三张图取平均)。
  • 表格部分按 markdown
  • 文本同样用 Sentence-BERT 得到 e_tbl。
  • 音频无独立向量,直接忽略或并入文本。
  • 将三向量拼接后降维到 768 维,得到最终向量 e_slot。
  • 把 (doc_id, e_slot, 完整 JSON 文档) 插入向量数据库的同一张表。

下面给出一种**面向向量数据库(Milvus / Qdrant / Weaviate / pgvector 均可)**的主键设计,使得 "查 30 秒窗口内所有模态" 仍然只需 一次范围查询 就能召回 e_slot 向量 以及 原始 JSON


1 一行记录的主键(主键 = 逻辑时间轴)

text 复制代码
{video_id}:{chunk_start_ms}:{modality_flag}:{uuid}
  • video_id ------ 8~12 字节定长,保证同一视频连续存储
  • chunk_start_ms ------ 该 30 s 窗口的起始毫秒,左补零 10 位,字典序即时间序
  • modality_flag ------ 1 字符:S 代表"slot",表示这一行是 融合后向量
  • uuid ------ 4~6 字节随机,避免同一毫秒多行冲突

例子:vid123abc:000000000:S:c8f9e


2 表的 schema(以 Milvus 为例)

字段名 类型 说明
id VARCHAR(64) 主键,格式如上
video_id VARCHAR(12) 冗余字段,便于过滤
chunk_start_ms INT64 起始毫秒
e_slot FLOAT_VECTOR(768) 降维后的统一向量
raw_json JSON / VARCHAR(MAX) 原始文档,含文本、图像 url、表格 markdown

3 插入流程(离线预处理)

python 复制代码
# 伪代码
for seg in video.chunks(30_000):           # 30 s 步长
    e_txt  = sbert(seg.texts)
    e_img  = clip(seg.images).mean(axis=0)
    e_tbl  = sbert(seg.tables_md)
    e_slot = pca( np.hstack([e_txt, e_img, e_tbl]) )   # 降到 768 维

    row = {
        "id"             : f"{video_id}:{seg.start:010d}:S:{uuid4().hex[:6]}",
        "video_id"       : video_id,
        "chunk_start_ms" : seg.start,
        "e_slot"         : e_slot,
        "raw_json"       : seg.to_json()
    }
    milvus.insert("video_slots", row)

4 一次查询拉回 30 s 窗口

python 复制代码
# 想查视频 vid123abc 的 30--60 s 段
start = 30_000
end   = 60_000

expr = f'video_id == "vid123abc" and 30000 <= chunk_start_ms < 60000'

results = milvus.query(
    collection="video_slots",
    filter=expr,
    output_fields=["raw_json", "e_slot"]
)

# 结果即包含 e_slot 向量 + 完整 JSON

一句话总结

30 秒窗口 编码成 连续字典序前缀vid123abc:000030000:Svid123abc:000060000:S),

向量数据库里 一次范围过滤 就能拿回 融合向量与原始多模态 JSON

相关推荐
爱编程的鱼18 分钟前
计算机(电脑)是什么?零基础硬件软件详解
java·开发语言·算法·c#·电脑·集合
洛生&25 分钟前
【abc417】E - A Path in A Dictionary
算法
亮亮爱刷题33 分钟前
算法提升之数学(快速幂+逆元求法)
算法
恣艺1 小时前
LeetCode 124:二叉树中的最大路径和
算法·leetcode·职场和发展
weisian1511 小时前
力扣经典算法篇-42-矩阵置零(辅助数组标记法,使用两个标记变量)
算法·leetcode·矩阵
恣艺1 小时前
LeetCode 123:买卖股票的最佳时机 III
算法·leetcode·职场和发展
geoyster2 小时前
20250802-102508010-CP
算法
Q741_1472 小时前
优选算法 力扣 202.快乐数 快慢双指针 解决带环问题 C++解题思路 每日一题
c++·算法·leetcode·快慢双指针·环形问题
DONG9132 小时前
Python 中的可迭代、迭代器与生成器——从协议到实现再到最佳实践
开发语言·汇编·数据结构·python·算法·青少年编程·排序算法