未记录事实核验 · 状态:维护中

记录仅说明核验时间与维护状态,不保证适用于所有环境;使用前请留意正文中的版本、适用条件与风险提示。

warning 适用边界与维护说明

本文适合建立 Milvus 数据组织、Schema、ANN、检索接口与一致性的概念框架,不是可按顺序执行的完整工程教程。代码片段需分别准备匹配的集合、字段、主键与动态字段设置、索引及加载状态:前述 articles 不包含后续多处查询字段,多向量示例需另建对应集合,HNSW 搜索不能直接使用 IVF 的 nprobe。正文尚未明确部分功能与限制对应的服务端及 PyMilvus 版本,尤其是 Database、ARRAY、自动 ID、JSON 索引与无索引查询;不能将相关绝对表述直接用于当前部署。距离度量表、流程图与实践建议仍不一致,应优先服从模型说明或训练目标,不能仅凭是否归一化选择 L2 或 COSINE。分片数、分区粒度、Segment 大小、IVF 参数比例及速查表推荐值仅供测试参考,不是生产标准。本次仅作全文结构审阅,未作外部事实核验或运行验证。 已取消无法确定目标的可点击引用「#nprobe / ef / ef_construction / m」,保留原提及;Missing anchor: #nprobe / ef / ef_construction / m 已取消无法确定目标的可点击引用「07-Schema设计与数据建模」,保留原提及;Ambiguous link target: 07-Schema设计与数据建模

Milvus 核心概念详解

tip 文档定位

这是一本 Milvus 的概念字典。在你写第一行代码之前,先理解这里的主要概念,有助于减少后续开发中的概念混淆。 每个概念不只给定义,更重要的是解释**"为什么这样设计"**——理解设计意图,才能用好这个工具。

目录


1. 数据组织层级

Milvus 的数据组织从大到小分为四层:Database → Collection → Partition → Segment。理解这四层是一切操作的基础。

%%{init: {"theme":"base","themeVariables":{"fontFamily":"PingFang SC, -apple-system, Source Han Serif SC, serif","fontSize":"16px","background":"#FDFBF5","primaryColor":"#FDFBF5","primaryTextColor":"#2D2A26","primaryBorderColor":"#6E6A60","secondaryColor":"#E8EFE8","secondaryBorderColor":"#8FA890","secondaryTextColor":"#2D2A26","tertiaryColor":"#FDFBF5","tertiaryBorderColor":"#9A9488","tertiaryTextColor":"#6E6A60","lineColor":"#6E6A60","textColor":"#2D2A26","mainBkg":"#FDFBF5","nodeBorder":"#2D5A3D","clusterBkg":"#F3EEDF","clusterBorder":"#9A9488","edgeLabelBackground":"#FDFBF5"},"flowchart":{"htmlLabels":true,"curve":"basis","padding":20,"nodeSpacing":60,"rankSpacing":70,"useMaxWidth":false},"themeCSS":".node rect, .node polygon, .node circle { stroke-width: 1.5px; } .edgePath .path { stroke-width: 1.5px; } .cluster-label .nodeLabel, .cluster-label foreignObject { color: #2D2A26 !important; } .edgeLabel, .edgeLabel foreignObject { color: #2D2A26 !important; background-color: #FDFBF5; } .edgeLabel rect { fill: #FDFBF5; }"}}%%
graph TD
    DB["Database(数据库)<br/>多租户隔离单元"]
    C1["Collection A<br/>(相当于一张表)"]
    C2["Collection B<br/>(相当于另一张表)"]
    P1["Partition: default"]
    P2["Partition: 2024-Q1"]
    P3["Partition: 2024-Q2"]
    SG1["Growing Segment<br/>(写入缓冲区)"]
    SG2["Sealed Segment<br/>(已封存,可建索引)"]
    SG3["Sealed Segment"]

    DB --> C1
    DB --> C2
    C1 --> P1
    C1 --> P2
    C1 --> P3
    P1 --> SG1
    P2 --> SG2
    P2 --> SG3

    style DB fill:#4A90D9,color:#fff,stroke:#2c6fad
    style C1 fill:#7B68EE,color:#fff,stroke:#5a4ec9
    style C2 fill:#7B68EE,color:#fff,stroke:#5a4ec9
    style P1 fill:#48C9B0,color:#fff,stroke:#2eab94
    style P2 fill:#48C9B0,color:#fff,stroke:#2eab94
    style P3 fill:#48C9B0,color:#fff,stroke:#2eab94
    style SG1 fill:#F39C12,color:#fff,stroke:#d68910
    style SG2 fill:#85929E,color:#fff,stroke:#6c7a89
    style SG3 fill:#85929E,color:#fff,stroke:#6c7a89

Database(数据库)

定义:Milvus 2.2 版本起支持多 Database,概念与 MySQL 的 database 完全对应——一个 Milvus 实例可以创建多个相互隔离的 Database。

为什么需要这个设计?

在 2.2 之前,一个 Milvus 实例只有一个全局命名空间,所有 Collection 混在一起。当你需要为不同业务部门、不同客户提供服务时,Collection 的名字会打架,权限也无法隔离。

多 Database 的引入,解决了多租户场景的核心痛点:

场景 没有 Database 时 有 Database 时
电商平台服务多个商家 Collection 命名加前缀区分,混乱 每个商家一个 Database,区分命名空间;权限需配置,计算资源不因此独享
同一公司多个业务线 容易命名冲突,难以权限管控 业务线级别隔离,权限清晰
开发/测试/生产环境 需要部署多套 Milvus 实例 同一实例建三个 Database

操作示例:

from pymilvus import connections, db

# 连接 Milvus
connections.connect(host="localhost", port="19530")

# 创建 database
db.create_database("ecommerce_merchant_001")

# 切换到指定 database
db.using_database("ecommerce_merchant_001")

note 默认 Database

如果不显式创建和切换,所有操作都在名为 default 的 Database 中进行。对于单租户场景,完全不需要关心 Database 层。


Collection(集合)

定义:Collection 是 Milvus 中存储数据的核心结构,类比关系数据库中的 Table(表)。但它和普通表有一个根本区别:Schema 中必须包含至少一个向量字段。

Collection 的物理存储方式:Shard 分片

创建 Collection 时,Milvus 会把它拆分成若干个 Shard(分片),每个 Shard 独立接收写入请求,由不同的 DataNode 处理。这是 Milvus 实现写入水平扩展的核心机制。

