向量数据库 Milvus

向量数据库 Milvus

参考:https://blog.csdn.net/qq_58602552/article/details/155983178

1. 简介

Milvus 于 2019 年创建,其目标只有一个:存储、索引和管理由深度神经网络和其他机器学习 (ML) 模型生成的大量嵌入向量。它具备高可用、高性能、易拓展的特点,用于海量向量数据的实时召回。

作为专门为处理输入向量查询而设计的数据库,它能够对万亿规模的向量进行索引。与现有的关系数据库主要处理遵循预定义模式的结构化数据不同,Milvus 是自下而上设计的,旨在处理从非结构化数据转换而来的嵌入向量。

Milvus 采用共享存储架构,存储计算完全分离,计算节点支持横向扩展。从架构上来看,Milvus 遵循数据流和控制流分离,整体分为了四个层次,分别为接入层(access layer)、协调服务(coordinator service)、执行节点(worker node)和存储层(storage)。各个层次相互独立,独立扩展和容灾。

2. 核心概念理解

Embeddings:Embedding = 把文字 / 图片 / 音频,变成一串数字(向量),让计算机能 “读懂” 内容的含义。

2.1 数据库概念

  • Collections,相当于关系数据库中的“表”,用于存储和管理实体。

  • 实体(Entity),,由多个字段组成,代表现实世界对象;每个实体有唯一主键(可自定义或 AutoID)。

  • 字段(Field),,支持标量字段(int, string)和向量字段(dense/sparse vector)。

  • 模式(Schema),定义 Collection 的结构,包括字段、主键是否自动递增(AutoID)、描述等。

  • 动态模式(Dynamic Schema),允许插入未在 Schema 中预定义的新字段,实现无 Schema 写入。

  • 非结构化数据,图像、视频、文本等无固定格式数据,通过 AI 模型转入向量存储 Milvus。

  • 向量(Vector),非结构化数据(图像、视频、文本)的嵌入表示,Milvus 2.4+ 支持密集向量和稀疏向量。

  • 主键与ID(AutoID),主键字段的属性,启用后由系统根据时间戳自动生成唯一 ID;

  • 索引与搜索(Index), 为加速向量相似性搜索而构建的数据结构;支持多种类型(IVF, HNSW 等)。

  • 自动索引,Milvus 根据经验自动选择最优索引类型和参数,适合无需精细调参的场景。

  • 度量类型(Metric Type),定义向量相似度计算方式:L2(欧氏距离)、IP(内积)、COSINE(余弦)、二元等。

  • 搜索(Search)基于向量执行相似性搜索的 API。

  • 查询(Query)使用布尔表达式对标量字段进行过滤的 API 。

  • 过滤搜索,向量搜索 + 标量条件过滤(如 category == "cat")。

  • 混合搜索,Milvus 2.4+ 支持对多个向量字段同时搜索并融合结果。

  • 范围搜索, 查找与目标向量距离在指定范围内的结果。

  • 高级功能:

    • 嵌入(Embedding) , Milvus 内置支持调用嵌入模型(如 text2vec),简化向量化流程。
    • Milvus 集群,分布式部署,支持高可用、水平扩展。
  • 数据组织:

    名称 解释
    分区(Partition) 对 Collection 的逻辑划分,减少读取时扫描的数据量。
    分区键(Partition Key) 按字段值自动分片,使相同简直的数据落在同一分区,加速带该字段过滤的查询。
    碎片(Shard) 基于主键哈希的物理分片,用于分散写入负载,提升读写吞吐。
    分段(Segment) 存储实体数据文件,分为"成长段"(接收新数据)和“封存段”(只读,对象存储)
  • 流式日志:

    名称 解释
    通道(Channel) Milvus 流架构的核心单元,分 PChannel(物理)和 VChannel(虚拟)。
    PC 通道(PChannel) 物理通道,对应 Woodpecker 管理的一个 WAL 流。
    VChannel 虚拟通道,对应一个 Collection 的一个分片(shard)。
    流服务(Stream Service) 基于 WAL 构建,支持流式写入、故障恢复、数据订阅等。
    日志快照(Binlog) 记录数据变更的二进制日志,分 Insert/Delete/DDL 三类。
    WAL storage 先写日志机制,确保数据持久性和一致性。
    MemoryBuffer Woodpecker 轻量模式,数据暂存内存后刷入对象存储,适合小规模批量写入。
    QuorumBuffer Woodpecker 高可用模式,三副本法定写入,适合低延迟、高可靠场景。
  • 工具与生态

    名称 解释
    Attu Milvus 官方一体化 Web 管理 UI,降低运维复杂度。
    Birdwatcher 调试工具,连接 etcd 实时监控 Milvus 状态,支持 etcd 备份与故障排查。
    PyMilvus 官方 Python SDK,支持 ORM 和 MilvusClient 两种使用方式。
    Milvus 备份 数据备份工具,用于灾难恢复。
  • 依赖组件,Milvus 依赖 etcd(元数据)、MinIO/S3(对象存储)、Pulsar/Kafka(旧版日志)或 Woodpecker(新版 WAL)。

2.2 部署模式

  • Milvus 单机版, 所有组件运行于单进程,适合开发/测试。
  • Milvus 集群,分布式部署,支持高可用、水平扩展。

2.3 安装

Milvus 是一个高性能、可扩展的向量数据库。它支持各种规模的用例,从在 Jupyter 笔记本中本地运行的演示到处理数百亿向量的大规模 Kubernetes 集群。

目前,Milvus 有三种部署选项:Milvus Lite、Milvus Standalone 和 Milvus Distributed。
image-20260313142915749

2.3.1 Milvus Lite

使用 Milvus Lite 在本地运行 Milvus。Milvus Lite 是Milvus 的轻量级版本,Milvus 是一个开源向量数据库,通过向量嵌入和相似性搜索为人工智能应用提供支持。

Milvus Lite 目前支持以下环境:

  • Ubuntu >= 20.04(x86_64 和 arm64)
  • MacOS >= 11.0(苹果硅 M1/M2 和 x86_64)
  • 不支持 Windows
# 安装
pip install pymilvus

# 再次安装
pip install milvus_lite

使用的时候可能会报错;

2.3.2 Milvus Standalone

直接在 Ubuntu 的平台中使用 docker compose 进行部署使用;

下载相关的 Dockercompose.yml 文件

wget https://github.com/milvus-io/milvus/releases/download/v2.6.7/milvus-standalone-docker-compose.yml -O docker-compose.yml

下载后的文件为

version: '3.5'

services:
  etcd:
    container_name: milvus-etcd
    image: quay.io/coreos/etcd:v3.5.25
    environment:
      - ETCD_AUTO_COMPACTION_MODE=revision
      - ETCD_AUTO_COMPACTION_RETENTION=1000
      - ETCD_QUOTA_BACKEND_BYTES=4294967296
      - ETCD_SNAPSHOT_COUNT=50000
    volumes:
      - ${DOCKER_VOLUME_DIRECTORY:-.}/volumes/etcd:/etcd
    command: etcd -advertise-client-urls=http://etcd:2379 -listen-client-urls http://0.0.0.0:2379 --data-dir /etcd
    healthcheck:
      test: ["CMD", "etcdctl", "endpoint", "health"]
      interval: 30s
      timeout: 20s
      retries: 3

  minio:
    container_name: milvus-minio
    image: minio/minio:RELEASE.2024-12-18T13-15-44Z
    environment:
      MINIO_ACCESS_KEY: minioadmin
      MINIO_SECRET_KEY: minioadmin
    ports:
      - "9001:9001"
      - "9000:9000"
    volumes:
      - ${DOCKER_VOLUME_DIRECTORY:-.}/volumes/minio:/minio_data
    command: minio server /minio_data --console-address ":9001"
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"]
      interval: 30s
      timeout: 20s
      retries: 3

  standalone:
    container_name: milvus-standalone
    image: milvusdb/milvus:v2.6.7
    command: ["milvus", "run", "standalone"]
    security_opt:
    - seccomp:unconfined
    environment:
      ETCD_ENDPOINTS: etcd:2379
      MINIO_ADDRESS: minio:9000
      MQ_TYPE: woodpecker
    volumes:
      - ${DOCKER_VOLUME_DIRECTORY:-.}/volumes/milvus:/var/lib/milvus
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:9091/healthz"]
      interval: 30s
      start_period: 90s
      timeout: 20s
      retries: 3
    ports:
      - "19530:19530"
      - "9091:9091"
    depends_on:
      - "etcd"
      - "minio"

networks:
  default:
    name: milvus(agent)

我们可以看到下载的docker-compose.yml的文件有三个,功能主要是

etcd = 存配置 / 结构

minio = 存向量 / 索引

milvus = 计算 / 查询

容器 作用 镜像 类比
milvus-standalone Milvus 主服务:处理向量查询、插入、计算、索引 milvusdb/milvus:v2.6.7 大脑
etcd 元数据存储:存配置、集合信息、分片、状态 quay.io/coreos/etcd:v3.5.25 记事本 / 注册表
minio 对象存储:存原始向量数据、索引文件 minio/minio:RELEASE.2024-12-18T13-15-44Z 仓库 / 硬盘

使用docker-compose up -d启动后,查看状态

image-20260316105901602

访问自己电脑上的端口

image-20260316114117907

关于 UI 的介绍,详情见文档:https://milvus.io/docs/zh/milvus-webui.md

3. Milvus 使用

3.1 常见使用

from pymilvus import MilvusClient
# client = MilvusClient("./milvus_demo.db")

# 连接
client = MilvusClient("http://192.168.159.133:19530", timeout=1000)
print("OK")

# 创建数据库
client.create_database(db_name="my_milvus")

print("创建数据库成功")

# 查看数据库
v = client.list_databases()
print(v)
# 描述数据库
desc = client.describe_database("default")
print(desc)

"""
>>> OK
>>> 创建数据库成功
>>> ['default', 'my_milvus']
>>> {'name': 'default'}
"""

image-20260316115255588

3.2 数据库的属性

每个数据库都有自己的属性,您可以在创建数据库时设置数据库属性(如创建数据库中所述),也可以更改和删除任何现有数据库的属性。

属性名称 类型 属性名称
database.replica.number 整数 指定数据库的副本数量。
database.resource_groups 字符串 以逗号分隔的列表形式列出与指定数据库相关的资源组名称。
database.diskQuota.mb 整数 指定数据库的最大磁盘空间大小(MB)。
database.max.collections 整数 指定书数据库中允许的最大 Collections 数量。
database.force.deny.writing 布尔 是否强制指定的数据库拒绝写操作。
database.force.deny.reading 布尔 是否强制指定的数据库拒绝读取操作。

3.3 数据库的删除

from pymilvus import MilvusClient

# client = MilvusClient("./milvus_demo.db")

# 连接
client = MilvusClient("http://192.168.159.133:19530", timeout=1000)
# print("OK")

# 创建数据库
# client.create_database(db_name="my_milvus")
client.create_database(db_name="my_database_2")
#
# print("创建数据库成功")

# 查看数据库
# v = client.list_databases()
# print(v)
# 描述数据库
# desc = client.describe_database("default")
# print(desc)


# 更改数据库属性
client.alter_database_properties(
    db_name="my_milvus",
    properties={
        "database.max.collections": 10
    }
)

client.alter_database_properties(
    db_name="my_database_2",
    properties={
        "database.max.collections": 10
    }
)

# 删除数据库属性
client.drop_database_properties(
    db_name="my_database_2",
    property_keys=["database.max.collections"]
)

# 切换数据库
client.use_database(
    db_name="my_database_2"
)

# 删除数据库
client.drop_database(
    db_name="my_database_2"
)

image-20260316134735745

3.4 数据表

在 Milvus 上,您可以创建多个 Collections 来管理数据,并将数据作为实体插入到 Collections 中,Collections 和实体类似于关系数据库中的表和记录。

Collection 是一个二维表,具有固定的列和变化的行。每列代表一个字段,每行代表一个实体。

img

3.4.1 约束摘要(Shema)

在描述一个对象时,我们通常会提到它的属性,如大小、重量和位置。您可以将这些属性用作 Collection 中的字段。每个字段都有各种约束属性,例如向量字段的数据类型和维度。通过创建字段并定义其顺序,可以形成一个 Collections Schema。

