2、向量数据库基础回顾:主流向量数据库的架构与数据模型

聊版本管理之前,咱们得先把地基打牢。说白了,你要是不了解向量数据库内部是怎么存数据、怎么组织数据的,那后面谈版本回滚就是空中楼阁。

我个人习惯把向量数据库比作一个「超级索引工厂」。它不光要存原始向量,还得维护一堆倒排索引、量化索引、图索引。版本管理,本质上就是在管理这些索引的快照。

今天咱们重点看三个主流选手:Milvus、Qdrant 和 Weaviate。我会从架构和数据模型两个角度拆开讲。

2.1 核心概念:向量、标量、集合与分段

先统一一下术语。不管哪个数据库,都绕不开这几个概念:

  • 向量(Vector):浮点数数组,比如 [0.12, 0.45, 0.78, ...]。维度从几十到几千不等。
  • 标量(Scalar):附加的元数据,比如商品ID、价格、时间戳。用来做过滤。
  • 集合(Collection):相当于关系数据库里的「表」。一个集合包含一组向量和对应的标量字段。
  • 分段(Segment / Shard):集合内部的数据分片。每个分段独立构建索引,独立存储。

关键认知:版本管理的粒度,通常落在「分段」级别。你回滚一个集合,本质上是把某些分段替换成历史快照。

嗯,这里要注意:不同数据库对「分段」的叫法不一样。Milvus 叫 segment,Qdrant 叫 point 组,Weaviate 叫 shard。但底层逻辑是相通的。

2.2 Milvus:云原生架构与日志代理

Milvus 是我最早接触的生产级向量数据库。它的架构设计非常「云原生」——说白了就是把存储和计算拆开了。

架构概览

Milvus 2.x 的架构分四层:

  1. 接入层(Proxy):处理客户端请求,做路由和限流。
  2. 协调层(Coordinator):管理元数据、任务调度、索引构建。
  3. 工作节点(Worker Node):实际执行查询和索引构建的节点。
  4. 存储层(Object Storage + Meta Store):向量数据存对象存储(如 MinIO、S3),元数据存 etcd 或 MySQL。

我记得第一次看这个架构时,第一反应是「这不就是微服务套壳吗?」但用久了才发现,这种解耦对版本管理特别友好——因为你可以单独对某个 segment 做快照,而不影响整个集群。

数据模型

Milvus 的数据模型以 Collection 为核心:

  • 每个 Collection 有一个 Schema,定义向量字段和标量字段。
  • 向量字段必须指定维度(dim)和距离度量(metric type)。
  • 标量字段支持 INT、FLOAT、VARCHAR、JSON 等类型。
  • 数据写入时先进入 log broker(基于 Pulsar),然后异步刷到对象存储。
# Milvus Collection Schema 示例
from pymilvus import CollectionSchema, FieldSchema, DataType

fields = [
    FieldSchema(name="id", dtype=DataType.INT64, is_primary=True),
    FieldSchema(name="embedding", dtype=DataType.FLOAT_VECTOR, dim=768),
    FieldSchema(name="price", dtype=DataType.FLOAT),
    FieldSchema(name="category", dtype=DataType.VARCHAR, max_length=64)
]
schema = CollectionSchema(fields, description="商品向量集合")

我的经验:Milvus 的 log broker 机制是版本管理的「双刃剑」。好处是数据持久化有保障,坏处是回滚时需要处理 Pulsar 里的未消费消息。我曾经因为没清干净 log,导致回滚后数据不一致——嗯,后来我加了个「暂停写入」步骤才解决。

2.3 Qdrant:Rust 实现与点存储模型

Qdrant 是后起之秀,用 Rust 写的,性能很猛。它的架构比 Milvus 轻量很多。

架构概览

Qdrant 的架构相对简洁:

  • 单进程模型:一个 Qdrant 实例就是一个进程,内置 gRPC 和 REST API。
  • 分段存储:每个 Collection 分成多个 Segment,每个 Segment 独立维护 HNSW 索引。
  • WAL(Write-Ahead Log):所有写入先写 WAL,再刷到内存索引。
  • 快照机制:支持对 Collection 做全量快照,也支持增量快照。

说白了,Qdrant 的设计哲学就是「简单粗暴」。没有复杂的协调层,没有消息队列,一个二进制文件跑起来就能用。

数据模型

Qdrant 的数据模型以 Point 为单位:

  • 每个 Point 包含一个 ID、一个 向量、以及可选的 Payload(标量数据)。
  • Payload 支持 JSON 格式,可以嵌套。
  • Collection 可以设置 向量配置(维度、距离函数)和 索引配置(HNSW 参数)。