%%{init: {"theme":"base","themeVariables":{"fontFamily":"PingFang SC, -apple-system, Source Han Serif SC, serif","fontSize":"16px","background":"#FDFBF5","primaryColor":"#FDFBF5","primaryTextColor":"#2D2A26","primaryBorderColor":"#6E6A60","secondaryColor":"#E8EFE8","secondaryBorderColor":"#8FA890","secondaryTextColor":"#2D2A26","tertiaryColor":"#FDFBF5","tertiaryBorderColor":"#9A9488","tertiaryTextColor":"#6E6A60","lineColor":"#6E6A60","textColor":"#2D2A26","mainBkg":"#FDFBF5","nodeBorder":"#2D5A3D","clusterBkg":"#F3EEDF","clusterBorder":"#9A9488","edgeLabelBackground":"#FDFBF5"},"flowchart":{"htmlLabels":true,"curve":"basis","padding":20,"nodeSpacing":60,"rankSpacing":70,"useMaxWidth":false},"themeCSS":".node rect, .node polygon, .node circle { stroke-width: 1.5px; } .edgePath .path { stroke-width: 1.5px; } .cluster-label .nodeLabel, .cluster-label foreignObject { color: #2D2A26 !important; } .edgeLabel, .edgeLabel foreignObject { color: #2D2A26 !important; background-color: #FDFBF5; } .edgeLabel rect { fill: #FDFBF5; }"}}%%
graph LR
    Client["写入请求"] --> Proxy
    Proxy --> |"Shard 0"| DN1["DataNode 1"]
    Proxy --> |"Shard 1"| DN2["DataNode 2"]
    Proxy --> |"Shard 2"| DN3["DataNode 3"]
    DN1 --> S3_1["对象存储"]
    DN2 --> S3_2["对象存储"]
    DN3 --> S3_3["对象存储"]

    style Client fill:#E74C3C,color:#fff
    style Proxy fill:#3498DB,color:#fff
    style DN1 fill:#2ECC71,color:#fff
    style DN2 fill:#2ECC71,color:#fff
    style DN3 fill:#2ECC71,color:#fff

Shard 数量对写入性能的影响

Shard 数量 适合场景 注意事项
1 可作为低写入压力场景的测试起点,默认值需按版本确认 单 Shard 不等于所有写入串行;吞吐还取决于批量大小、部署资源与服务实现
2 可作为生产压测的候选配置 是否合适需比较写入吞吐、查询开销与资源消耗
4+ 超高写入吞吐需求 Shard 过多会增加查询时的合并开销

warning Shard 数量不可修改

Collection 创建后,Shard 数量无法动态修改。需要在创建前根据业务规模合理规划。如果评估不准确,只能重建 Collection 并迁移数据。

创建 Collection 示例:

from pymilvus import CollectionSchema, FieldSchema, DataType, Collection

# 定义 Schema
fields = [
    FieldSchema(name="id", dtype=DataType.INT64, is_primary=True, auto_id=True),
    FieldSchema(name="text_vector", dtype=DataType.FLOAT_VECTOR, dim=768),
    FieldSchema(name="category", dtype=DataType.VARCHAR, max_length=64),
]
schema = CollectionSchema(fields=fields, description="文章向量库")

# 创建 Collection,指定 Shard 数量
collection = Collection(
    name="articles",
    schema=schema,
    num_shards=2  # 示例配置,生产取值需结合部署与压测确定
)

Partition(分区)

定义:Partition 是在 Collection 内部做的逻辑分区,让你在查询时只扫描部分数据,而不是全量扫描整个 Collection。

Shard vs Partition——最容易搞混的两个概念

这两个概念经常让初学者困惑,一张表格说清楚:

维度 Shard(分片) Partition(分区)
可见性 对用户透明,自动管理 用户显式创建和命名
目的 提升写入并发度 提升查询过滤性能
分割依据 哈希算法自动分配 用户指定 partition_name
修改 创建后不可改 随时增删分区
类比 MySQL 的分库 MySQL 的分表/分区表

tip 一句话理解

Shard 是给写入加速用的,Partition 是给查询加速用的。 写入时数据自动分配到不同 Shard,查询时你告诉 Milvus "我只查这几个 Partition",大幅减少扫描量。

典型分区策略

%%{init: {"theme":"base","themeVariables":{"fontFamily":"PingFang SC, -apple-system, Source Han Serif SC, serif","fontSize":"16px","background":"#FDFBF5","primaryColor":"#FDFBF5","primaryTextColor":"#2D2A26","primaryBorderColor":"#6E6A60","secondaryColor":"#E8EFE8","secondaryBorderColor":"#8FA890","secondaryTextColor":"#2D2A26","tertiaryColor":"#FDFBF5","tertiaryBorderColor":"#9A9488","tertiaryTextColor":"#6E6A60","lineColor":"#6E6A60","textColor":"#2D2A26","mainBkg":"#FDFBF5","nodeBorder":"#2D5A3D","clusterBkg":"#F3EEDF","clusterBorder":"#9A9488","edgeLabelBackground":"#FDFBF5"},"flowchart":{"htmlLabels":true,"curve":"basis","padding":20,"nodeSpacing":60,"rankSpacing":70,"useMaxWidth":false},"themeCSS":".node rect, .node polygon, .node circle { stroke-width: 1.5px; } .edgePath .path { stroke-width: 1.5px; } .cluster-label .nodeLabel, .cluster-label foreignObject { color: #2D2A26 !important; } .edgeLabel, .edgeLabel foreignObject { color: #2D2A26 !important; background-color: #FDFBF5; } .edgeLabel rect { fill: #FDFBF5; }"}}%%
graph TD
    subgraph "按时间分区(推荐场景:日志、文章)"
        C1["Collection: news_vectors"]
        P11["Partition: 2024_Q1"]
        P12["Partition: 2024_Q2"]
        P13["Partition: 2024_Q3"]
        P14["Partition: 2024_Q4"]
        C1 --> P11
        C1 --> P12
        C1 --> P13
        C1 --> P14
    end

    subgraph "按业务类型分区(推荐场景:多品类商品)"
        C2["Collection: product_vectors"]
        P21["Partition: electronics"]
        P22["Partition: clothing"]
        P23["Partition: food"]
        C2 --> P21
        C2 --> P22
        C2 --> P23
    end

    style C1 fill:#7B68EE,color:#fff
    style C2 fill:#7B68EE,color:#fff

分区操作示例:

# 创建分区
collection.create_partition("2024_Q1")
collection.create_partition("2024_Q2")

# 向指定分区写入数据
collection.insert(data, partition_name="2024_Q1")

# 只在指定分区内搜索(性能提升关键!)
results = collection.search(
    data=query_vectors,
    anns_field="text_vector",
    param={"metric_type": "L2", "params": {"nprobe": 16}},
    limit=10,
    partition_names=["2024_Q1", "2024_Q2"]  # 只扫这两个分区
)

分区数量限制与最佳实践

warning 分区数量上限

每个 Collection 默认最多创建 1024 个分区(可通过配置调整,但不建议设置过大)。

最佳实践:

  • 可将 100 个以内作为分区数量的压测候选范围,而非通用上限;需观察元数据管理开销
  • 可将每个分区 百万条以上作为分区粒度的待测假设,而非收益必然超过成本的门槛
  • 如果分类维度超过 100 个,可对比标量过滤(在 Schema 中加字段)与分区方案,按查询模式和测试结果选择

Segment(段)

定义:Segment 是 Milvus 数据管理的最小物理单元。用户感知不到 Segment 的存在,但它是理解 Milvus 性能特性的关键。

Growing Segment vs Sealed Segment

Milvus 中的 Segment 有两种状态,生命周期如下:

%%{init: {"theme":"base","themeVariables":{"fontFamily":"PingFang SC, -apple-system, Source Han Serif SC, serif","fontSize":"16px","background":"#FDFBF5","primaryColor":"#FDFBF5","primaryTextColor":"#2D2A26","primaryBorderColor":"#6E6A60","secondaryColor":"#E8EFE8","secondaryBorderColor":"#8FA890","secondaryTextColor":"#2D2A26","tertiaryColor":"#FDFBF5","tertiaryBorderColor":"#9A9488","tertiaryTextColor":"#6E6A60","lineColor":"#6E6A60","textColor":"#2D2A26","mainBkg":"#FDFBF5","nodeBorder":"#2D5A3D","clusterBkg":"#F3EEDF","clusterBorder":"#9A9488","edgeLabelBackground":"#FDFBF5"},"flowchart":{"htmlLabels":true,"curve":"basis","padding":20,"nodeSpacing":60,"rankSpacing":70,"useMaxWidth":false},"themeCSS":".node rect, .node polygon, .node circle { stroke-width: 1.5px; } .edgePath .path { stroke-width: 1.5px; } .cluster-label .nodeLabel, .cluster-label foreignObject { color: #2D2A26 !important; } .edgeLabel, .edgeLabel foreignObject { color: #2D2A26 !important; background-color: #FDFBF5; } .edgeLabel rect { fill: #FDFBF5; }"}}%%
stateDiagram-v2
    [*] --> Growing: 新数据写入
    Growing --> Sealed: 达到大小上限<br/>(默认 512MB)<br/>或超过时间阈值
    Sealed --> Indexed: 后台异步建索引
    Indexed --> [*]: 查询可用

    note right of Growing
        内存中的写入缓冲区
        支持实时写入和查询
        使用暴力搜索(无索引)
    end note

    note right of Sealed
        已封存,不再接受新数据
        触发异步索引构建任务
        等待索引完成前暴力搜索
    end note
特性 Growing Segment Sealed Segment
状态 活跃,接受写入 已封存,只读
存储位置 QueryNode 内存 对象存储(S3/MinIO)
查询方式 暴力搜索(Brute Force) 使用 ANN 索引
索引 没有索引 异步构建索引
可见性 数据可见性取决于一致性级别与查询读取进度 封存不等于数据消失,可查询性仍受加载状态与一致性设置约束

为什么 Segment 大小有限制(512MB 默认)?

这是一个精心设计的权衡:

  • 太小(如 10MB):Segment 数量爆炸,元数据管理开销剧增,索引构建频繁,整体性能反而下降
  • 太大(如 5GB):单个 Segment 的索引构建耗时过长,占用内存过多,QueryNode 加载困难

此处以 512MB 作为讲解用的配置假设,实际默认值应以部署版本和配置为准。对于高维向量(如 4096 维),可将 1–2GB 作为压测候选值,但不能仅凭维度决定调大;还需观察索引构建耗时、加载内存和查询延迟。

Segment 和索引的关系

important 关键理解

索引是按 Segment 粒度构建的,而不是按 Collection 或 Partition 粒度。

这意味着:

  • 一个 Segment 完成索引构建,查询立即加速——不需要等整个 Collection 的索引都建完
  • Growing Segment 里的数据(刚写入的新数据)始终用暴力搜索,无论你是否创建了索引
  • Growing Segment 可参与查询,但新写入是否立即可见仍取决于一致性级别与读取进度

2. Schema 设计核心概念

Schema 定义了你的数据长什么样。Milvus 的 Schema 设计比关系数据库更灵活,但也有一些独特的约束需要了解。

详细的 Schema 设计最佳实践请参考 07-Schema设计与数据建模。


字段类型全解析

主键字段

每个 Collection 必须有且只有一个主键字段,类型只能是 INT64 或 VARCHAR。

主键类型 auto_id=True auto_id=False
INT64 Milvus 自动生成递增 ID 你自己提供唯一 int64
VARCHAR 不支持自动生成 你自己提供唯一字符串

自动 ID vs 手动指定——如何选择?