您应在要插入的实体中包含所有 Schema 定义的字段。要使其中一些字段可选,可考虑启用动态字段。有关详情,请参阅动态字段。

  • 使其为空或设置默认值

    有关如何使字段无效或设置默认值的详细信息,请参阅无效和默认

  • 启用动态字段

    有关如何启用和使用动态字段的详细信息,请参阅动态字段。

from pymilvus import MilvusClient, DataType

# 连接到本地 Milvus 服务
client = MilvusClient(
    uri="http://192.168.159.133:19530",
    db_name="my_milvus",
    # token="<PASSWORD>", # 认证的用户名与密码
)

# 创建集合结构
schema = MilvusClient.create_schema(auto_id=False, enable_dynamic=True)  # 指定主键、允许插入未定义的额外字段

# 添加主键字段
schema.add_field(field_name="my_id", datatype=DataType.INT64, is_primary=True)
# 添加向量字段
schema.add_field(field_name="my_vector", datatype=DataType.FLOAT_VECTOR, dim=5)
# 添加字符串字段
schema.add_field(field_name="my_age", datatype=DataType.VARCHAR, max_length=512)

3.4.2 主键

与关系数据库中的主字段类似,Collection 也有一个主字段,用于将实体与其他实体区分开来。主字段中的每个值都是全局唯一的,并与一个特定的实体相对应。

如上图所示,名为id的字段是主字段,第一个 ID0对应一个名为 "冠状病毒的死亡率并不重要"的实体。不会有其他实体的主字段为 0。

主字段只接受整数或字符串。插入实体时,默认情况下应包含主字段值。但是,如果在创建 Collections 时启用了AutoId,Milvus 将在插入数据时生成这些值。在这种情况下,请从要插入的实体中排除主字段值。

3.4.3 设置索引参数

在特定字段上创建索引可加快对该字段的搜索。索引记录了 Collections 中实体的顺序。如以下代码片段所示,您可以使用metric_typeindex_type 为 Milvus 选择适当的方式为字段建立索引,并测量向量嵌入之间的相似性。

在 Milvus 上,您可以使用AUTOINDEX 作为所有向量场的索引类型,并根据需要使用COSINEL2IP 中的一种作为度量类型。

  • metric_type(度量类型):
    定义如何计算两个向量之间的相似性或距离。常见选项:
    • L2:欧几里得距离(越小越相似)
    • IP(Inner Product):点积(越大越相似,常用于归一化后的向量)
    • COSINE:余弦相似度(衡量方向一致性)
  • index_type(索引类型):定义使用哪种算法结构来加速搜索,例如 IVF_FLAT、HNSW、AUTOINDEX 等。

这两个参数共同决定了索引的构建方式和后续搜索的行为。

# FLOAT_VECTOR 类型的字段必须创建向量索引,否则无法是使用;
index_params = client.prepare_index_params()
 
index_params.add_index(
    field_name="my_id",
    index_type="AUTOINDEX"
)
 
index_params.add_index(
    field_name="my_vector", 
    index_type="AUTOINDEX",  # 索引类型;
    metric_type="COSINE"     # 相似性的判断, COSINE
)

3.4.4 创建数据表

如果创建了带有索引参数的 Collection,Milvus 会在创建是自动加载该 Collection。在这种情况下,索引参数中提到的所有字段都会被索引。

以下代码片段演示了如何创建带索引参数的 Collections 并检查加载状态。

# !/usr/bin/env python
# -*-coding:utf-8 -*-

"""
@File    : 2.py
@Time    : 2026/3/17 15:04
@Author  : zi qing bao jian
@Version : 1.0
@Desc    : 
"""
from pymilvus import MilvusClient, DataType
from pymilvus.milvus_client import IndexParams

# 连接到本地 Milvus 服务
client = MilvusClient(
    uri="http://192.168.159.133:19530",
    db_name="my_milvus",
    # token="<PASSWORD>", # 认证的用户名与密码
)

# 创建集合结构
schema = MilvusClient.create_schema(auto_id=False, enable_dynamic=True)  # 指定主键、允许插入未定义的额外字段

# 添加主键字段
schema.add_field(field_name="my_id", datatype=DataType.INT64, is_primary=True)
# 添加向量字段
schema.add_field(field_name="my_vector", datatype=DataType.FLOAT_VECTOR, dim=5)
# 添加字符串字段
schema.add_field(field_name="my_age", datatype=DataType.VARCHAR, max_length=512)

# 创建向量的索引
# FLOAT_VECTOR 类型的字段必须创建向量索引,否则无法是使用;
index_params = client.prepare_index_params()

index_params.add_index(
    field_name="my_id",
    index_type="AUTOINDEX"
)

index_params.add_index(
    field_name="my_vector",
    index_type="AUTOINDEX",  # 索引类型;
    metric_type="COSINE"  # 相似性的判断, COSINE, 使用余弦相似度
)

client.create_collection(collection_name="my_collection2",schema=schema, index_params=index_params)

res = client.get_load_state(
    collection_name="my_collection2"
)

print(res)  # >>> 输出 {'state': <LoadState: NotExist>}

image-20260317153125186

3.4.5 设置数据表属性

您可以为要创建的 Collection 设置属性,使其适合您的服务。适用的属性如下。

  • 设置分片数

    分片是 Collections 的水平切片,每个分片对应一个数据输入通道。默认情况下,每个 Collections 都有一个分区。您可以在创建 Collections 时指定分片数量,以便更好地适应数据量和工作负载。

    作为一般指导原则,在设置分片数量时应考虑以下几点:

    数据大小:通常的做法是每 2 亿个实体设置一个分区。也可以根据总数据量进行估算,例如,计划插入的数据量每 100 GB 就增加一个分区。
    流节点利用率:如果你的 Milvus 实例有多个流节点,建议使用多个分片。这样可以确保数据插入工作量分布在所有可用的流节点上,防止一些节点闲置,而其他节点超负荷工作。

    client.create_collection(
        collection_name="customized_setup_3",
        schema=schema,
        # highlight-next-line
        num_shards=1
    )
    
  • 启用 mmap

    Milvus 默认在所有 Collections 上启用 mmap,允许 Milvus 将原始字段数据映射到内存中,而不是完全加载它们。这样可以减少内存占用,提高 Collections 的容量。有关 mmap 的详细信息,请参阅使用 mmap

    client.create_collection(
        collection_name="customized_setup_4",
        schema=schema,
        # highlight-next-line
        enable_mmap=False
    )
    
  • 设置 Collections TTL

    如果需要在特定时间段内删除 Collections 中的数据,可以考虑以秒为单位设置其 Time-To-Live (TTL)。一旦 TTL 超时,Milvus 就会删除 Collection 中的实体。删除是异步的,这表明在删除完成之前,搜索和查询仍然可以进行。

    client.create_collection(
        collection_name="customized_setup_5",
        schema=schema,
        # highlight-start
        properties={
            "collection.ttl.seconds": 86400
        }
        # highlight-end
    )
    
  • 设置一致性级别

    创建 Collection 时,可以为集合中的搜索和查询设置一致性级别,您还可以再特定搜索或查询过程中更改 Collections 的一致性级别

    client.create_collection(
        collection_name="customized_setup_6",
        schema=schema,
        # highlight-next-line
        consistency_level="Bounded",
    )
    
  • 合并后的代码

    # !/usr/bin/env python
    # -*-coding:utf-8 -*-
    
    """
    @File    : 2.py
    @Time    : 2026/3/17 15:04
    @Author  : zi qing bao jian
    @Version : 1.0
    @Desc    : 
    """
    from pymilvus import MilvusClient, DataType
    from pymilvus.milvus_client import IndexParams
    
    # 连接到本地 Milvus 服务
    client = MilvusClient(
        uri="http://192.168.159.133:19530",
        db_name="my_milvus",
        # token="<PASSWORD>", # 认证的用户名与密码
    )
    
    # 创建集合结构
    schema = MilvusClient.create_schema(auto_id=False, enable_dynamic=True)  # 指定主键、允许插入未定义的额外字段
    
    # 添加主键字段
    schema.add_field(field_name="my_id", datatype=DataType.INT64, is_primary=True)
    # 添加向量字段
    schema.add_field(field_name="my_vector", datatype=DataType.FLOAT_VECTOR, dim=5)
    # 添加字符串字段
    schema.add_field(field_name="my_age", datatype=DataType.VARCHAR, max_length=512)
    
    # 创建向量的索引
    # FLOAT_VECTOR 类型的字段必须创建向量索引,否则无法是使用;
    index_params = client.prepare_index_params()
    
    index_params.add_index(
        field_name="my_id",
        index_type="AUTOINDEX"
    )
    
    index_params.add_index(
        field_name="my_vector",
        index_type="AUTOINDEX",  # 索引类型;
        metric_type="COSINE"  # 相似性的判断, COSINE, 使用余弦相似度
    )
    
    # client.create_collection(collection_name="my_collection2",schema=schema, index_params=index_params)
    
    # 设置分区, TTL
    client.create_collection(
        collection_name="my_collection3",
        schema=schema,
        index_params=index_params,
        num_shards=1,
        properties={
            "collection.ttl.seconds": 86400,  # 设定ttl, 删除数据时候, 超过 milvus 就会删除 Collection 中的实体;
        }
    )
    
    
    
    res = client.get_load_state(
        collection_name="my_collection3"
    )
    
    print(res)  # >>> 输出 {'state': <LoadState: NotExist>}
    
    

3.4.6 列出数据表

from pymilvus import MilvusClient, DataType

client = MilvusClient("http://192.168.159.133:19530", db_name="my_milvus")
res = client.list_collections()  # 列出数据表
print(res)

image-20260317184855688

3.4.7 修改数据表

from pymilvus import MilvusClient, DataType

client = MilvusClient("http://192.168.159.133:19530", db_name="my_milvus")
res = client.list_collections()  # 列出数据表
print(res)

# 设置属性

client.alter_collection_properties(
    collection_name="my_collection3",
    properties={"collection.ttl.seconds": 60}  # 减小 ttl
)
print("ttl 设置成功")
# 对表名进行重命名
client.rename_collection(old_name="my_collection3", new_name="my_collection0315")
res = client.list_collections()  # 再次列出数据表
print(res)

# 删除,属性的配置
client.drop_collection_properties(
    collection_name="my_collection0315",
    property_keys=["collection.ttl.seconds"]
)

image-20260317185602198

3.4.8 加载和释放

加载数据表是在集合中进行相似性搜索和查询的前提,加载 Collections 时,Milvus 会将索引文件盒所有字段的原始数据加载到内存中,以便快速响应搜索和查询,在载入 Collections 后插入的实体会自动编入索引并载入。

# 加载与释放
from pymilvus import MilvusClient, DataType

client = MilvusClient("http://192.168.159.133:19530", db_name="my_milvus")

client.load_collection(collection_name="my_collection2")

res = client.get_load_state(
    collection_name="my_collection2"
)

print(res)

client.release_collection(
    collection_name="my_collection2"
)

res = client.get_load_state(
    collection_name="my_collection2"
)

print(res)

image-20260317190024443

3.4.9 一致性级别

Milvus 提供以下四种一致性级别(Consistency Levels):

  • Strong(强一致性):读操作总能返回最新的写入结果,但性能开销比较大
  • Bounded(有限一致性,默认):在可接受的延迟范围内保证数据一致性(例如,最多延迟几秒),兼顾性能与准确性。
  • Eventually(最终一致性):写入后经过一段时间,所有节点最终会看到相同的数据;延迟可能较长,但吞吐高。
  • Session(会话一致性):在同一客户端会话中,保证“读己之写”(即自己写的数据自己能立刻读到)。

3.5 分区管理

分区:partition

分区是一个 Collection 的子集。每个分区与其父集合共享相同的数据结构,但只包含集合中的一个数据子集。

创建一个 Collection 时,Milvus 也会在该 Collection 中创建一个名为_default 的分区。如果不添加其他分区,所有插入到 Collections 中的实体都会进入默认分区,所有搜索和查询也都在默认分区内进行。

可以可以添加更多分区,并根据特定条件将实体插入其中。这样就可以限制在某些分区内进行搜索和查询,从而提高搜索性能。一个 Collections 最多可以由 1024 个分区。

# !/usr/bin/env python
# -*-coding:utf-8 -*-