// Qdrant Point 结构(Rust 伪代码)
struct Point {
    id: PointId,          // 可以是 uint64 或 UUID
    vector: Vec<f32>,     // 浮点数向量
    payload: HashMap<String, Value>,  // 任意 JSON 数据
}

避坑指南:Qdrant 的 WAL 默认不自动清理。如果你频繁做版本回滚,WAL 文件会越积越大。我曾经在生产环境遇到过 WAL 撑爆磁盘的情况——从那以后,我养成了定期执行 wal_cleanup 的习惯。

2.4 Weaviate:图式架构与模块化设计

Weaviate 的定位比较特殊——它更像一个「AI 原生数据库」。内置了向量化模块、推理模块,甚至能直接调用 的 Embedding API。

架构概览

Weaviate 的架构有几个特点:

  • 模块化:向量化、推理、存储都是独立模块,可以按需加载。
  • 图式数据模型:数据以 Object 形式存储,Object 之间可以建立 Cross-Reference(交叉引用)。
  • 倒排索引 + 向量索引:同时支持 BM25 文本搜索和 ANN 向量搜索。
  • 分片与复制:每个 Class(相当于 Collection)可以配置分片数和复制因子。

我个人觉得 Weaviate 最亮眼的设计是「图式关联」。你想想看,如果你存的是知识图谱数据,Object 之间的引用关系天然就是图结构,查询时可以直接沿着引用链做向量搜索。

数据模型

Weaviate 的数据模型以 Class 和 Object 为核心:

  • Class:定义数据模式,包括属性(Property)和向量化配置。
  • Object:具体的数据实例,包含属性值和向量。
  • Cross-Reference:Object 之间的引用关系,类似外键但更灵活。
# Weaviate Class 定义示例(GraphQL 风格)
{
  "class": "Product",
  "properties": [
    { "name": "name", "dataType": ["text"] },
    { "name": "price", "dataType": ["number"] },
    { "name": "category", "dataType": ["text"] },
    { "name": "relatedProducts", "dataType": ["Product"] }  // 交叉引用
  ],
  "vectorizer": "text2vec-"  // 自动向量化
}

我的建议:如果你做版本管理时涉及 Cross-Reference,一定要小心。回滚一个 Object 可能导致引用断裂。我一般会先做「引用完整性检查」,再执行回滚操作。

2.5 三大数据库对比总结

为了方便你对比,我整理了一张表:

特性 Milvus Qdrant Weaviate
开发语言 Go + C++ Rust Go
架构风格 分布式微服务 单进程 + 分片 模块化 + 分片
数据单元 Collection → Segment Collection → Point Class → Object
标量存储 Schema 定义字段 Payload(JSON) Property(类型化)
索引类型 IVF_FLAT, HNSW, DiskANN HNSW HNSW + 倒排索引
快照方式 Segment 级别快照 Collection 全量/增量快照 Class 级别快照
版本管理友好度 ⭐⭐⭐⭐(日志代理复杂) ⭐⭐⭐⭐⭐(WAL 简单) ⭐⭐⭐(引用关系复杂)

2.6 核心架构对比图

下面这张 SVG 图展示了三个数据库的架构差异,方便你直观理解:

三大向量数据库架构对比 三大向量数据库架构对比 Milvus Proxy(接入层) Coordinator(协调层) Worker Node(工作节点) Log Broker (Pulsar) Object Storage (MinIO/S3) Meta Store (etcd/MySQL) 特点:分布式微服务 数据单元:Segment 版本管理:日志代理复杂 Qdrant gRPC / REST API Segment Manager WAL (Write-Ahead Log) HNSW Index (内存) Snapshot (磁盘) 特点:单进程 + 分片 数据单元:Point 版本管理:WAL 简单 Weaviate REST / GraphQL API Module System Object Store Inverted Index (BM25) HNSW Vector Index Cross-Reference 特点:模块化 + 图式 数据单元:Object 版本管理:引用关系复杂

2.7 小结:选型与版本管理的关联

看到这里,你可能会问:「那我到底该选哪个?」

我的建议是:

  • 如果你需要强一致性和复杂标量过滤,Milvus 的 Schema 机制更合适。但要做好处理 Log Broker 延迟的心理准备。
  • 如果你追求极致性能和简单运维,Qdrant 的 Rust 实现和 WAL 机制会让你省心很多。版本回滚也最直接。
  • 如果你做的是知识图谱或多模态搜索,Weaviate 的图式模型和内置向量化模块能减少很多开发工作。但回滚时要格外注意引用完整性。

嗯,其实没有完美的数据库。关键是你得清楚自己的场景,然后接受它的 trade-off。后面几章我们会深入每个数据库的版本管理细节,到时候你会看到更多实战中的坑和技巧。