%%{init: {"theme":"base","themeVariables":{"fontFamily":"PingFang SC, -apple-system, Source Han Serif SC, serif","fontSize":"16px","background":"#FDFBF5","primaryColor":"#FDFBF5","primaryTextColor":"#2D2A26","primaryBorderColor":"#6E6A60","secondaryColor":"#E8EFE8","secondaryBorderColor":"#8FA890","secondaryTextColor":"#2D2A26","tertiaryColor":"#FDFBF5","tertiaryBorderColor":"#9A9488","tertiaryTextColor":"#6E6A60","lineColor":"#6E6A60","textColor":"#2D2A26","mainBkg":"#FDFBF5","nodeBorder":"#2D5A3D","clusterBkg":"#F3EEDF","clusterBorder":"#9A9488","edgeLabelBackground":"#FDFBF5"},"flowchart":{"htmlLabels":true,"curve":"basis","padding":20,"nodeSpacing":60,"rankSpacing":70,"useMaxWidth":false},"themeCSS":".node rect, .node polygon, .node circle { stroke-width: 1.5px; } .edgePath .path { stroke-width: 1.5px; } .cluster-label .nodeLabel, .cluster-label foreignObject { color: #2D2A26 !important; } .edgeLabel, .edgeLabel foreignObject { color: #2D2A26 !important; background-color: #FDFBF5; } .edgeLabel rect { fill: #FDFBF5; }"}}%%
graph TD
    Q1{"你的业务数据<br/>有自然唯一 ID 吗?"}
    Q2{"ID 是字符串格式<br/>如 UUID、商品编号?"}
    A1["auto_id=True<br/>INT64 主键<br/>让 Milvus 管理 ID"]
    A2["auto_id=False<br/>INT64 主键<br/>传入你的业务 ID"]
    A3["auto_id=False<br/>VARCHAR 主键<br/>传入字符串 ID"]
    WARN["注意:auto_id=True 时<br/>插入后通过返回值获取生成的 ID"]

    Q1 -->|否| A1
    Q1 -->|是| Q2
    Q2 -->|否,是整数| A2
    Q2 -->|是| A3
    A1 --> WARN

    style A1 fill:#2ECC71,color:#fff
    style A2 fill:#3498DB,color:#fff
    style A3 fill:#9B59B6,color:#fff
    style WARN fill:#F39C12,color:#fff

tip 经验法则

  • 如果你的数据来自其他系统(数据库、文档系统),通常有业务 ID,用 auto_id=False 保留原始 ID,方便关联查询
  • 如果 Milvus 是独立的向量存储,没有外部 ID,用 auto_id=True 最简单

向量字段

向量字段是 Milvus 的核心,当前支持五种类型:

向量类型 数据类型 典型维度 使用场景
FLOAT_VECTOR float32,每维 4 字节 128~4096 通用场景,最常用
BINARY_VECTOR bit,每维 1/8 字节 128~2048 图像哈希、文档指纹,极致压缩
FLOAT16_VECTOR float16,每维 2 字节 128~4096 降低存储和内存,精度略降
BFLOAT16_VECTOR bfloat16,每维 2 字节 128~4096 深度学习模型输出,与 float32 精度接近
SPARSE_FLOAT_VECTOR 稀疏格式 不固定 关键词匹配、BM25 混合检索

稀疏向量(SparseFloatVector)是什么?什么时候用?

普通向量(Dense Vector):每个维度都有值,即使是 0 也要存储。

[0.1, 0.0, 0.0, 0.5, 0.0, 0.0, 0.3, ...]  # 10000 维,大部分是 0

稀疏向量(Sparse Vector):只存非零维度的位置和值,用字典表示。

# 只存非零维,大幅节省空间
{42: 0.5, 1891: 0.3, 7654: 0.1}  # 位置: 值

note 稀疏向量的典型用途

稀疏向量主要用于词袋模型(BoW)和 BM25 检索场景:

  • 传统关键词搜索(TF-IDF、BM25)产生的向量天然是稀疏的
  • 维度数 = 词汇表大小(通常 10万+),但每个文档只包含少数词
  • 和 Dense 向量混合使用,实现语义搜索 + 关键词搜索的融合(Hybrid Search)

标量字段

标量字段用于存储非向量的元数据,支持以下类型:

类型 说明 适用场景
INT8 / INT16 / INT32 / INT64 整数,位数越大范围越大 计数、枚举、时间戳
FLOAT / DOUBLE 浮点数 价格、评分、地理坐标
BOOL 布尔值 是否上架、是否审核通过
VARCHAR 变长字符串,需指定 max_length 标题、标签、状态码
JSON JSON 对象 动态属性、扩展信息
ARRAY 同类型元素的数组 标签列表、多值属性

JSON 字段的查询支持

JSON 字段可以直接在过滤表达式中访问嵌套字段:

# Schema 中定义 JSON 字段
FieldSchema(name="metadata", dtype=DataType.JSON)

# 写入时传入 JSON 对象
data = {
    "metadata": {
        "author": "张三",
        "views": 10000,
        "tags": ["AI", "技术"]
    }
}

# 查询时直接访问 JSON 内部字段
results = collection.query(
    expr='metadata["author"] == "张三" and metadata["views"] > 5000'
)

warning JSON 字段的限制

  • JSON 字段不能建标量索引,过滤时需要全量扫描
  • JSON 内的数组字段不支持 ARRAY_CONTAINS 语法(这种需求用 ARRAY 字段类型)
  • 适合存放偶尔查询的扩展属性,频繁过滤的字段请用普通标量字段

ARRAY 字段的特殊用法

ARRAY 字段是 Milvus 2.4+ 新增的类型,存储同类型元素的列表:

# Schema 定义
FieldSchema(
    name="tags",
    dtype=DataType.ARRAY,
    element_type=DataType.VARCHAR,  # 数组元素类型
    max_capacity=10,                # 最大元素数量
    max_length=64                   # 每个元素最大长度(字符串类型才需要)
)

# 查询:标签包含"AI"的文档
results = collection.query(expr='ARRAY_CONTAINS(tags, "AI")')

# 查询:标签数组长度大于 3
results = collection.query(expr='ARRAY_LENGTH(tags) > 3')

Dynamic Field(动态字段)

什么是 Dynamic Schema?为什么需要它?

传统数据库的 Schema 是刚性的——你必须提前定义所有字段,之后新增字段就得 ALTER TABLE,非常痛苦。

Milvus 的动态字段(Dynamic Field)解决了这个问题:允许你在 Schema 中没有显式定义的字段,直接写入数据。

启用方式:

schema = CollectionSchema(
    fields=fields,
    enable_dynamic_field=True  # 开启动态字段
)

启用后能做什么?

# 即使 Schema 里没有定义 "source" 和 "score" 字段
# 也可以直接写入
data = [
    {
        "id": 1,
        "text_vector": [0.1, 0.2, ...],
        "title": "文章标题",          # 在前述 fields 中未定义;启用动态字段后可作为动态字段
        "source": "wechat",           # 动态字段(Schema 中未定义)
        "read_count": 5000,           # 动态字段
        "is_premium": True            # 动态字段
    }
]
collection.insert(data)

# 动态字段也可以参与过滤查询
results = collection.query(expr='source == "wechat" and read_count > 1000')

note 动态字段的存储原理

动态字段在底层被统一存储在一个隐藏的 $meta JSON 字段中。所以动态字段本质上就是 JSON 字段的语法糖——查询性能与 JSON 字段相同,不适合高频过滤。