"""
@File    : 5.py
@Time    : 2026/3/18 15:43
@Author  : zi qing bao jian
@Version : 1.0
@Desc    : 分区管理
"""
from pymilvus import MilvusClient

client = MilvusClient("http://192.168.159.133:19530", db_name="my_milvus")

# 创建分区
client.create_partition(collection_name="my_database_2", partition_name="partition_2")

# 列出分区
res = client.list_partitions(collection_name="my_database_2")

print(res)

# 检查分区
res = client.has_partition(collection_name="my_database_2", partition_name="partition_2")
print(res)

client.load_partitions(
    collection_name="my_collection",
    partition_names=["partitionA"]
)

res = client.get_load_state(
    collection_name="my_collection",
    partition_name="partitionA"
)

print(res)

# 释放分区
client.release_partitions(
    collection_name="my_collection",
    partition_names=["partitionA"]
)

# 删除分区
client.drop_partition(
    collection_name="my_collection",
    partition_name="partitionA"
)

4. 模式

Schema 定义了 Collections 的数据结构。在创建一个 Collection 之前,你需要设计出它的 Schema。

设计良好的 Schema 至关重要,因为它抽象了数据模型 ,并决定能否通过搜索实现业务目标。此外,由于插入 Collections 的每一行数据都必须遵循 Schema,因此有助于保持数据的一致性和长期质量。从技术角度看,定义明确的 Schema 会带来组织良好的列数据存储和更简洁的索引结构,从而提升搜索性能。

一个 Collection Schema 有一个主键,最多四个向量字段和几个标量字段。下图说明了如何将文章映射到模式字段列表。

img

from pymilvus import MilvusClient, DataType

# 创建 Schema
schema = MilvusClient.create_schema()

# 添加主键, Collections 中的主字段唯一标识一个实体。只接受 INT64 或 VarChar 值;
schema.add_field(
    field_name="my_id",
    datatype=DataType.INT64,
    # highlight-start
    is_primary=True,
    auto_id=False,
    # highlight-end
)

# 添加向量, 向量字段接受各种稀疏和密集向量嵌入。
schema.add_field(
	field_name="my_vector",
    datatype=DateType.FLOAT_VECTOR,
    dim=5
)

# 添加标量,在常见情况下,您可以使用标量字段来存储存储在 Milvus 中的向量嵌入的元数据,
# 并通过元数据过滤进行 ANN 搜索,以提高搜索结果的正确性。

#字符串
schema.add_field(
    field_name="my_varchar",
    datatype=DataType.VARCHAR,
    # highlight-next-line
    max_length=512
)


#数字
schema.add_field(
    field_name="my_int64",
    datatype=DataType.INT64,
)
 
#布尔0/1
schema.add_field(
    field_name="my_bool",
    datatype=DataType.BOOL,
)
 
#json
schema.add_field(
    field_name="my_json",
    datatype=DataType.JSON,
)
 
#数组
schema.add_field(
    field_name="my_array",
    datatype=DataType.ARRAY,
    element_type=DataType.VARCHAR,
    max_capacity=5,
    max_length=512,
)

4.1 主键

Milvus 支持两种分配主键值的模式。

模式 描述 建议
自动 ID Milvus 自动为插入或者导入的实体生成唯一标识符。 不需要手动管理 ID 的大多数情况
手动 ID 在插入或导入数据时,您自己提供唯一 ID 。 当 ID 必须与外部系统或已有数据集保持一致时。
from pymilvus import MilvusClient, DataType

client = MilvusClient(uri="http://192.168.159.133:19530", db_name="my_milvus")

schema = client.create_schema()

schema.add_field(
    field_name="id",
    is_primary=True,
    auto_id=True,  # Milvus generates IDs automatically; Defaults to False
    datatype=DataType.INT64
)

schema.add_field(field_name="embedding", datatype=DataType.FLOAT_VECTOR, dim=4)  # Vector field
schema.add_field(field_name="category", datatype=DataType.VARCHAR, max_length=1000)  # Scalar field of the VARCHAR type

# 查看是否存在 collection, 如果存在的话则删除;
if client.has_collection("demo_autoid"):
    client.drop_collection("demo_autoid")

# 创建的 collection, 并且指定 schema
client.create_collection(collection_name="demo_autoid", schema=schema)

插入数据,不要在数据中包含主键字段的列, Milvus 会自动生成 ID 。

# !/usr/bin/env python
# -*-coding:utf-8 -*-

"""
@File    : 6.py
@Time    : 2026/3/23 12:17
@Author  : zi qing bao jian
@Version : 1.0
@Desc    :
"""

from pymilvus import MilvusClient, DataType

client = MilvusClient(uri="http://192.168.159.133:19530", db_name="my_milvus")

data = [
    {"embedding": [0.1, 0.2, 0.3, 0.4], "category": "book"},
    {"embedding": [0.2, 0.3, 0.4, 0.5], "category": "toy"},
]

res = client.insert(collection_name="demo_autoid", data=data)
print("Generated IDs:", res.get("ids"))



image-20260323123539957

Milvus Web UI(v2.5+ 内置)主要用于监控和运维,不支持直接查看 / 预览插入的原始数据(向量、字段值)。

额外补充: 查看的时候使用,Attu 是官方全功能 GUI,支持数据列表、预览、搜索、编辑、删除

docker run -d --name=attu -p 8000:3000 -e MILVUS_URL=localhost:19530 zilliz/attu:latest

image-20260323134126941

手动 ID

schema.add_field(
    field_name="product_id",
    is_primary=True,
    auto_id=False,  # You'll provide IDs manually at data ingestion
    datatype=DataType.VARCHAR,
    max_length=100 # Required when datatype is VARCHAR
)


data = [
    {"product_id": "PROD-001", "embedding": [0.1, 0.2, 0.3, 0.4], "category": "book"},
    {"product_id": "PROD-002", "embedding": [0.2, 0.3, 0.4, 0.5], "category": "toy"},
]
 
res = client.insert(collection_name="demo_manual_ids", data=data)
print("Generated IDs:", res.get("ids"))

插入后的数据可以使用 attu 进行查看

image-20260402134748579

4.2 密集向量

密集向量是广泛应用与机器学习和数据分析的数据表示法。它们由包含实数的数组组成,其中大部分或所有元素都不为0。与稀疏向量相比,密集向量在同一维度上包含更多信息,因为每个维度都持有有意义的值。这种表示方法能有效捕捉复杂的模式和关系,使数据在高位空间中更容易分析和处理。密集向量通常有固定的维数,从几十到几百甚至上千不等,具体取决于应用和需求;

密集向量主要用于需要理解数据语义的场景,如语义搜索和推荐系统。在语义搜索 中,密集向量有助于捕捉查询和文档之间的潜在联系,提高搜索结果的相关性。在推荐系统中,密集矢量有助于识别用户和项目之间的相似性,从而提供更加个性化的建议。
密集向量通常表示为具有固定长度的浮点数数组,如[0.2, 0.7, 0.1, 0.8, 0.3, ..., 0.5] 。这些向量的维度通常从数百到数千不等,如 128、256、768 或 1024。每个维度都能捕捉对象的特定语义特征,通过相似性计算使其适用于各种场景。

img

上图展示了密集向量在二维空间中的表现形式。虽然实际应用中的密集向量通常具有更高的维度,但这种二维插图有效地传达了几个关键概念:

  • 多维表示:每个点代表一个概念对象(如Milvus、向量数据库、检索系统等),其位置由其维度值决定。

  • 语义关系:点之间的距离反映了概念之间的语义相似性。距离较近的点表示语义关联度较高的概念。

  • 聚类效应:相关概念(如Milvus、向量数据库和检索系统)在空间中的位置相互靠近,形成语义聚类。

下面是一个代表文本"Milvus is an efficient vector database" 的真实稠密向量示例:

[
    -0.013052909,
    0.020387933,
    -0.007869,
    -0.11111383,
    -0.030188112,
    -0.0053388323,
    0.0010654867,
    0.072027855,
    // ... more dimensions
]
 

稠密向量可使用各种嵌入模型生成,如用于图像的 CNN 模型(如ResNet、VGG)和用于文本的语言模型(如BERT、Word2Vec)。这些模型将原始数据转化为高维空间中的点,捕捉数据的语义特征。此外,Milvus 还提供便捷的方法,帮助用户生成和处理密集向量,详见 Embeddings。

一旦数据被向量化,就可以存储在 Milvus 中进行管理和向量检索。下图显示了基本流程。

img

4.2.1 添加向量场

要在 Milvus 中使用密集向量,首先要在 Collections 创建时定义一个用于存储密集向量的向量场。这一过程包括

  • 将 datatyoe 设置为支持的密集向量数据类型。
  • 使用dim 参数指定密集向量的维数。

在下面的示例中,我们添加了一个名为dense_vector 的向量字段来存储密集向量。字段的数据类型为FLOAT_VECTOR ,维数为4

from pymilvus import MilvusClient, DataType

client = MilvusClient(uri="http://192.168.159.133:19530")

schema = client.create_schema(
	auto_id=True,
    enable_dynamic_fileds=True
)

# 设置为 VARCHAR, 并且设置成为主键的形式;
schema.add_field(field_name="pk", datatype=DataType.VARCHAR, is_primary=True, max_length=100)
# 创建向量字段,设置维数为4
schema.add_filed(field_name="dense_vector", datatype=DataType.FLOAT_VECTOR, dim=4)

4.2.2 设置索引参数

为了加速语义搜索,必须为向量字段创建索引。索引可以大大提高大规模向量数据的检索效率。

from pymilvus import MilvusClient, DataType

client = MilvusClient(uri="http://192.168.159.133:19530")

schema = client.create_schema(
	auto_id=True,
    enable_dynamic_fileds=True
)

# 设置为 VARCHAR, 并且设置成为主键的形式;
schema.add_field(field_name="pk", datatype=DataType.VARCHAR, is_primary=True, max_length=100)
# 创建向量字段,设置维数为4
schema.add_filed(field_name="dense_vector", datatype=DataType.FLOAT_VECTOR, dim=4)

#
index_params = client.prepare_index_params()

# 创建索引的字段;
index_params.add_index(
	field_name="dense_vector",
    index_name="dense_vector_index",  # 指定索引的名称;
    index_type="AUTOINDEX",  # 指定索引的类型;
    metric_type="IP"  # 表示将使用内积作为距离度量;
)

Milvus 提供多种索引类型,以获得更好的向量搜索体验。AUTOINDEX 是一种特殊的索引类型,旨在平滑向量搜索的学习曲线。

4.2.3 插入数据

完成密集向量和索引参数设置后, 就可以创建包含密集向量的 Collections。下面的实力使用create_collection方法创建一个名为 my_collection 的集合。

client.create_collection(
	collection_name="my_collection",
    schema=schema,
    index_params=index_params
)

创建集合后,使用insert 方法添加包含密集向量的数据。确保插入的密集向量的维度与添加密集向量字段时定义的dim 值相匹配。

data = [
    {"dense_vector": [0.1, 0.2, 0.3, 0.7]},
    {"dense_vector": [0.2, 0.3, 0.4, 0.8]},
]

# 插入数据
client.insert(
	collection_name="my_collection",
    data=data
)

4.2.4 执行相似性搜索

基于密集向量的语义搜索是 Milvus 的核心功能之一,可以根据向量之间的距离快速找到与查询向量相似最相似的数据。要执行相似性搜索,请准备好查询向量和搜索参数,然后调用 Search 方法。

# 定义向量搜索参数
# nprobe 控制在近似最近邻搜索(ANN)中查询时探索的聚类的中心数量;
# 值越大,搜索越精确但速度越慢;值越小,速度越快但可能牺牲精度。
search_params = {
    "params": {"nprobe": 10}
}

# 定义查询向量,这是一个四维浮点数列表,代表要搜索的嵌入向量(embedding)
query_vector = [0.1, 0.2, 0.3, 0.7]

# 执行向量的相似性搜索
res = client.search(
	collection_name="my_collection",		# 指定要搜索的集合名称
    data=[query_vector], 		# 输入查询向量需要包装在列表中,支持批量查询;
    anns_field="dense_vector",  # 用于 ANN 搜索的向量的字段名
    search_params=search_params, # 传入搜索参数 nprobe
    limit=5,
    output_fields=['pk']		# 指定那些字段返回
)

print(res)

4.3 字符串字段

在 Milvus 中, VARCHAR 是用于存储字符串的数据类型。

定义 Varchar 字段时,有两个参数是必须的:

  • 将 datatype 设置为 DataType.VARCHAR。
  • 指定 max_length,它定义了 VARCHAR 字段可以存储的最大字节数。max_length 的有效范围为 1 至 65535 字节;

4.3.1 添加字符串字段

要在 Milvus 中存储字符串数据,请在 Collections Schema 中定义一个VARCHAR 字段。下面是一个定义了两个VARCHAR 字段的 Collections 模式的示例:

from pymilvus import MilvusClient, DataType
 
SERVER_ADDR = "http://localhost:19530"
 
client = MilvusClient(uri=SERVER_ADDR)
 
schema = client.create_schema(
    auto_id=False,
    enable_dynamic_fields=True,
)
 
schema.add_field(field_name="varchar_field1", datatype=DataType.VARCHAR, max_length=100, nullable=True, default_value="Unknown")
schema.add_field(field_name="varchar_field2", datatype=DataType.VARCHAR, max_length=200, nullable=True)
schema.add_field(field_name="pk", datatype=DataType.INT64, is_primary=True)
schema.add_field(field_name="embedding", datatype=DataType.FLOAT_VECTOR, dim=3)

# 设置索引的参数
# 下面的示例使用AUTOINDEX 索引类型为向量字段embedding 和标量字段varchar_field1 创建了索引。
# 使用这种类型,Milvus 会根据数据类型自动选择最合适的索引。您还可以自定义每个字段的索引类型和参数。
 
index_params = client.prepare_index_params()
 
index_params.add_index(
    field_name="varchar_field1",
    index_type="AUTOINDEX",
    index_name="varchar_index"
)
 
index_params.add_index(
    field_name="embedding",
    index_type="AUTOINDEX",  # Use automatic indexing to simplify complex index settings
    metric_type="COSINE"  # Specify similarity metric type, options include L2, COSINE, or IP
)
# 定义好 Schema 和索引之后, 插入数据;
client.create_collection(
    collection_name="my_collection",
    schema=schema,
    index_params=index_params
)

data = [
    {"varchar_field1": "Product A", "varchar_field2": "High quality product", "pk": 1, "embedding": [0.1, 0.2, 0.3]},
    {"varchar_field1": "Product B", "pk": 2, "embedding": [0.4, 0.5, 0.6]}, # varchar_field2 field is missing, which should be NULL
    {"varchar_field1": None, "varchar_field2": None, "pk": 3, "embedding": [0.2, 0.3, 0.1]},  # `varchar_field1` should default to `Unknown`, `varchar_field2` is NULL
    {"varchar_field1": "Product C", "varchar_field2": None, "pk": 4, "embedding": [0.5, 0.7, 0.2]},  # `varchar_field2` is NULL
    {"varchar_field1": None, "varchar_field2": "Exclusive deal", "pk": 5, "embedding": [0.6, 0.4, 0.8]},  # `varchar_field1` should default to `Unknown`
    {"varchar_field1": "Unknown", "varchar_field2": None, "pk": 6, "embedding": [0.8, 0.5, 0.3]},  # `varchar_field2` is NULL
    {"varchar_field1": "", "varchar_field2": "Best seller", "pk": 7, "embedding": [0.8, 0.5, 0.3]}, # Empty string is not treated as NULL
]
 
client.insert(
    collection_name="my_collection",
    data=data
)

索引有助于提高搜索和查询性能。在 Milvus 中,对于向量字段必须建立索引,但对于标量字段可选。

4.3.2 过滤表达式检索

使用 query 方法检索与指定过滤表达式匹配实体。

  • 搜索:向量
  • 检索:标量
################### 检索 #######################

from pymilvus import MilvusClient, DataType

SERVER_ADDR = "http://192.168.159.133:19530"

client = MilvusClient(uri=SERVER_ADDR)

# 检索 varchar_filed1 与字符串 “Product A”
filter_str = "varchar_field1 == 'Product A'"
res = client.query(
    collection_name="my_collection",
    filter=filter_str,
    output_fields=["varchar_field1", "varchar_field2"],
)

print(res)
print("###############################")
# 检索 varchar_field2 为空的实体
filter_str = "varchar_field2 is null"  # 此处不能使用 == 只能使用 is
res = client.query(
    collection_name="my_collection",
    filter=filter_str,
    output_fields=["varchar_field1", "varchar_field2"],
)
print(res)
print("################################")
# 检索 varchar_field1 为 Unknow
# 由于varchar_field1 的默认值是"Unknown" ,因此预期结果应包括将varchar_field1 明确设置为"Unknown" 或将varchar_field1 设置为空的实体。
filter_str = "varchar_field1 == 'Unknown'"  # 查找指定的字符串的时候需要加上 引号的字符串的限制
res = client.query(
    collection_name="my_collection",
    filter=filter_str,
    output_fields=["varchar_field1", "varchar_field2"]
)
print(res)
print("##################################")
# 除了基本的标量字段筛选外,您还可以将向量相似性搜索与标量字段筛选结合起来。
filter_str = "varchar_field2 == 'Best seller'"
res = client.query(
    collection_name="my_collection",
    data=[[0.3, -0.6, 0.1]],
    limit=5,
    search_params={"params":{"nprobe": 10}},  # 内积形式的检索, 速度与准确度的指标范围 1 - 10
    output_fields=["varchar_field1", "varchar_field2"],
    filter=filter_str
)

print(res)
print("###################################")

image-20260402110439035

4.4 数字字段

数字字段时一种存储数值的标量字段。这些数值可以是整数或者十进制数浮点数。他们通常用于表示数量、测量值或任何需要进行数学处理的数据。

4.4.1 添加数字字段

要存储数值数据,请在 Collections Schema 中定义一个数字字段。

# !/usr/bin/env python
# -*-coding:utf-8 -*-

"""
@File    : 2.py
@Time    : 2026/4/2 11:18
@Author  : zi qing bao jian
@Version : 1.0
@Desc    : 避免表名的冲突;
"""
from pymilvus import MilvusClient, DataType

SERVER_ADDR = "http://192.168.159.133:19530"

client = MilvusClient(uri=SERVER_ADDR)

schema = client.create_schema(
    auto_id=False,
    enable_dynamic_fields=True,
)

# 添加存储整数的字段, 设置默认值为 18
schema.add_field(field_name="age", datatype=DataType.INT64, nullable=True, default_value=18)
# 存储浮点数据, 允许为空, 没有默认值
schema.add_field(field_name="price", datatype=DataType.FLOAT, nullable=True)
schema.add_field(field_name="pk", datatype=DataType.INT64, is_primary=True)
schema.add_field(field_name="embedding", datatype=DataType.FLOAT_VECTOR, dim=3)

# 设置索引参数: 对于向量字段必须建立索引,但对于标量字段可选。
# 使用AUTOINDEX 索引类型为向量字段embedding 和标量字段age 创建了索引;
# 使用这种类型,Milvus 会根据数据类型自动选择最合适的索引。您还可以自定义每个字段的索引类型和参数。

index_params = client.prepare_index_params()

index_params.add_index(
    field_name="age",
    index_type="AUTOINDEX",  # 自动索引, 会自动选择合适的索引;
    index_name="age_index"
)

index_params.add_index(
    field_name="embedding",
    index_type="AUTOINDEX",  # Use automatic indexing to simplify complex index settings
    metric_type="COSINE"  # Specify similarity metric type, options include L2, COSINE, or IP
)

# 插入数据;
client.create_collection(
    collection_name="my_collection_number",
    schema=schema,
    index_params=index_params
)
# 创建 Collections 后, 插入与 Schema 匹配的实体
data = [
    {"age": 25, "price": 99.99, "pk": 1, "embedding": [0.1, 0.2, 0.3]},
    {"age": 30, "pk": 2, "embedding": [0.4, 0.5, 0.6]},  # `price` field is missing, which should be null
    {"age": None, "price": None, "pk": 3, "embedding": [0.2, 0.3, 0.1]},  # `age` should default to 18, `price` is null
    {"age": 45, "price": None, "pk": 4, "embedding": [0.9, 0.1, 0.4]},  # `price` is null
    {"age": None, "price": 59.99, "pk": 5, "embedding": [0.8, 0.5, 0.3]},  # `age` should default to 18
    {"age": 60, "price": None, "pk": 6, "embedding": [0.1, 0.6, 0.9]}  # `price` is null
]

client.insert(
    collection_name="my_collection_number",
    data=data
)

4.4.2 检索

from pymilvus import MilvusClient, DataType

SERVER_ADDR = "http://192.168.159.133:19530"

client = MilvusClient(uri=SERVER_ADDR)

# 检索age 大于 30 的实体:
filter_str = 'age > 30'

res = client.query(
    collection_name="my_collection_number",
    filter=filter_str,  # 这里是过滤条件,标量
    output_fields=["age", "price", "pk"]
)

print(res)

# 除了基本的数字字段过滤外,您还可以将向量相似性搜索与数字字段过滤器结合起来

filter_str = "25 <= age <= 35"

res = client.search(
    collection_name="my_collection_number",
    data=[[0.3, -0.6, 0.1]],
    limit=5,
    search_params={"params": {"nprobe": 10}},
    output_fields=["age", "price"],
    filter=filter_str
)

print(res)

image-20260402112304187

4.5 Json 字段

在构建产品目录、内容管理系统或用户偏好引擎等应用程序时,您往往需要在存储向量 Embeddings 的同时存储灵活的元数据。产品属性因类别而异,用户偏好随时间演变,文档属性具有复杂的嵌套结构。Milvus 中的 JSON 字段解决了这一难题,允许您在不牺牲性能的情况下存储和查询灵活的结构化数据。
json 字段时 Milvus 中的一种 Schema 定义数据类型DataType.Json,用于存储结构化键值数据。与传统的刚性数据库列不同,json 字段可以容纳嵌套对象、数组和混合数据类型,同时提供多种索引选项,以实现快速查询。

{
  "metadata": { 
    "category": "electronics",
    "brand": "BrandA",
    "in_stock": true,
    "price": 99.99,
    "string_price": "99.99",
    "tags": ["clearance", "summer_sale"],
    "supplier": {
      "name": "SupplierX",
      "country": "USA",
      "contact": {
        "email": "support@supplierx.com",
        "phone": "+1-800-555-0199"
      }
    }
  }
}

在这个示例中,metadata 是一个单一的 JSON 字段,包含平面值(如category,in_stock )、数组 (tags) 和嵌套对象 (supplier) 的混合数据。

4.5.1 添加字段

要使用 JSON 字段,请在创建 Collection 时在模式 Schema 中明确定义该字段。下面的示例演示了如何创建一个带有metadata 类型字段DataType.JSON 的 Collections:

from pymilvus import MilvusClient, DataType
 
client = MilvusClient(uri="http://192.168.159.133:19530") # Replace with your server address 
 
schema = client.create_schema(auto_id=False, enable_dynamic_field=True)
 
schema.add_field(field_name="product_id", datatype=DataType.INT64, is_primary=True) # Primary field
schema.add_field(field_name="vector", datatype=DataType.FLOAT_VECTOR, dim=5) # Vector field
schema.add_field(field_name="metadata", datatype=DataType.JSON, nullable=True)
 
client.create_collection(
    collection_name="product_catalog",
    schema=schema
)

# 插入数据
# 创建 Collections 后,在指定的 JSON 字段中插入包含结构化 JSON 对象的实体。数据格式应为字典列表。
entities = [
    {
        "product_id": 1,
        "vector": [0.1, 0.2, 0.3, 0.4, 0.5],
        # highlight-start
        "metadata": { # JSON field
            "category": "electronics",
            "brand": "BrandA",
            "in_stock": True,
            "price": 99.99,
            "string_price": "99.99",
            "tags": ["clearance", "summer_sale"],
            "supplier": {
                "name": "SupplierX",
                "country": "USA",
                "contact": {
                    "email": "support@supplierx.com",
                    "phone": "+1-800-555-0199"
                }
            }
        }
        # highlight-end
    }
]
 
client.insert(collection_name="product_catalog", data=entities)

# 必须要创建索引
client.insert(collection_name="product_catalog", data=entities)

index_params = client.prepare_index_params()  # 在每个向量字段上创建了索引
index_params.add_index(
    field_name="vector",
    index_type="AUTOINDEX",
    index_name="vector_index",
    metric_type="COSINE"
)