适合 Dynamic Field 的场景:

  • 爬虫数据,不同网站的元信息字段各不相同
  • 用户生成内容,属性字段随版本迭代不断扩展
  • 快速原型开发,还不确定最终 Schema 长什么样

Multi-Vector(多向量)

一条数据存多个向量的场景

现实中的数据往往有多种模态,单一向量无法完整描述。Milvus 2.4+ 支持在同一个 Collection 中定义多个向量字段:

# 电商商品的 Schema 示例:同时存文本向量和图像向量
fields = [
    FieldSchema(name="product_id", dtype=DataType.INT64, is_primary=True),
    FieldSchema(name="title_vector", dtype=DataType.FLOAT_VECTOR, dim=768),   # 标题文本向量
    FieldSchema(name="image_vector", dtype=DataType.FLOAT_VECTOR, dim=2048),  # 商品图片向量
    FieldSchema(name="product_name", dtype=DataType.VARCHAR, max_length=256),
    FieldSchema(name="price", dtype=DataType.FLOAT),
]

多向量搜索(Multi-Vector Search)

from pymilvus import AnnSearchRequest, RRFRanker

# 定义文本向量搜索请求
text_search = AnnSearchRequest(
    data=[text_query_vector],
    anns_field="title_vector",
    param={"metric_type": "COSINE", "params": {"nprobe": 16}},
    limit=20
)

# 定义图像向量搜索请求
image_search = AnnSearchRequest(
    data=[image_query_vector],
    anns_field="image_vector",
    param={"metric_type": "L2", "params": {"nprobe": 16}},
    limit=20
)

# 使用 RRF 算法融合两路结果
results = collection.hybrid_search(
    reqs=[text_search, image_search],
    rerank=RRFRanker(k=60),  # RRF 融合
    limit=10
)

tip 多向量的典型应用场景

  • 电商搜索:文字搜索 + 以图搜图,双路融合提升召回率
  • 文档检索:Dense 语义向量 + Sparse BM25 向量,结合语义和关键词优势
  • 多模态内容推荐:用户行为向量 + 内容特征向量,综合排序

3. 索引概念概述

note 本节为概述,详细内容请参考 [[【技术与工具】/向量数据库/Milvus/06-索引类型与选型指南]]

这里只建立直觉性理解,不深入数学细节。


什么是 ANN 索引

为什么不能用 B-Tree?

关系数据库中对整数、字符串的索引用 B-Tree,因为这些数据有自然的全序关系——1 < 2 < 3,字符串有字典序。可以高效地做范围查找。

向量不行。一个 768 维的向量,没有"大小"的概念,只有两个向量之间的"距离"或"相似度"。你想问的是:"哪些向量和我的查询向量距离最近?"

暴力解法:把查询向量和库里每一个向量计算距离,排序取前 K 个。这是精确答案,叫 KNN(K-Nearest Neighbors),但计算量是 O(N × dim),在千万数据量下完全不可接受。

ANN(Approximate Nearest Neighbor) 的思路:允许一点精度损失,换取数量级的速度提升。

important ANN 的精度-速度权衡

想象你在一个大城市找"距离你最近的咖啡馆":

  • KNN(精确):挨个量每家咖啡馆和你的距离,一定找到最近的那家,但要花一天时间
  • ANN(近似):先找你所在的区,只在这个区里找,5 分钟出结果,答案可能不是全市最近的,但通常差不多

ANN 索引就是那个"先缩小搜索范围"的机制,牺牲一点召回率(Recall),换取查询速度。

Recall(召回率) 是衡量 ANN 精度的核心指标:

Recall@K = ANN 返回的结果中有多少个是真实 KNN 结果 / K

Recall@10 = 0.95 意味着:10 个结果里有 9.5 个是真正最近的(近似平均),5% 的结果是"次优"的。


距离度量(Metric Type)

距离度量决定了"什么叫相似"。选错了,搜索结果会很差。

Metric Type 公式含义 最佳场景 注意事项
L2(欧氏距离) 两向量在空间中的直线距离 向量未归一化时的通用选择 距离越小越相似,值域 [0, +∞)
IP(内积) 两向量的点积 向量已归一化到单位长度时,等价余弦相似度 值越大越相似
COSINE(余弦相似度) 两向量夹角的余弦 文本语义相似度,Milvus 2.3+ 原生支持 值域 [-1, 1],越大越相似
HAMMING 二进制串不同位的数量 二进制向量(BinaryVector) 仅用于 BinaryVector
JACCARD Jaccard 距离,即 1 减去二进制集合的交并比 文档指纹、相似文档检测 用于 BinaryVector,距离越小越相似

L2 vs IP vs COSINE 的选择逻辑:

%%{init: {"theme":"base","themeVariables":{"fontFamily":"PingFang SC, -apple-system, Source Han Serif SC, serif","fontSize":"16px","background":"#FDFBF5","primaryColor":"#FDFBF5","primaryTextColor":"#2D2A26","primaryBorderColor":"#6E6A60","secondaryColor":"#E8EFE8","secondaryBorderColor":"#8FA890","secondaryTextColor":"#2D2A26","tertiaryColor":"#FDFBF5","tertiaryBorderColor":"#9A9488","tertiaryTextColor":"#6E6A60","lineColor":"#6E6A60","textColor":"#2D2A26","mainBkg":"#FDFBF5","nodeBorder":"#2D5A3D","clusterBkg":"#F3EEDF","clusterBorder":"#9A9488","edgeLabelBackground":"#FDFBF5"},"flowchart":{"htmlLabels":true,"curve":"basis","padding":20,"nodeSpacing":60,"rankSpacing":70,"useMaxWidth":false},"themeCSS":".node rect, .node polygon, .node circle { stroke-width: 1.5px; } .edgePath .path { stroke-width: 1.5px; } .cluster-label .nodeLabel, .cluster-label foreignObject { color: #2D2A26 !important; } .edgeLabel, .edgeLabel foreignObject { color: #2D2A26 !important; background-color: #FDFBF5; } .edgeLabel rect { fill: #FDFBF5; }"}}%%
graph TD
    Q1{"你的向量是否<br/>已经归一化?<br/>(L2 范数 = 1)"}
    Q2{"向量维度和<br/>数值范围稳定吗?"}
    A_COSINE["使用 COSINE<br/>(最直观的语义相似度)"]
    A_IP["使用 IP<br/>(单位向量下与 COSINE 排序等价,性能需实测)"]
    A_L2["使用 L2<br/>(通用距离,不依赖归一化)"]

    Q1 -->|是| Q2
    Q1 -->|否| A_COSINE
    Q2 -->|是,向量稳定| A_IP
    Q2 -->|不确定| A_COSINE

    style A_COSINE fill:#2ECC71,color:#fff
    style A_IP fill:#3498DB,color:#fff
    style A_L2 fill:#E67E22,color:#fff

tip 实践建议

  • 使用 OpenAI、Sentence-BERT 等 Embedding 模型时,应确认具体模型和调用设置是否归一化,不能仅凭模型系列名称判断;单位向量下 IP 与 COSINE 排序等价
  • 优先采用模型说明或训练目标要求的度量;若目标是比较方向且向量非零,可考虑 COSINE
  • 自己训练的模型也应按训练目标选择度量,不能仅因向量未归一化就默认使用 L2

Index 和 Collection 的关系

几个关键认知:

一个向量字段只能有一个索引

不像关系数据库可以对同一列建多个索引(普通索引、唯一索引),Milvus 中每个向量字段只能创建一种 ANN 索引。如果想换索引类型,需要先删除再重建。

没有索引时是 FLAT 暴力搜索

# 如果你没有调用 create_index(),查询仍然可以执行
# 但 Milvus 会对所有 Sealed Segment 做暴力搜索
# 数据量小时无感,百万级以上查询会很慢

索引是异步构建的

索引构建由后台任务执行,但后台执行不等于 SDK 调用立即返回;create_index() 是否等待完成取决于接口及同步、异步调用方式。搜索前需确认索引就绪并完成所需加载。

# 创建索引;调用是否等待完成取决于接口及同步、异步调用方式
collection.create_index(
    field_name="text_vector",
    index_params={"index_type": "HNSW", "metric_type": "COSINE", "params": {"M": 16, "efConstruction": 200}}
)

# 确认索引就绪后加载到内存
collection.load()

# 现在可以使用 ANN 索引的快速搜索了

4. 查询相关概念


这是 Milvus 中最重要的概念区分之一,初学者经常混淆:

操作 方法 输入 输出 本质
Search collection.search() 向量 Top-K 最相似的记录 向量相似度搜索
Query collection.query() 布尔表达式 接口结果窗口及分页设置范围内的匹配记录 标量条件过滤
# Search:给我找最像这个向量的 10 条记录
results = collection.search(
    data=[[0.1, 0.2, ...]],   # 查询向量
    anns_field="text_vector",
    param={"metric_type": "COSINE", "params": {"nprobe": 16}},
    limit=10,                  # Top-K
    output_fields=["title"]
)

# Query:给我找所有 category="技术" 且 views>1000 的记录
results = collection.query(
    expr='category == "技术" and views > 1000',
    output_fields=["id", "title", "views"]
)

warning Query 的注意事项

  • Query 按标量条件查询;即使未显式指定 limit,也不能据此认为一次会返回全部匹配记录,仍需考虑版本、接口结果窗口及分页限制
  • 如果过滤条件选择性不高,可能返回大量数据,导致内存压力
  • Query 不做向量计算,只做标量过滤,速度取决于索引是否支持该字段

Hybrid Search(混合查询)

带标量过滤的向量搜索:与多路 Hybrid Search 区分

大多数真实场景中,纯向量搜索是不够的。你可能需要:"找最相似的文章,但只要发布于 2024 年且作者是张三的"。这是带标量过滤的向量搜索;前文的 hybrid_search 则用于融合多路向量检索结果,两者不应混为同一接口概念。

以下对比预过滤与后过滤的概念流程,不表示它们都是当前示例接口的可选模式;具体支持方式及性能取决于版本、索引与过滤条件:

%%{init: {"theme":"base","themeVariables":{"fontFamily":"PingFang SC, -apple-system, Source Han Serif SC, serif","fontSize":"16px","background":"#FDFBF5","primaryColor":"#FDFBF5","primaryTextColor":"#2D2A26","primaryBorderColor":"#6E6A60","secondaryColor":"#E8EFE8","secondaryBorderColor":"#8FA890","secondaryTextColor":"#2D2A26","tertiaryColor":"#FDFBF5","tertiaryBorderColor":"#9A9488","tertiaryTextColor":"#6E6A60","lineColor":"#6E6A60","textColor":"#2D2A26","mainBkg":"#FDFBF5","nodeBorder":"#2D5A3D","clusterBkg":"#F3EEDF","clusterBorder":"#9A9488","edgeLabelBackground":"#FDFBF5"},"flowchart":{"htmlLabels":true,"curve":"basis","padding":20,"nodeSpacing":60,"rankSpacing":70,"useMaxWidth":false},"themeCSS":".node rect, .node polygon, .node circle { stroke-width: 1.5px; } .edgePath .path { stroke-width: 1.5px; } .cluster-label .nodeLabel, .cluster-label foreignObject { color: #2D2A26 !important; } .edgeLabel, .edgeLabel foreignObject { color: #2D2A26 !important; background-color: #FDFBF5; } .edgeLabel rect { fill: #FDFBF5; }"}}%%
graph LR
    subgraph "Pre-filtering(推荐)"
        PF_Q["查询向量"] --> PF_F["先过滤标量<br/>找到候选集"]
        PF_F --> PF_S["在候选集中<br/>做向量搜索"]
        PF_S --> PF_R["Top-K 结果"]
    end

    subgraph "Post-filtering"
        POST_Q["查询向量"] --> POST_S["先做全量<br/>向量搜索"]
        POST_S --> POST_F["再过滤标量"]
        POST_F --> POST_R["过滤后结果<br/>(数量可能 < K)"]
    end

    style PF_F fill:#2ECC71,color:#fff
    style POST_S fill:#E74C3C,color:#fff

Milvus 的实际行为:

Milvus 默认使用 pre-filtering(称为 bitset 过滤),在执行 ANN 搜索时同时应用标量过滤条件:

# 标量过滤直接写在 search 的 expr 参数中
results = collection.search(
    data=[query_vector],
    anns_field="text_vector",
    param={"metric_type": "COSINE", "params": {"nprobe": 32}},
    limit=10,
    expr='publish_year == 2024 and author == "张三"',  # 与向量搜索同时执行
    output_fields=["title", "author", "publish_year"]
)

warning Pre-filtering 的陷阱

当过滤条件极其严格(过滤后剩余数据很少)时,pre-filtering 可能导致"找不够 K 个结果"的问题。