# 创建索引;
client.create_index(collection_name="product_catalog", index_params=index_params)

client.load_collection(collection_name="product_catalog")  # 加载数据表, 加载到内存中;

4.5.2 检索

要查询特定键,请使用括号符访问 json 键:json_field_name["key"]。对于嵌套键,可将他们串联起来json_field_name["key"][key2]

要过滤category"electronics" 的实体:

filter = 'metadata["category"] == "electronics"'
 
client.search(
    collection_name="product_catalog",  # Collection name
    data=[[0.1, 0.2, 0.3, 0.4, 0.5]],               # Query vector (must match collection's vector dim)
    limit=5,                           # Max. number of results to return
    # highlight-next-line
    filter=filter,                    # Filter expression
    output_fields=["product_id", "metadata"]   # Fields to include in the search results
)

Milvus 还提供特殊操作符,用于查询特定 JSON 字段键上的数组值。例如

  • json_contains(identifier, expr):检查 JSON 数组中是否存在特定元素或子数组;
  • json_contains_all(identifier, expr):确保指定 JSON 表达式的所有元素都存在于字段中;
  • json_contains_any(identifier, expr):过滤字段中至少存在一个 JSON 表达式成员的实体;

查找tags 关键字下具有"summer_sale" 值的产品:

from pymilvus import MilvusClient, DataType

client = MilvusClient(uri="http://192.168.159.133:19530")  # Replace with your server address

filter_str = 'metadata["category"] == "electronics"'

res = client.search(
    collection_name="product_catalog",  # Collection name
    data=[[0.1, 0.2, 0.3, 0.4, 0.5]],  # Query vector (must match collection's vector dim)
    limit=5,  # Max. number of results to return
    # highlight-next-line
    filter=filter_str,  # Filter expression
    output_fields=["product_id", "metadata"]  # Fields to include in the search results
)

print(res)

print("=" * 50)
filter_str = 'json_contains(metadata["tags"], "summer_sale")'  # 检查 JSON 数组中是否存在特定元素或子数组

res = client.search(
    collection_name="product_catalog",  # Collection name
    data=[[0.1, 0.2, 0.3, 0.4, 0.5]],  # Query vector (must match collection's vector dim)
    limit=5,  # Max. number of results to return
    # highlight-next-line
    filter=filter_str,  # Filter expression
    output_fields=["product_id", "metadata"]  # Fields to include in the search results
)

print(res)
print("=" * 50)
# 查找在tags 关键字下至少有一个"electronics" 、"new" 或"clearance" 值的产品:
filter_str = 'json_contains_any(metadata["tags"], ["electronics", "new", "clearance"])'

res = client.search(
    collection_name="product_catalog",  # Collection name
    data=[[0.1, 0.2, 0.3, 0.4, 0.5]],  # Query vector (must match collection's vector dim)
    limit=5,  # Max. number of results to return
    # highlight-next-line
    filter=filter_str,  # Filter expression
    output_fields=["product_id", "metadata"]  # Fields to include in the search results
)

print(res)

image-20260402114515163

4.5.3 json 索引

json 字段为在 Milvus 中存储结构化元数据提供了一种灵活的方式。如果没有索引,对 json 字段的查询需要全 Collection 扫描;随着数据集的增长,扫描速度也会变慢。json 索引通过在 json 数据中创建索引来实现快速查询。

json 索引适用于:

  • 具有一致、已知键的结构化 Schema
  • 特定 json 路径上的等价和范围查询
  • 需要精确控制索引键的情况
  • 对目标查询进行高效存储加速

创建 json 索引时,需要指定

  • json 路径:要索引的数据的确切位置
  • 数据类型:如何解释和存储索引值
  • 可选类型转换:如果需要,在索引过程中转换数据
# 创建 Milvus 客户端所需的索引参数配置对象
index_params = MilvusClient.prepare_index_params()
 
# 为指定的 JSON 字段添加索引配置
index_params.add_index(
    field_name="<json_field_name>",  # JSON 类型字段的名称(集合中定义的字段名)
    index_type="AUTOINDEX",          # 索引类型,对于 JSON 字段必须为 "AUTOINDEX" 或 "INVERTED"
    index_name="<unique_index_name>", # 为此索引指定一个唯一名称,便于管理和识别
    params={
        # 指定 JSON 数据内部要建立索引的具体键路径(例如:("$.user.age"))
        "json_path": "<path_to_json_key>",
        
        # 指定该 JSON 键对应值在索引时应被解释为何种数据类型(如 "int64"、"string"、"double" 等)
        "json_cast_type": "<data_type>",
        
        # (可选)指定一个转换函数,在索引时将该键的值转换为目标类型(例如处理字符串转数字等)
        # "json_cast_function": "<cast_function>"
    }
)

创建 json 索引

from pymilvus import MilvusClient, DataType

client = MilvusClient(uri="http://192.168.159.133:19530")  # Replace with your server address

filter_str = 'metadata["category"] == "electronics"'


# 创建索引参数对象;
index_params = MilvusClient.prepare_index_params()

index_params.add_index(
    field_name="metadata",
    index_type="AUTOINDEX",
    index_name="category_index",
    params={
        "json_path": 'metadata["category"]',
        "json_caste_type": "varchar"
    }
)

index_params.add_index(
    field_name="metadata",
    # highlight-next-line
    index_type="AUTOINDEX",  # Must be set to AUTOINDEX or INVERTED for JSON path indexing
    index_name="email_index",  # Unique index name
    # highlight-start
    params={
        "json_path": 'metadata["supplier"]["contact"]["email"]',  # 索引嵌套索引
        "json_cast_type": "varchar"  # Data cast type
    }
    # highlight-end
)

# 索引时转换数据类型;
# 有时,数字数据会被错误地存储为字符串。使用STRING_TO_DOUBLE 转换功能进行正确转换和索引:
index_params.add_index(
    field_name="metadata",
    # highlight-next-line
    index_type="AUTOINDEX",  # Must be set to AUTOINDEX or INVERTED for JSON path indexing
    index_name="string_to_double_index",  # Unique index name
    params={
        "json_path": 'metadata["string_price"]',  # Path to the JSON key to be indexed
        "json_cast_type": "double",  # Data cast type
        # highlight-next-line
        "json_cast_function": "STRING_TO_DOUBLE"  # 进行转换数据类型;
    }
)
# 索引整个对象, 以便对其中的任何字段混进行查询. 使用 json_cast_type 时, 系统会自动
# 使 json 结构扁平化, 将嵌套对象转换为扁平路径,以实现高效索引
# 推断数据类型:根据每个值的内容自动将其归类为数值、字符串、布尔值或日期值
# 创建全面的覆盖范围:对象中的所有键和嵌套路径均可搜索

index_params.add_index(
    field_name="metadata",
    index_type="AUTOINDEX",
    index_name="metadata_full_index",
    params={
        # highlight-start
        "json_path": "metadata",  # 索引整个 metadata 对象
        "json_cast_type": "JSON"
        # highlight-end
    }
)

# 定义完索引的参数之后, 插入到 collections 中;
MilvusClient.create_index(
    collection_name="your_collection_name",
    index_params=index_params
)

5. 插入和删除数据

Collections 中的实体是指共享同一组字段的数据记录。每条数据记录中的字段值构成一个实体。本页介绍如何在 Collections 中插入实体。

添加字段:如果在创建 Collections 后动态添加新字段,并且在插入实体时没有为这些字段指定值,Milvus 会自动用定义的默认值填充它们,如果没有设置默认值,则填充 NULL。有关详细信息,请参阅向现有 Collections 添加字段

重复处理:标准insert 操作符不会检查主键是否重复。使用现有主键插入数据会创建具有相同键的新实体,从而导致数据重复和潜在的应用问题。要更新现有实体或避免重复,请使用 upsert操作符。有关详细信息,请参阅 "更新实体"。

5.1 实体添加

在插入数据之前,需要根据 Schema 将数据组织到字典列表中,每个字典代表一个实体,并包含 Schema 中定义的所有字段。如果 Collection 启用了动态字段,每个字典还可以包含 Schema 中未定义的字段。

以这种方式创建的 Collection 只有两个字段,分别名为id向量。此外,该 Collections 启用了动态字段,因此示例代码中的实体包含一个名为color的字段,该字段未在 Schema 中定义。

# !/usr/bin/env python
# -*-coding:utf-8 -*-

"""
@File    : 4.py
@Time    : 2026/4/3 11:09
@Author  : zi qing bao jian
@Version : 1.0
@Desc    : 
"""
from pymilvus import MilvusClient

client = MilvusClient(
    uri="http://192.168.159.133:19530",
)

# 先检查集合是否存在,不存在就创建
collection_name = "quick_setup"

# !!! 可以不创建 schema ,但是必须要有 collection
if not client.has_collection(collection_name):
    # 创建集合(向量维度 5,和你的数据一致)
    client.create_collection(
        collection_name=collection_name,
        dimension=5,  # 关键:你的 vector 长度是 5,必须写 5
        auto_id=False  # 因为你自己指定了 id
    )
    print(f"集合 {collection_name} 创建成功!")

data = [
    {"id": 0,
     "vector": [0.3580376395471989, -0.6023495712049978, 0.18414012509913835, -0.26286205330961354, 0.9029438446296592],
     "color": "pink_8682"},
    {"id": 1,
     "vector": [0.19886812562848388, 0.06023560599112088, 0.6976963061752597, 0.2614474506242501, 0.838729485096104],
     "color": "red_7025"},
    {"id": 2,
     "vector": [0.43742130801983836, -0.5597502546264526, 0.6457887650909682, 0.7894058910881185, 0.20785793220625592],
     "color": "orange_6781"},
    {"id": 3,
     "vector": [0.3172005263489739, 0.9719044792798428, -0.36981146090600725, -0.4860894583077995, 0.95791889146345],
     "color": "pink_9298"},
    {"id": 4,
     "vector": [0.4452349528804562, -0.8757026943054742, 0.8220779437047674, 0.46406290649483184, 0.30337481143159106],
     "color": "red_4794"},
    {"id": 5,
     "vector": [0.985825131989184, -0.8144651566660419, 0.6299267002202009, 0.1206906911183383, -0.1446277761879955],
     "color": "yellow_4222"},
    {"id": 6, "vector": [0.8371977790571115, -0.015764369584852833, -0.31062937026679327, -0.562666951622192,
                         -0.8984947637863987], "color": "red_9392"},
    {"id": 7,
     "vector": [-0.33445148015177995, -0.2567135004164067, 0.8987539745369246, 0.9402995886420709, 0.5378064918413052],
     "color": "grey_8510"},
    {"id": 8,
     "vector": [0.39524717779832685, 0.4000257286739164, -0.5890507376891594, -0.8650502298996872, -0.6140360785406336],
     "color": "white_9381"},
    {"id": 9, "vector": [0.5718280481994695, 0.24070317428066512, -0.3737913482606834, -0.06726932177492717,
                         -0.6980531615588608], "color": "purple_4976"}
]

res = client.insert(
    collection_name="quick_setup",
    data=data
)

print(res)

image-20260403111953883

将实体插入指定的分区,以下代码片段假定您的 Collections 中有一个名为PartitionA的分区。

data=[
    {"id": 10, "vector": [0.3580376395471989, -0.6023495712049978, 0.18414012509913835, -0.26286205330961354, 0.9029438446296592], "color": "pink_8682"},
    {"id": 11, "vector": [0.19886812562848388, 0.06023560599112088, 0.6976963061752597, 0.2614474506242501, 0.838729485096104], "color": "red_7025"},
    {"id": 12, "vector": [0.43742130801983836, -0.5597502546264526, 0.6457887650909682, 0.7894058910881185, 0.20785793220625592], "color": "orange_6781"},
    {"id": 13, "vector": [0.3172005263489739, 0.9719044792798428, -0.36981146090600725, -0.4860894583077995, 0.95791889146345], "color": "pink_9298"},
    {"id": 14, "vector": [0.4452349528804562, -0.8757026943054742, 0.8220779437047674, 0.46406290649483184, 0.30337481143159106], "color": "red_4794"},
    {"id": 15, "vector": [0.985825131989184, -0.8144651566660419, 0.6299267002202009, 0.1206906911183383, -0.1446277761879955], "color": "yellow_4222"},
    {"id": 16, "vector": [0.8371977790571115, -0.015764369584852833, -0.31062937026679327, -0.562666951622192, -0.8984947637863987], "color": "red_9392"},
    {"id": 17, "vector": [-0.33445148015177995, -0.2567135004164067, 0.8987539745369246, 0.9402995886420709, 0.5378064918413052], "color": "grey_8510"},
    {"id": 18, "vector": [0.39524717779832685, 0.4000257286739164, -0.5890507376891594, -0.8650502298996872, -0.6140360785406336], "color": "white_9381"},
    {"id": 19, "vector": [0.5718280481994695, 0.24070317428066512, -0.3737913482606834, -0.06726932177492717, -0.6980531615588608], "color": "purple_4976"}
]
 
res = client.insert(
    collection_name="quick_setup",
    # highlight-next-line
    partition_name="partitionA",
    data=data
)
 
print(res)
 

5.2 删除实体

通过筛选条件或主键删除不再需要的实体。

  • 条件筛选删除实体

    批量删除共享某些属性的多个实体时,可以使用过滤表达式。下面的示例代码使用in操作符批量删除了所有颜色字段设置为红色紫色的实体。你也可以使用其他操作符来构建符合你要求的过滤表达式。有关过滤表达式的更多信息,请参阅《过滤详解》

    from pymilvus import MilvusClient
     
    client = MilvusClient(
        uri="http://localhost:19530",
        token="root:Milvus"
    )
     
    res = client.delete(
        collection_name="quick_setup",
        # highlight-next-line
        filter="color in ['red_7025', 'purple_4976]"
    )
     
    print(res)
     
    
  • 主键删除实体

    在大多数情况下,主键唯一标识一个实体。你可以通过在删除请求中设置实体的主键来删除实体。下面的示例代码演示了如何删除主键为1819 的两个实体。

    res = client.delete(
        collection_name="quick_setup",
        # highlight-next-line
        ids=[18, 19]
    )
     
    print(res)
    
    
  • 分区删除实体

    您还可以删除存储在特定分区中的实体。以下代码片段假定您的 Collection 中有一个名为PartitionA的分区。

    res = client.delete(
        collection_name="quick_setup",
        ids=[18, 19],
        partition_name="partitionA"
    )
     
    print(res)
    
    

6. 搜索

向量搜索是 RAG 中的 retrieval 核心,把用户 query 转 embedding 后 search, 拿到最相似的文档喂给LLM。

近似近邻搜索以记录向量嵌入排序顺序的索引文件为基础,根据接收到的搜索请求中的查询向量查找向量嵌入子集,将查询向量与子群中的向量进行比较,并返回最相似的结果。通过 ANN 搜索,Milvus 提供了高效的检索体验,

ANN 搜索依赖于预建索引,搜索吞吐量、内存使用量和搜索正确性可能会因选择的索引类型而不同。您需要在搜索性能和正确性之间取得平衡。

6.1 单向量搜素

在 ANN 搜索中,单向量搜索值得是只涉及一个查询向量的搜索。根据预建索引和搜索请求中携带的度量类型,Milvus 将找到与查询向量最相似的前 K 个向量。搜索请求携带单个查询向量,要求 Milvus 使用内积(IP)计算查询向量与 Collections 中向量的相似度,并返回三个最相似的向量。

from pymilvus import MilvusClient
 
client = MilvusClient(
    uri="http://localhost:19530",
    token="root:Milvus"
)
 
query_vector = [0.3580376395471989, -0.6023495712049978, 0.18414012509913835, -0.26286205330961354, 0.9029438446296592]
res = client.search(
    collection_name="quick_setup",
    anns_field="vector",
    data=[query_vector],
    limit=3,
    search_params={"metric_type": "IP"}
)
 
for hits in res:
    for hit in hits:
        print(hit)
 

6.2 过滤搜索

ANN 搜索能找到与指定向量嵌入最相似的向量嵌入。但是,搜索结果不一定总是正确的。您可以在搜索请求中包含过滤条件,这样 Milvus 就会在进行 ANN 搜索前进行元数据过滤,将搜索范围从整个 Collections 缩小到只搜索符合指定过滤条件的实体。

img

from pymilvus import MilvusClient
 
client = MilvusClient(
    uri="http://localhost:19530",
    token="root:Milvus"
)
 
query_vector = [0.3580376395471989, -0.6023495712049978, 0.18414012509913835, -0.26286205330961354, 0.9029438446296592]
 
res = client.search(
    collection_name="my_collection",
    data=[query_vector],
    limit=5,
    # highlight-start
    filter='color like "red%" and likes > 50',
    output_fields=["color", "likes"]
    # highlight-end
)
 
for hits in res:
    print("TopK results:")
    for hit in hits:
        print(hit)

6.3 范围搜索

范围搜索可将返回实体的距离或得分限制在特定范围内,从而提高搜索结果的相关性

img

上图显示,范围搜索请求包含两个参数:半径和 range_filter。收到范围搜索请求后,Milvus 会执行以下操作:

  • 使用指定的度量类型(COSINE)查找与查询向量最相似的所有向量嵌入。
  • 过滤与查询向量的距离得分在半径和 range_filter 参数指定范围内的向量嵌入。
  • 从筛选出的实体中返回前 K个实体。
from pymilvus import MilvusClient
 
client = MilvusClient(
    uri="http://localhost:19530",
    token="root:Milvus"
)
 
query_vector = [0.3580376395471989, -0.6023495712049978, 0.18414012509913835, -0.26286205330961354, 0.9029438446296592]
 
res = client.search(
    collection_name="my_collection",
    data=[query_vector],
    limit=3,
    search_params={
        # highlight-start
        "params": {
            "radius": 0.4,
            "range_filter": 0.6
        }
        # highlight-end
    }
)
 
for hits in res:
    print("TopK results:")
    for hit in hits:
        print(hit)

6.4 分组搜索

分组搜索允许 Milvus 根据指定字段的值对搜索结果进行分组,以便在更高层次上汇总数据。例如,您可以使用基本的 ANN 搜索来查找与手头的图书相似的图书,但也可以使用分组搜索来查找可能涉及该图书所讨论主题的图书类别。

当搜索结果中的实体在标量字段中共享相同值时,这表明它们在特定属性上相似,这可能会对搜索结果产生负面影响。

假设一个 Collections 存储了多个文档(用docId 表示)。在将文档转换成向量时,为了尽可能多地保留语义信息,每份文档都会被分割成更小的、易于管理的段落(或块),并作为单独的实体存储。即使文档被分割成较小的段落,用户通常仍希望识别哪些文档与他们的需求最相关。
img

在搜索请求中,将group_by_fieldoutput_fields 都设置为docId 。Milvus 将根据指定字段对结果进行分组,并从每个分组中返回最相似的实体,包括每个返回实体的docId 值。

from pymilvus import MilvusClient
 
# 向量库
[
        {"id": 0, "vector": [0.3580376395471989, -0.6023495712049978, 0.18414012509913835, -0.26286205330961354, 0.9029438446296592], "chunk": "pink_8682", "docId": 1},
        {"id": 1, "vector": [0.19886812562848388, 0.06023560599112088, 0.6976963061752597, 0.2614474506242501, 0.838729485096104], "chunk": "red_7025", "docId": 5},
        {"id": 2, "vector": [0.43742130801983836, -0.5597502546264526, 0.6457887650909682, 0.7894058910881185, 0.20785793220625592], "chunk": "orange_6781", "docId": 2},
        {"id": 3, "vector": [0.3172005263489739, 0.9719044792798428, -0.36981146090600725, -0.4860894583077995, 0.95791889146345], "chunk": "pink_9298", "docId": 3},
        {"id": 4, "vector": [0.4452349528804562, -0.8757026943054742, 0.8220779437047674, 0.46406290649483184, 0.30337481143159106], "chunk": "red_4794", "docId": 3},
        {"id": 5, "vector": [0.985825131989184, -0.8144651566660419, 0.6299267002202009, 0.1206906911183383, -0.1446277761879955], "chunk": "yellow_4222", "docId": 4},
        {"id": 6, "vector": [0.8371977790571115, -0.015764369584852833, -0.31062937026679327, -0.562666951622192, -0.8984947637863987], "chunk": "red_9392", "docId": 1},
        {"id": 7, "vector": [-0.33445148015177995, -0.2567135004164067, 0.8987539745369246, 0.9402995886420709, 0.5378064918413052], "chunk": "grey_8510", "docId": 2},
        {"id": 8, "vector": [0.39524717779832685, 0.4000257286739164, -0.5890507376891594, -0.8650502298996872, -0.6140360785406336], "chunk": "white_9381", "docId": 5},
        {"id": 9, "vector": [0.5718280481994695, 0.24070317428066512, -0.3737913482606834, -0.06726932177492717, -0.6980531615588608], "chunk": "purple_4976", "docId": 3},
]
 

client = MilvusClient(
    uri="http://localhost:19530",
    token="root:Milvus"
)
 
query_vectors = [
    [0.14529211512077012, 0.9147257273453546, 0.7965055218724449, 0.7009258593102812, 0.5605206522382088]]
 
res = client.search(
    collection_name="my_collection",
    data=query_vectors,
    limit=3,
    group_by_field="docId",
    output_fields=["docId"]
)
 
doc_ids = [result['entity']['docId'] for result in res[0]]

在上面的请求中,limit=3 表示系统将从三个组中返回搜索结果,每个组都包含与查询向量最相似的单个实体。

6.5 混合搜索

在许多应用中,可以通过标题和描述等丰富的信息集或文本、图像和音频等多种模式来搜索对象。例如,如果文本或图片与搜索查询的语义相符,就可以搜索包含一段文本和一张图片的推文。混合搜索将这些不同领域的搜索结合在一起,从而增强了搜索体验。Milvus 允许在多个向量场上进行搜索,同时进行多个近似近邻(ANN)搜索,从而支持这种搜索。如果要同时搜索文本和图像、描述同一对象的多个文本字段或密集和稀疏向量以提高搜索质量,多向量混合搜索尤其有用。
img

让我们考虑一个真实世界的使用案例,其中每个产品都包含文字描述和图片。根据可用数据,我们可以进行三种类型的搜索:

  • 语义文本搜索:这涉及使用密集向量查询产品的文本描述。可以使用BERTTransformers等模型或OpenAI 等服务生成文本嵌入。
  • 全文搜索:在这里,我们使用稀疏向量的关键词匹配来查询产品的文本描述。BM25等算法或BGE-M3SPLADE等稀疏嵌入模型可用于此目的。
  • 多模态图像搜索:这种方法使用带有密集向量的文本查询对图像进行查询。可以使用CLIP 等模型生成图像嵌入。

本指南将引导您通过一个结合上述搜索方法的多模态混合搜索示例,给出产品的原始文本描述和图像嵌入。我们将演示如何存储多向量数据并使用 Rerankers 策略执行混合搜索。

创建具有多个向量场的 Collections

此示例将以下字段纳入 Schema 模式:

  • id:作为存储文本 ID 的主键。该字段的数据类型为INT64 。

  • text:用于存储文本内容。该字段的数据类型为VARCHAR ,最大长度为 1000 字节。enable_analyzer 选项设置为True ,以便于全文检索。

  • text_dense:用于存储文本的密集向量。该字段的数据类型为FLOAT_VECTOR ,向量维数为 768。

  • text_sparse:用于存储文本的稀疏向量。该字段的数据类型为SPARSE_FLOAT_VECTOR 。

  • image_dense:用于存储产品图像的密集向量。该字段的数据类型为FLOAT_VETOR ,向量维数为 512。

from pymilvus import (
    MilvusClient, DataType, Function, FunctionType
)
 
client = MilvusClient(
    uri="http://localhost:19530",
    token="root:Milvus"
)
 
schema = client.create_schema(auto_id=False)
 
schema.add_field(field_name="id", datatype=DataType.INT64, is_primary=True, description="product id")
schema.add_field(field_name="text", datatype=DataType.VARCHAR, max_length=1000, enable_analyzer=True, description="raw text of product description")
schema.add_field(field_name="text_dense", datatype=DataType.FLOAT_VECTOR, dim=768, description="text dense embedding")
schema.add_field(field_name="text_sparse", datatype=DataType.SPARSE_FLOAT_VECTOR, description="text sparse embedding auto-generated by the built-in BM25 function")
schema.add_field(field_name="image_dense", datatype=DataType.FLOAT_VECTOR, dim=512, description="image dense embedding")
 