例如:全库 100 万条,过滤后只剩 50 条,请求 Top-10 的目标是在这 50 条中找最相似的 10 条;仅凭候选集缩小不能判断结果不足或质量不高,还需区分候选数量不足、ANN 召回不足与业务相关性不足。

若是 ANN 召回不足,可按索引类型测试提高 IVF 的 nprobe 或 HNSW 的 ef;若满足条件的记录本就少于 K,调参不会增加合格记录。AUTOINDEX 是否适用需结合部署能力与测试结果判断。


Consistency Level

Milvus 是分布式系统,写入和读取可能在不同节点上,因此存在数据一致性的问题。

Milvus 提供四个一致性级别,对应 CAP 定理中 C(Consistency)和 A(Availability)的不同权衡:

级别 含义 适用场景 性能开销
Strong 写入后立即可查,严格一致 金融交易、需要精确实时性的场景 最高
Bounded Staleness 允许最多 X 秒的延迟 大多数业务场景的推荐值 中等
Session 同一个 session 内写入立即可查,跨 session 可能延迟 用户个性化推荐,用户刚操作的数据要立即反映 较低
Eventually 最终一致,延迟不确定 批量数据分析,对实时性要求低 最低
# 在 search 时指定一致性级别
results = collection.search(
    data=[query_vector],
    anns_field="text_vector",
    param={"metric_type": "COSINE", "params": {"nprobe": 16}},
    limit=10,
    consistency_level="Bounded"  # 推荐生产环境使用
)

note 更多架构细节

Consistency Level 的底层实现(时间戳机制、TSO 全局时钟)详见 02-Milvus架构深度解析。


Alias(别名)

定义:为 Collection 设置一个别名,应用程序通过别名访问,而不是直接使用 Collection 名称。

为什么需要 Alias?

想象你需要重建索引(比如切换到新的索引类型):

  • 没有 Alias:若坚持让新 Collection 沿用旧名称,可能需要停服重建;也可使用不同集合名称,并通过应用配置、路由和数据同步方案迁移,不是只能先删除旧集合。
  • 有 Alias:新旧 Collection 可以并存;在新集合数据同步、索引构建和加载完成,并妥善处理写入与在途请求后,可切换 Alias 指向,以减少切换中断,但 Alias 本身不保证零停机。
%%{init: {"theme":"base","themeVariables":{"fontFamily":"PingFang SC, -apple-system, Source Han Serif SC, serif","fontSize":"16px","background":"#FDFBF5","primaryColor":"#FDFBF5","primaryTextColor":"#2D2A26","primaryBorderColor":"#6E6A60","secondaryColor":"#E8EFE8","secondaryBorderColor":"#8FA890","secondaryTextColor":"#2D2A26","tertiaryColor":"#FDFBF5","tertiaryBorderColor":"#9A9488","tertiaryTextColor":"#6E6A60","lineColor":"#6E6A60","textColor":"#2D2A26","mainBkg":"#FDFBF5","nodeBorder":"#2D5A3D","clusterBkg":"#F3EEDF","clusterBorder":"#9A9488","edgeLabelBackground":"#FDFBF5"},"flowchart":{"htmlLabels":true,"curve":"basis","padding":20,"nodeSpacing":60,"rankSpacing":70,"useMaxWidth":false},"themeCSS":".node rect, .node polygon, .node circle { stroke-width: 1.5px; } .edgePath .path { stroke-width: 1.5px; } .cluster-label .nodeLabel, .cluster-label foreignObject { color: #2D2A26 !important; } .edgeLabel, .edgeLabel foreignObject { color: #2D2A26 !important; background-color: #FDFBF5; } .edgeLabel rect { fill: #FDFBF5; }"}}%%
sequenceDiagram
    participant App as 应用程序
    participant Alias as Alias: articles_prod
    participant Old as articles_v1 (旧索引)
    participant New as articles_v2 (新索引,后台构建)

    App->>Alias: search(...)
    Alias->>Old: 转发请求(当前指向 v1)
    Old-->>App: 返回结果

    Note over New: 后台完成新索引构建

    App->>Alias: search(...) 切换 Alias
    Alias->>New: 转发请求(现在指向 v2)
    New-->>App: 返回结果(中断程度取决于同步、加载及请求切换方案)

操作示例:

from pymilvus import utility

# 创建 alias
utility.create_alias(collection_name="articles_v1", alias="articles_prod")

# 应用程序使用 alias 访问
collection = Collection("articles_prod")  # 实际访问 articles_v1

# 后台建好 articles_v2 后,一键切换
utility.alter_alias(collection_name="articles_v2", alias="articles_prod")

# 现在 "articles_prod" 指向 articles_v2,应用无需任何修改

tip Alias 的其他使用场景

  • A/B 测试:两个不同索引配置的 Collection,通过流量控制分别访问,对比效果
  • 灰度发布:新模型产出的向量存入新 Collection,逐步切量
  • 环境隔离:同一套代码,通过 Alias 区分测试和生产数据

5. 关键参数概念


nprobe / ef / ef_construction / m

这些参数初次见到容易令人困惑,因为它们是不同索引类型的参数,混在一起使用。下面把它们分类说清楚:

%%{init: {"theme":"base","themeVariables":{"fontFamily":"PingFang SC, -apple-system, Source Han Serif SC, serif","fontSize":"16px","background":"#FDFBF5","primaryColor":"#FDFBF5","primaryTextColor":"#2D2A26","primaryBorderColor":"#6E6A60","secondaryColor":"#E8EFE8","secondaryBorderColor":"#8FA890","secondaryTextColor":"#2D2A26","tertiaryColor":"#FDFBF5","tertiaryBorderColor":"#9A9488","tertiaryTextColor":"#6E6A60","lineColor":"#6E6A60","textColor":"#2D2A26","mainBkg":"#FDFBF5","nodeBorder":"#2D5A3D","clusterBkg":"#F3EEDF","clusterBorder":"#9A9488","edgeLabelBackground":"#FDFBF5"},"flowchart":{"htmlLabels":true,"curve":"basis","padding":20,"nodeSpacing":60,"rankSpacing":70,"useMaxWidth":false},"themeCSS":".node rect, .node polygon, .node circle { stroke-width: 1.5px; } .edgePath .path { stroke-width: 1.5px; } .cluster-label .nodeLabel, .cluster-label foreignObject { color: #2D2A26 !important; } .edgeLabel, .edgeLabel foreignObject { color: #2D2A26 !important; background-color: #FDFBF5; } .edgeLabel rect { fill: #FDFBF5; }"}}%%
graph TD
    subgraph "索引构建阶段(创建索引时设置)"
        EC["efConstruction<br/>HNSW 索引构建时的候选集大小"]
        M["M<br/>HNSW 每个节点的最大连接数"]
        NLIST["nlist<br/>IVF 系列索引的簇数量"]
    end

    subgraph "查询阶段(每次 search 时设置)"
        NP["nprobe<br/>IVF 系列查询时扫描的簇数量"]
        EF["ef<br/>HNSW 查询时的动态候选集大小"]
    end

    style EC fill:#9B59B6,color:#fff
    style M fill:#9B59B6,color:#fff
    style NLIST fill:#9B59B6,color:#fff
    style NP fill:#E67E22,color:#fff
    style EF fill:#E67E22,color:#fff

IVF 系列索引的参数(IVFFLAT、IVFPQ、IVFSQ8)

参数 在哪里设置 直觉理解 范围建议
nlist create_index 把数据空间划分成多少个"区域"(类似城市的区) 数据量/1000 ~ 数据量/100
nprobe search param 查询时检查多少个"区域" 1~nlist,推荐 nlist/8~nlist/4

HNSW 索引的参数

参数 在哪里设置 直觉理解 范围建议
M create_index 图中每个节点最多连几条边(连接密度) 4~64,通常 16
efConstruction create_index 的 HNSW params 建图时为每个节点找多少候选邻居 示例取 200,支持范围与实际取值需结合版本及压测确定
ef search param 查询时维护的候选集大小 必须 >= K,通常 64~512

用比喻理解这些参数:

tip 地图搜索比喻

把向量数据库比作一张城市地图,ANN 搜索是找离你最近的餐厅:

IVF 系列:

  • nlist = 城市被划分成多少个区(区越多,每区越小,越精准)
  • nprobe = 查找时去几个区里找(去的区越多,越准确,但越慢)

HNSW:

  • M = 地图的道路密度(路越多,导航越灵活,但地图越大)
  • ef_construction = 建地图时每个地点连接多少条路的候选数(越大地图质量越高,但建图越慢)
  • ef = 导航时考虑的备选路线数(越多结果越准,但越慢)

精度 vs 速度的调节规律:

  • 提高 nprobe(IVF)或 ef(HNSW)→ 精度提升,速度下降
  • 降低 nprobe(IVF)或 ef(HNSW)→ 速度提升,精度下降
  • M 和 ef_construction 影响索引质量,设置好了就不用改,查询时不再调整

Top-K / Limit / Offset

三个参数的区别

参数 含义 适用方法
limit 返回多少条结果 search 和 query 都有
Top-K search 中 limit 的语义:找最相似的前 K 条 search
offset 跳过前 N 条,用于翻页 search 和 query 都有

分页(Pagination)的实现

# 第 1 页:前 10 条
page1 = collection.search(
    data=[query_vector],
    anns_field="text_vector",
    param={"metric_type": "COSINE", "params": {"nprobe": 16}},
    limit=10,
    offset=0
)

# 第 2 页:第 11-20 条
page2 = collection.search(
    data=[query_vector],
    anns_field="text_vector",
    param={"metric_type": "COSINE", "params": {"nprobe": 16}},
    limit=10,
    offset=10  # 跳过前 10 条
)

# 第 N 页
page_n = collection.search(
    ...,
    limit=page_size,
    offset=(page_number - 1) * page_size
)

warning Offset 分页的性能限制

Milvus 的 offset 分页有硬性限制:limit + offset 的值不能超过 16384。

也就是说,你最多能翻到第 16384 / page_size 页。这是所述接口的结果窗口限制,不是所有 ANN 算法的天然限制;具体边界需结合使用版本确认。

如果业务需要深度分页或全量导出,应选择使用版本支持的迭代或分页接口,并确认其排序语义与导出目标;单次增大 limit 不能绕过同一结果窗口上限。

一个常见误区:

# 错误理解:以为每次 search 独立,offset 是相对于这次搜索结果
# 这样分页才是正确的

# 正确理解:
# search(limit=10, offset=0)  → 最相似的 1~10 名
# search(limit=10, offset=10) → 最相似的 11~20 名
# 每次请求都会重新计算,offset 是跳过的数量

总结:概念速查表

概念 一句话定义 关键数字/限制
Database 多租户隔离单元(Milvus 2.2+) 无硬性数量限制
Collection 向量数据的核心存储表,必须有向量字段 Shard 数创建后不可改
Shard 写入分片,可支持写入并发扩展 默认值按版本确认;2 可作为压测候选配置
Partition 逻辑查询分区,用户控制 默认上限 1024
Segment 数据管理最小单元 512MB 为本文配置假设,封存条件按版本与配置确认
Growing Segment 活跃写入缓冲,暴力搜索 内存中
Sealed Segment 只读,异步建索引 对象存储
Dynamic Field 无需预定义 Schema 的弹性字段 底层是 JSON,查询较慢
FLOAT_VECTOR 最通用的向量类型 维度上限 32768
SPARSE_FLOAT_VECTOR 稀疏向量,用于关键词检索 维度不固定
ANN 索引 通过近似搜索权衡召回率与查询开销 可将 Recall@K ≥ 95% 作为示例验收目标,不代表默认保证
L2 欧氏距离,通用距离度量 越小越相似
COSINE 余弦相似度,语义相似首选 越大越相似,[-1,1]
Search 向量相似度搜索,返回 Top-K limit+offset <= 16384
Query 标量条件过滤,返回接口限制及分页设置范围内的匹配记录 注意结果窗口限制和大量返回的内存压力
Hybrid Search 融合多路向量检索结果 与单路 search 加标量过滤区分
Alias Collection 的别名 配合数据同步、加载与切换方案减少服务中断
nprobe IVF 查询时扫描的簇数 越大越准,越慢
ef HNSW 查询候选集大小 必须 >= limit
Consistency Level 读一致性保证级别 推荐 Bounded

延伸阅读

主题 文档
Milvus 内部架构,如何实现一致性和高可用 02-Milvus架构深度解析
各种 ANN 索引类型的详细对比和选型建议 06-索引类型与选型指南
Schema 设计模式,多种业务场景的建模实战 07-Schema设计与数据建模

#向量数据库 #Milvus #核心概念 #ANN #Schema设计 #数据组织