bm25_function = Function(
    name="text_bm25_emb",
    input_field_names=["text"],
    output_field_names=["text_sparse"],
    function_type=FunctionType.BM25,
)
schema.add_function(bm25_function)

7. 查询

除 ANN 搜索外,Milvus 还支持通过查询过滤元数据。

Collections 可以存储各种类型的标量字段,你可以让 Milvus 根据一个或多个标量字段过滤实体。Milvus 提供三种类型的查询:查询、获取和查询迭代器。下表比较了这三种查询类型。

7.1 获取

当需要通过主键查找实体时,可以使用Get方法。以下代码示例假定在 Collections 中有三个字段,分别名为idvectorcolor

[
        {"id": 0, "vector": [0.3580376395471989, -0.6023495712049978, 0.18414012509913835, -0.26286205330961354, 0.9029438446296592], "color": "pink_8682"},
        {"id": 1, "vector": [0.19886812562848388, 0.06023560599112088, 0.6976963061752597, 0.2614474506242501, 0.838729485096104], "color": "red_7025"},
        {"id": 2, "vector": [0.43742130801983836, -0.5597502546264526, 0.6457887650909682, 0.7894058910881185, 0.20785793220625592], "color": "orange_6781"},
        {"id": 3, "vector": [0.3172005263489739, 0.9719044792798428, -0.36981146090600725, -0.4860894583077995, 0.95791889146345], "color": "pink_9298"},
        {"id": 4, "vector": [0.4452349528804562, -0.8757026943054742, 0.8220779437047674, 0.46406290649483184, 0.30337481143159106], "color": "red_4794"},
        {"id": 5, "vector": [0.985825131989184, -0.8144651566660419, 0.6299267002202009, 0.1206906911183383, -0.1446277761879955], "color": "yellow_4222"},
        {"id": 6, "vector": [0.8371977790571115, -0.015764369584852833, -0.31062937026679327, -0.562666951622192, -0.8984947637863987], "color": "red_9392"},
        {"id": 7, "vector": [-0.33445148015177995, -0.2567135004164067, 0.8987539745369246, 0.9402995886420709, 0.5378064918413052], "color": "grey_8510"},
        {"id": 8, "vector": [0.39524717779832685, 0.4000257286739164, -0.5890507376891594, -0.8650502298996872, -0.6140360785406336], "color": "white_9381"},
        {"id": 9, "vector": [0.5718280481994695, 0.24070317428066512, -0.3737913482606834, -0.06726932177492717, -0.6980531615588608], "color": "purple_4976"},
]


from pymilvus import MilvusClient
 
client = MilvusClient(
    uri="http://192.168.159.133:19530",
)
 
res = client.get(
    collection_name="my_collection",
    ids=[0, 1, 2],
    output_fields=["vector", "color"]
)
 
print(res)

8.2 查询

当您需要通过自定义过滤条件查找实体时,请使用Query方法。以下代码示例假定有三个字段,分别名为idvectorcolor ,并返回从red 开始持有color 值的实体的指定数目。

from pymilvus import MilvusClient
 
client = MilvusClient(
    uri="http://localhost:19530",
    token="root:Milvus"
)
 
res = client.query(
    collection_name="my_collection",
    filter="color like \"red%\"",
    output_fields=["vector", "color"],
    limit=3
)

分区中的查询,可以通过在 Get、Query 或 QueryIterator 请求中包含分区名称,在一个或多个分区中执行查询。以下代码示例假定 Collections 中有一个名为PartitionA的分区。

from pymilvus import MilvusClient
client = MilvusClient(
    uri="http://localhost:19530",
    token="root:Milvus"
)
 
res = client.get(
    collection_name="my_collection",
    # highlight-next-line
    partitionNames=["partitionA"],
    ids=[10, 11, 12],
    output_fields=["vector", "color"]
)
 
from pymilvus import MilvusClient
 
client = MilvusClient(
    uri="http://localhost:19530",
    token="root:Milvus"
)
 
res = client.query(
    collection_name="my_collection",
    # highlight-next-line
    partitionNames=["partitionA"],
    filter="color like \"red%\"",
    output_fields=["vector", "color"],
    limit=3
)
 
from pymilvus import connections, Collection
 
connections.connect(
    uri="http://localhost:19530",
    token="root:Milvus"
)
 
collection = Collection("my_collection")
 
iterator = collection.query_iterator(
    # highlight-next-line
    partition_names=["partitionA"],
    batch_size=10,
    expr="color like \"red%\"",
    output_fields=["color"]
)
 
results = []
 
while True:
    result = iterator.next()
    if not result:
        iterator.close()
        break
 
    print(result)
    results += result

8. 过滤

Milvus 提供强大的过滤功能,可精确查询数据。过滤表达式允许你针对特定的标量字段,用不同的条件细化搜索结果。

Milvus 支持几种用于过滤数据的基本操作符:

  • 比较操作符:==!==><>=<=允许基于数字或文本字段进行筛选。

  • 范围过滤:IN 和 LIKE 可帮助匹配特定的值范围或集合。

  • 算数运算符:+,-,*,/,%, 和** 用于涉及数字字段的计算。

  • 逻辑操作符AND,OR, 和NOT 将多个条件组合成复杂的表达式。

  • IS NULL 和 IS NOT NULL 操作符IS NULLIS NOT NULL 操作符用于根据字段是否包含空值(无数据)来筛选字段。有关详细信息,请参阅基本操作符

要在标量字段 Color 中查找具有三原色(红绿蓝)的实体,可以使用以下的表达式

filter='color' in ['red', 'green', 'blue']

Milvus 允许在 JSON 字段中引用键。例如,如果您有一个带有键pricemodel 的 JSON 字段product ,并想查找具有特定模型且价格低于 1,850 的产品,请使用此过滤表达式:

filter='product["model"] == "JSN-087" AND product["price"] < 1850'

如果有一个数组字段history_temperatures ,其中包含自 2000 年以来各观测站报告的平均气温记录,要查找 2009 年(第 10 次记录)气温超过 23°C 的观测站,请使用此表达式:

filter='history_temperatures[10] > 23'

9. 全文搜索

全文搜索是一种在文本数据集中检索包含特定术语或短语的文档,然后后根据相关性对结果进行排序的功能。该功能克服了雨衣搜索的局限性,确保获取到最准确且与上下文最相关的结果。此外还通过接受原始文本输入来简化向量搜索,自动将文本转换为系数嵌入,无需手动生成向量嵌入;

该功能使用 BM25 算法进行相关性评分,在检索增强生成(RAG)场景中尤为重要,他能优先处理与特定搜索词密切匹配的文档。

Milvus 的全文搜索工作流程:

  1. 原始文本输入:插入文本文档或使用纯文本提供查询,无需嵌入模型。
  2. 文本分析:Milvus 使用分析器将文本处理成可索引和搜索有意义术语。
  3. BM25 函数处理:一个内置函数可将这些术语转换成为针对 BM25 评分优化的系数向量表示。
  4. Collections 存储:Milvus 将生成的稀疏嵌入存储在一个 Collections 中,以便快速检索和排序。
  5. BM25 相关性评分:在搜索时,Milvus 应用 BM25 评分函数计算文档相关性,并返回与查询词最匹配的排序结果。

img

要使用全文搜索,请遵循以下主要步骤:

  1. 创建 Collections:设置所需字段并定义 BM25 函数,将原始文本转换为稀疏嵌入。
  2. 插入数据:将原始文本文档输入 Collections。
  3. 执行搜索:使用自然语言查询文本,根据 BM25 相关性检索排序结果。

要启用 BM25 支持的全文搜索,您必须准备一个包含所需字段的 Collections,定义一个 BM25 函数来生成稀疏向量,配置索引,然后创建 Collections。

您的 Collections Schema 必须包含至少三个必填字段:

  • 主字段:唯一标识 Collections 中的每个实体。
  • 文本字段:存储原始文本文档。必须设置enable_analyzer=True,以便 Milvus 处理文本,进行 BM25 相关性排序,默认情况下, Milvus 使用 standard 分析器进行文本分析。
  • 稀疏向量场:存储由 BM25 函数自动生成的稀疏嵌入。
# !/usr/bin/env python
# -*-coding:utf-8 -*-

"""
@File    : 6.py
@Time    : 2026/4/9 14:53
@Author  : zi qing bao jian
@Version : 1.0
@Desc    : 全文搜索;
"""

from pymilvus import MilvusClient, DataType, FunctionType, Function

client = MilvusClient(
    uri="http://192.168.159.133:19530"
)

schema = client.create_schema()

# 作为主键,由auto_id=True 自动生成。
schema.add_field(field_name="id", datatype=DataType.INT64, is_primary=True, auto_id=True)  # Primary field
# text:存储原始文本数据,用于全文搜索操作符。数据类型必须是VARCHAR ,因为VARCHAR 是用于文本存储的 Milvus 字符串数据类型。
schema.add_field(field_name="text", datatype=DataType.VARCHAR, max_length=1000, enable_analyzer=True)  # Text field
# sparse:一个向量字段,用于存储内部生成的稀疏嵌入,以进行全文搜索操作。数据类型必须是SPARSE_FLOAT_VECTOR 。
schema.add_field(field_name="sparse",
                 datatype=DataType.SPARSE_FLOAT_VECTOR)  # Sparse vector field; no dim required for sparse vectors

# 定义BM25 函数;
# BM25 函数将标记化文本转换为支持 BM25 评分的稀疏向量。
bm25_function = Function(
    name="text_bm25_emb",  # 函数名称, 该函数将 text 字段中的原始文本转换为兼容 BM25 兼容的稀疏向量, 这些稀疏向量将存储在 sparse 字段中。
    input_field_names=["text"],  # 需要将文本转换为稀疏向量的VARCHAR 字段的名称。对于FunctionType.BM25 ,该参数只接受一个字段名称。
    output_field_names=["sparse"],  # 存储内部生成的稀疏向量的字段名称。对于FunctionType.BM25 ,该参数只接受一个字段名称
    function_type=FunctionType.BM25  # 要使用的函数类型。必须为FunctionType.BM25 。
)
# 绑定函数
schema.add_function(bm25_function)

# 配置索引, 在定义包含必要字段和内置函数的 Schema 后
index_params = client.prepare_index_params()
index_params.add_index(
    field_name='sparse',
    index_type='SPARSE_INVERTED_INDEX',
    metric_type='BM25',
    params={
        'inverted_index_algo': 'DAAT_MAXSCORE',
        'bm25_k1': 1.2,
        'bm25_b': 0.75
    }
)

# 插入文本数据
client.create_collection(
    collection_name='my_collection_0409',
    schema=schema,
    index_params=index_params
)
# 设置好集合和索引后, 插入文本数据;只需提供原始文本。我们之前定义的内置函数会为每个文本条目自动生成相应的稀疏向量。
client.insert('my_collection_0409', [
    {'text': 'information retrieval is a field of study.'},
    {'text': 'information retrieval focuses on finding relevant information in large datasets.'},
    {'text': 'data mining and information retrieval overlap in research.'}
])

# 执行全文的搜索;将数据插入 Collections 后, 就可以使用原始文本查询执行全文检索了, Milvus 会自动将查询转换为稀疏向量, 并使用 BM25 算法对匹配的搜索结果进行排序, 然后返回 topK 结果
search_params = {
    "params": {'drop_ratio_search': 0.2}
}

res = client.search(
    collection_name='my_collection_0409',
    data=['information'],
    anns_field='sparse',
    output_fields=['text'],
    limit=3,
    search_params=search_params
)

print(res)

image-20260409152340340

10. 文本匹配

文本匹配适用于VARCHAR 字段类型,它本质上是 Milvus 中的字符串数据类型。要启用文本匹配,请将enable_analyzer 和enable_match 都设置为True ,然后在定义 Collections Schema 时选择性地配置分析器进行文本分析。

要启用特定VARCHAR 字段的文本匹配,请在定义字段 Schema 时将enable_analyzer 和enable_match 参数设置为True 。这将指示 Milvus 对文本进行标记化处理,并为指定字段创建反向索引,从而实现快速高效的文本匹配。
可选:配置分析器

关键词匹配的性能和准确性取决于所选的分析器。不同的分析器适用于不同的语言和文本结构,因此选择正确的分析器会极大地影响特定用例的搜索结果。

默认情况下,Milvus 使用standard 分析器,该分析器根据空白和标点符号对文本进行标记,删除长度超过 40 个字符的标记,并将文本转换为小写。应用此默认设置无需额外参数。更多信息,请参阅标准。

如果需要不同的分析器,可以使用analyzer_params 参数进行配置。例如,应用english 分析器处理英文文本:

from pymilvus import MilvusClient, DataType
 
schema = MilvusClient.create_schema(enable_dynamic_field=False)
schema.add_field(
    field_name="id",
    datatype=DataType.INT64,
    is_primary=True,
    auto_id=True
)
schema.add_field(
    field_name='text', 
    datatype=DataType.VARCHAR, 
    max_length=1000, 
    # 设置两个参数为 True
    enable_analyzer=True, # Whether to enable text analysis for this field
    enable_match=True # Whether to enable text match
)
schema.add_field(
    field_name="embeddings",
    datatype=DataType.FLOAT_VECTOR,
    dim=5
)

# 设置英文的分词器, 默认是 standard
analyzer_params = {
    "type": "english"
}

schema.add_field(
    field_name='text',
    datatype=DataType.VARCHAR,
    max_length=200,
    enable_analyzer=True,
    analyzer_params = analyzer_params,
    enable_match = True,
)

为 Collections Schema 中的 VARCHAR 字段启用文本匹配后,就可以使用TEXT_MATCH 表达式执行文本匹配。

# TEXT_MATCH 表达式用于指定要搜索的字段和术语。其语法如下:
TEXT_MATCH(field_name, text)
  • field_name:要搜索的 VARCHAR 字段的名称。
  • text:要搜索的术语。根据语言和配置的分析器,多个术语可以用空格或其他适当的分隔符分隔。

默认情况下,TEXT_MATCH 使用OR匹配逻辑,这意味着它会返回包含任何指定术语的文档。例如,要搜索text 字段中包含machinedeep 的文档,请使用以下表达式:

filter = "TEXT_MATCH(text, 'machine deep')"
# 还可以使用逻辑操作符组合多个TEXT_MATCH 表达式来执行AND匹配。
# 例: 要搜索text 字段中同时包含machine 和deep 的文档,请使用以下表达式
filter = "TEXT_MATCH(text, 'machine') and TEXT_MATCH(text, 'deep')"
# 要搜索text 字段中同时包含machine 和learning 但不包含deep 的文档,请使用以下表达式:
filter = "not TEXT_MATCH(text, 'deep') and TEXT_MATCH(text, 'machine') and TEXT_MATCH(text, 'learning')"

文本匹配可与向量相似性搜索结合使用,以缩小搜索范围并提高搜索性能。通过在向量相似性搜索前使用文本匹配过滤 Collections,可以减少需要搜索的文档数量,从而加快查询速度。

在这个示例中,filter 表达式过滤了搜索结果,使其只包含与指定术语keyword1 或keyword2 匹配的文档。然后在这个过滤后的文档子集中执行向量相似性搜索。

filter = "TEXT_MATCH(text, 'keyword1 keyword2')"
 
result = client.search(
    collection_name="my_collection", # Your collection name
    anns_field="embeddings", # Vector field name
    data=[query_vector], # Query vector
    filter=filter,
    search_params={"params": {"nprobe": 10}},
    limit=10, # Max. number of results to return
    output_fields=["id", "text"] # Fields to return
)

文本匹配也可用于查询操作中的标量过滤。通过在query() 方法的expr 参数中指定TEXT_MATCH 表达式,可以检索与给定术语匹配的文档。

下面的示例检索了text 字段包含keyword1keyword2 这两个术语的文档。

filter = "TEXT_MATCH(text, 'keyword1') and TEXT_MATCH(text, 'keyword2')"
 
result = client.query(
    collection_name="my_collection",
    filter=filter, 
    output_fields=["id", "text"]
)

为字段启用术语匹配会触发反向索引的创建,从而消耗存储资源。在决定是否启用此功能时,请考虑对存储的影响,因为它根据文本大小、唯一标记和所使用的分析器而有所不同。

在 Schema 中定义分析器后,其设置将永久适用于该 Collections。如果您认为不同的分析器更适合您的需要,您可以考虑删除现有的 Collections,然后使用所需的分析器配置创建一个新的 Collections。

filter 表达式中的转义规则:

表达式中用双引号或单引号括起来的字符被解释为字符串常量。如果字符串常量包含转义字符,则必须使用转义序列来表示转义字符。例如,用\ 表示\ ,用\t 表示制表符\t ,用\n 表示换行符。

如果字符串常量由单引号括起来,常量内的单引号应表示为\' ,而双引号可表示为" 或\" 。 示例:'It\'s milvus' 。

如果字符串常量由双引号括起来,常量中的双引号应表示为\" ,而单引号可表示为' 或\' 。 示例:"He said \"Hi\"" 。

11. 短语匹配

短语匹配可让您搜索包含精确短语查询词的文档。默认情况下,单词必须以相同的顺序出现,并且彼此直接相邻。例如,"机器人机器学习 "的查询会匹配"...典型的机器人机器学习模型... "这样的文本,其中"机器人"、 " 机器 "和"学习 "依次出现,中间没有其他词。

然而,在现实世界中,严格的短语匹配可能过于死板。您可能希望匹配的文本是"......机器人技术中广泛采用的机器学习模型......"。在这种情况下,相同的关键词会出现,但不会并排出现,也不会按照原来的顺序排列。为了处理这种情况,短语匹配支持一个slop 参数,从而增加了灵活性。slop 的值定义了短语中的词语之间允许多少次位置移动。例如,当slop 为 1 时,"机器学习 "查询可以匹配"......机器深度学习...... "这样的文本,其中一个单词("deep")分隔了原始术语。

短语匹配由Tantivy搜索引擎库提供支持,通过分析文档中单词的位置信息来实现。下图说明了这一过程:

Phrase Match Workflow

短语匹配工作流程:

  1. 文档标记化:将文档插入 Milvus 时,使用分析器将文本分割成标记(单个词或术语),并记录每个标记的位置信息。例如,doc_1被标记为["machine" (pos=0), "learning" (pos=1), "boosts" (pos=2), "efficiency" (pos=3)]。有关分析器的更多信息,请参阅分析器概述。
  2. 反向索引创建:Milvus 建立一个倒排索引,将每个标记映射到出现该标记的文档以及标记在这些文档中的位置。
  3. 短语匹配:当执行短语查询时,Milvus 会查找倒排索引中的每个标记,并检查它们的位置,以确定它们是否以正确的顺序和相邻关系出现。slop 参数控制匹配标记之间允许的最大位置数:
    • slop = 0表示词组必须以完全相同的顺序出现,并且紧邻(即中间没有多余的字)。
    • slop = 2允许匹配词之间最多有两个位置的灵活性或重新排列。

启用短语匹配

短语匹配适用于VARCHAR 字段类型,即 Milvus 中的字符串数据类型。要启用短语匹配,请配置您的 Collections Schema,将enable_analyzer 和enable_match 参数都设置为True ,类似于文本匹配。

设置enable_analyzer 和enable_match

要启用特定VARCHAR 字段的短语匹配,请在定义字段 Schema 时将enable_analyzer 和enable_match 参数设置为True 。该配置指示 Milvus 对文本进行标记化,并创建一个具有位置信息的反向索引,以实现高效的短语匹配。

from pymilvus import MilvusClient, DataType
 
schema = MilvusClient.create_schema(enable_dynamic_field=False)
schema.add_field(
    field_name="id",
    datatype=DataType.INT64,
    is_primary=True,
    auto_id=True
)
schema.add_field(
    field_name='text',                 # Name of the field
    datatype=DataType.VARCHAR,         # Field data type set as VARCHAR (string)
    max_length=1000,                   # Maximum length of the string
    enable_analyzer=True,              # Enables text analysis (tokenization)
    enable_match=True                  # Enables inverted indexing for phrase matching
)
schema.add_field(
    field_name="embeddings",
    datatype=DataType.FLOAT_VECTOR,
    dim=5
)
analyzer_params = {
    "type": "english"
}
 
schema.add_field(
    field_name='text',                 # Name of the field
    datatype=DataType.VARCHAR,         # Field data type set as VARCHAR
    max_length=1000,                   # Maximum length of the string
    enable_analyzer=True,              # Enables text analysis
    analyzer_params=analyzer_params,   # Specifies the analyzer configuration
    enable_match=True                  # Enables inverted indexing for phrase matching
)

短语匹配的使用

为 Collections Schema 中的VARCHAR 字段启用匹配后,就可以使用PHRASE_MATCH 表达式执行短语匹配。

PHRASE_MATCH 表达式不区分大小写。可以使用PHRASE_MATCH 或phrase_match 。

搜索时,使用PHRASE_MATCH 表达式指定字段、短语和可选的灵活性 (slop)。语法如下

PHRASE_MATCH(field_name, phrase, slop)

field_name:执行短语匹配的VARCHAR 字段名称。

phrase:要搜索的确切短语。

slop (可选):一个整数,指定匹配标记中允许的最大位置数。

0 (默认):只匹配精确短语。例如机器学习 "过滤器将精确匹配" machine learning",但不匹配"machine boosts learning "或"learning machine"。

1:允许细微变化,例如多一个词或位置上的细微变化。例如机器学习 "过滤器将匹配"machine boosts learning"("machine "和"learning "之间有一个标记),但不匹配"learning machine"(术语颠倒)。

2:允许更多的灵活性,包括术语顺序颠倒或最多在两个词组之间。例如机器学习 "过滤器将匹配"学习机器"(词序颠倒)或"机器快速促进学习"("机器 "和"学习 "之间有两个词组)。
假设您有一个名为tech_articles 的Collections,其中包含以下五个实体:

doc_id text
1 "机器学习提高了大规模数据分析的效率
2 "学习基于机器的方法对现代人工智能的发展至关重要" 3
3 "深度学习机器架构优化了计算负荷"
4 "机器迅速提高持续学习的模型性能"
5 "学习先进的机器算法,扩展人工智能能力

使用query() 方法时,PHRASE_MATCH 充当标量过滤器。只有包含指定短语的文档才会返回(取决于允许的斜率)。

示例:slop = 0(精确匹配)

此示例返回包含精确短语"machine learning "的文档,中间不包含任何额外标记。

filter = "PHRASE_MATCH(text, 'machine learning')"
 
result = client.query(
    collection_name="tech_articles",
    filter=filter,
    output_fields=["id", "text"]
)

img

使用短语匹配进行搜索

在搜索操作中,PHRASE_MATCH用于在应用向量相似性排序之前过滤文档。这种两步法首先通过文本匹配缩小候选集的范围,然后根据向量嵌入重新对这些候选集进行排序。

示例:斜率 = 1

这里,我们允许斜率为 1。该过滤器适用于包含"学习机 "短语的文档,并略有灵活性。

filter_slop1 = "PHRASE_MATCH(text, 'learning machine', 1)"
 
result_slop1 = client.search(
    collection_name="tech_articles",
    anns_field="embeddings",
    data=[query_vector],
    filter=filter_slop1,
    search_params={"params": {"nprobe": 10}},
    limit=10,
    output_fields=["id", "text"]
)

12. WEBUI

参考:https://blog.csdn.net/qq_58602552/article/details/156612460

image-20260409154714925

13. 数据导入

少量数据的到如使用编程的语言进行导入;

from pymilvus.bulk_writer import RemoteBulkWriter, BulkFileType
import json

writer = RemoteBulkWriter(
    schema=your_collection_schema,
    remote_path="your_minio_bucket/path",  # MinIO / S3 等对象存储
    file_type=BulkFileType.PARQUET
)

# 写入数据(可分批)
for batch in your_data_batches:
    writer.append_rows(batch)  # batch 是 list of dict

writer.commit()
print("文件生成完成,可上传到 MinIO")

使用可视化的工具进行数据的导入

将需要的数据导出

image-20260409160155010

image-20260409160103082

image-20260409160306443

image-20260409160317980

继续努力,终成大器!

posted @ 2026-04-09 16:05  紫青宝剑  阅读(6)  评论(0)    收藏  举报