milvus的使用
Milvus的使用
先抛出一段代码,用的是python sdk,然后我们再逐个分析
from pymilvus import (
connections,
utility,
FieldSchema,
CollectionSchema,
DataType,
Collection,
)
import random
# 1. 连接服务
# 连接到本地运行的 Milvus 服务,默认端口为 19530
connections.connect("default", host="localhost", port="19530")
# 2. 创建一个集合 (Collection)
# 定义字段 schema
fields = [
# 主键字段:INT64 类型,非自动生成 (auto_id=False),需要手动指定 ID
FieldSchema(name="pk", dtype=DataType.INT64, is_primary=True, auto_id=False),
# 普通标量字段:DOUBLE 类型
FieldSchema(name="random", dtype=DataType.DOUBLE),
# 向量字段:FLOAT_VECTOR 类型,维度为 8
FieldSchema(name="embeddings", dtype=DataType.FLOAT_VECTOR, dim=8)
]
# 创建 Schema 对象,并添加描述
schema = CollectionSchema(fields, "hello_milvus is the simplest demo to introduce the APIs")
# 基于 Schema 创建集合,如果集合已存在会报错(实际生产中通常先检查是否存在)
hello_milvus = Collection("hello_milvus", schema)
# 3. 在集合中插入向量数据
# 构造 3000 条实体数据
entities = [
[i for i in range(3000)], # pk 列:0 到 2999
[float(random.randrange(-20, -10)) for _ in range(3000)], # random 列:-20 到 -10 之间的随机浮点数
[[random.random() for _ in range(8)] for _ in range(3000)], # embeddings 列:3000 个 8 维随机向量
]
# 执行插入操作
insert_result = hello_milvus.insert(entities)
# 刷新集合,确保数据落盘并可被搜索/查询(重要步骤)
hello_milvus.flush()
print(f"插入了 {insert_result.insert_count} 条数据,ID 范围:{insert_result.primary_keys[0]} 到 {insert_result.primary_keys[-1]}")
# 4. 在实体上生成索引 (Index)
# 定义索引参数:IVF_FLAT 算法,L2 欧氏距离,nlist=128 (聚类中心数)
index = {
"index_type": "IVF_FLAT",
"metric_type": "L2",
"params": {"nlist": 128},
}
# 为 embeddings 字段创建索引
hello_milvus.create_index("embeddings", index)
# 5. 将集合加载到内存并执行向量相似性搜索
# 加载集合到内存(Milvus 是内存优先的数据库,搜索前必须 load)
hello_milvus.load()
# 选取最后两个向量作为查询向量
vectors_to_search = entities[-1][-2:]
# 定义搜索参数:nprobe=10 (搜索时探查的聚类中心数量)
search_params = {
"metric_type": "L2",
"params": {"nprobe": 10},
}
# 执行向量搜索
# limit=3: 返回最相似的 3 个结果
# output_fields: 返回结果中除了主键和向量外,额外返回的标量字段
result = hello_milvus.search(
vectors_to_search,
"embeddings",
search_params,
limit=3,
output_fields=["random"]
)
print("向量搜索结果:")
for hits in result:
for hit in hits:
print(f"ID: {hit.id}, Distance: {hit.distance}, Random Value: {hit.entity.get('random')}")
# 6. 执行标量查询 (Query)
# 基于标量字段过滤:查找 random > -14 的实体
result_query = hello_milvus.query(
expr="random > -14",
output_fields=["random", "embeddings"]
)
print(f"\n标量查询结果数量: {len(result_query)}")
# 7. 执行混合搜索 (Hybrid Search)
# 结合向量相似度 + 标量过滤:查找 random > -12 的实体中,与查询向量最相似的 3 个
result_hybrid = hello_milvus.search(
vectors_to_search,
"embeddings",
search_params,
limit=3,
expr="random > -12",
output_fields=["random"]
)
print("\n混合搜索结果:")
for hits in result_hybrid:
for hit in hits:
print(f"ID: {hit.id}, Distance: {hit.distance}, Random Value: {hit.entity.get('random')}")
# 8. 按照实体的主键删除实体
# 构造删除表达式:删除 pk 等于前两个插入数据的 ID
expr = f"pk in [{entities[0][0]}, {entities[0][1]}]"
hello_milvus.delete(expr)
print(f"\n已执行删除操作: {expr}")
# 9. 删除集合
utility.drop_collection("hello_milvus")
print("集合 'hello_milvus' 已删除。")
# 断开连接(可选,程序结束会自动断开)
connections.disconnect("default")
一、连接服务 (Connection)
connections.connect("default", host="localhost", port="19530")
-
作用:建立客户端与 Milvus 服务器(Server)的 gRPC 连接。
-
关键点
-
host="localhost": 默认连接本地运行的 Milvus。如果是远程服务器,这里填 IP。 -
port="19530": Milvus 默认的 gRPC 监听端口(注意不是 HTTP 的 9091 或 80)。 -
隐含逻辑:如果连接失败,通常意味着 Milvus 服务未启动(Docker 容器没跑)或防火墙阻挡。
-
二、定义集合 Schema
下面的的代码展示了用FieldSchema创建pk等字段,然后再用 CollectionSchema创建shema,从而用Collection("hello_milvus", schema)创建了集合hello_milvus。
fields = [
FieldSchema(name="pk", dtype=DataType.INT64, is_primary=True, auto_id=False),
FieldSchema(name="random", dtype=DataType.DOUBLE),
FieldSchema(name="embeddings", dtype=DataType.FLOAT_VECTOR, dim=8)
]
schema = CollectionSchema(fields, "hello_milvus is the simplest demo...")
hello_milvus = Collection("hello_milvus", schema)
1、集合介绍
集合是 Milvus 中通过 Schema(模式) 定义的数据结构。
创建一个集合时,必须定义其 Schema,这相当于定义了数据的“骨架”。
shema包含了列数据+元数据;在 Milvus 中,你不能直接用 fields 建表,必须把它封装进 schema 才能使用。
2、field
一个集合主要由以下几种字段(Field)组成:
主键字段:唯一标识每一条数据(实体)。
向量字段:存储高维特征向量,是检索的核心
标量字段:存储元数据,用于过滤或展示。
下面我们详细来介绍它。
1)pk (主键):
is_primary=True: 标记为主键,类似关系型数据库的 ID。
auto_id=False: 手动指定 ID。代码后续插入数据时使用了 0, 1, 2...。如果设为 True,Milvus 会自动生成 ID,插入时就不需要传这个字段了。
2)random (标量字段):
DataType.DOUBLE: 普通的双精度浮点数。用于后续的标量过滤(如 random > -14)。
3)embeddings (向量字段):
DataType.FLOAT_VECTOR: 声明这是一个浮点型向量。
dim=8: 向量维度。这里为了演示设为 8,实际业务中通常是 768 (BERT), 1536 (OpenAI), 或更高。注意:一旦创建,维度不可修改。
三、插入数据
entities = [
[i for i in range(3000)], # pk 列
[float(random.randrange(-20, -10)) for _ in range(3000)], # random 列
[[random.random() for _ in range(8)] for _ in range(3000)] # embeddings 列 (3000个 8维向量)
]
insert_result = hello_milvus.insert(entities)
hello_milvus.flush()
1、概念:列式存储
Milvus 的 Python SDK 在插入数据时,采用的是列式格式(List of Lists),而不是常见的行式格式(List of Dicts)。
-
外层列表:代表整个批次的数据。
-
内层列表:代表一列数据(对应 Schema 中的一个 Field)。
-
重要规则:所有内层列表的长度必须一致(这里都是 3000),代表插入了 3000 行数据。
2、构造数据
1)主键列 (pk)插入了:[0, 1, 2, ..., 2999]
2)标量列 (random):3000 个介于 -20 到 -10 之间的随机浮点数。
这是为了演示标量过滤。在后续的搜索中,我们可以用 random > -14 这样的条件来筛选数据。
3)向量列 (embeddings):[[random.random() for _ in range(8)] for _ in range(3000)]
生成:3000 个向量,每个向量包含 8 个 0.0 到 1.0 之间的随机浮点数。
3、执行插入
-
动作:将构造好的
entities发送给 Milvus 服务端。 -
返回值 (
insert_result):这是一个包含插入结果的对象,通常包含:
-
insert_count:成功插入的数量(应为 3000)。 -
primary_keys:插入数据的主键列表(这里就是 0 到 2999)。
-
-
注意:此时数据虽然发送到了服务器,但可能还在服务器的内存缓冲区中,尚未完全持久化到磁盘,也未立即对搜索可见。
4、数据落盘
-
作用:这是一个强制同步操作。
-
为什么要 Flush?
-
持久化:强制将内存中的增量数据(Insert Log)写入磁盘(Segment 文件),防止服务重启导致数据丢失。
-
生成索引:Milvus 的索引构建通常是基于磁盘上的数据段(Segment)进行的。只有 Flush 后生成了 Segment,后续的
create_index才能索引到这些数据。 -
搜索可见性:在某些配置下,未 Flush 的数据可能无法被搜索到。
-
四、创建索引
下述代码展示了集合hello_milvus的创建过程。
索引定义指定索引类型为:IVF_FLAT倒排文件索引; 衡量两个向量的直线距离使用L2,欧几里得距离。
nlist为聚类中心的数量。
index = {
"index_type": "IVF_FLAT",
"metric_type": "L2",
"params": {"nlist": 128},
}
hello_milvus.create_index("embeddings", index)
1、IVF_FLAT
训练阶段:算法会将所有向量聚类成 nlist 个簇(Cluster),每个簇有一个中心点。
搜索阶段:当你要搜索时,系统先判断你的查询向量离哪几个簇的中心最近,然后只在这些选中的簇里进行暴力搜索,而不是遍历全库。
2、metric_type: L2
含义:欧几里得距离。
作用:定义“相似度”的计算方式。
L2 计算的是空间中两点间的直线距离。距离越小,代表向量越相似。
3、params: {"nlist": 128}
含义:聚类中心的数量。
调优逻辑:
这个参数决定了将数据分成多少份。
经验公式:通常建议 nlist约等于根号n (N 为向量总数)。
影响:nlist 越大,搜索时排查的范围越精细(速度可能变慢,但精度可能提高),训练索引的时间也会变长。
4、执行创建索引
-
参数 1
"embeddings":指定要为哪个字段建立索引。这里对应 Schema 中定义的向量字段。 -
参数 2
index:传入上面定义的索引蓝图。 -
执行过程
-
Milvus 会读取集合中已
flush的数据。 -
在后台异步执行索引构建任务(聚类、生成倒排表)。
-
构建完成后,索引文件会被持久化存储。
-
五、加载到内存 (Load)
我们需要将数据从磁盘加载到内存中
hello_milvus.load()
六、搜索与查询
A. 向量相似性搜索 (Vector Search)
下面的向量相似性上搜索目的是:在 embeddings 字段中,寻找与 vectors_to_search 最相似的 limit=3 个向量。
vectors_to_search = entities[-1][-2:] # 取最后2个向量作为查询目标
result = hello_milvus.search(vectors_to_search, "embeddings", search_params, limit=3, ...)
-
distance: 0.0: 因为查询向量本身就是数据库里的最后两个向量(ID 2998, 2999),所以距离为 0(完全匹配)。 -
latency = 0.2796s: 对于 3000 条数据,这个延迟略高(通常毫秒级),可能是因为第一次加载索引或 Python 启动开销。在百万级数据下,IVF_FLAT 的优势才会体现出来(依然保持毫秒级)。
B. 标量查询 (Scalar Query)
下面的代码展示了标量查询,即筛选 random 字段大于 -14 的记录。
因为不涉及向量计算,速度极快。
result = hello_milvus.query(expr="random > -14", ...)
在返回的数据中,random field 的值全部是 -11.0。
这说明过滤生效了!只有满足标量条件的数据才被返回,即使有其他向量距离更近但不满足 random > -12 的数据,也被排除了。
七、删除与清理 (Delete & Drop)
下面展示了使用delete删除字段(逻辑删除)和drop删除集合。
expr = f"pk in [{entities[0][0]}, {entities[0][1]}]"
hello_milvus.delete(expr)
utility.drop_collection("hello_milvus")
1、构造表达式
entities[0] 是主键 pk 的列表(即 [0, 1, 2, ..., 2999])。 entities[0][0] 和 entities[0][1]:分别取出了列表中的前两个 ID,即 0 和 1。 f"pk in [...]":利用 Python 的 f-string 格式化字符串,最终生成的表达式为 "pk in [0, 1]"。 含义:这是一个布尔表达式,告诉 Milvus“我要操作主键是 0 或者 1 的数据”。
2、执行删除 (hello_milvus.delete(expr))
作用:从集合中移除符合 expr 条件的行。
原理:Milvus 的删除操作通常是逻辑删除。系统会在后台标记这两条数据为“已删除”,它们在后续的搜索和查询中不可见,但物理文件可能不会立即从磁盘消失(需要通过 Compaction 机制进行物理清理)。
限制:Milvus 的删除操作目前仅支持基于主键或标量字段的过滤,不支持基于向量相似度的删除。
3、删除整个集合(utility.drop_collection)
Drop: 彻底删除集合及其所有数据和索引,释放存储空间。
总结
1、本文首先介绍了Milvus 的基础连接。通过 connections.connect 建立客户端与服务器的通信。
2、用代码展示了用FieldSchema创建pk等字段,然后再用 CollectionSchema创建shema,从而用Collection("hello_milvus", schema)创建了集合hello_milvus。
然后介绍了集合(Collection)的定义;再而提出shema包含了列数据+元数据。并介绍了个字段的含义。
3、接着展示使用insert插入数据的代码。介绍了Milvus 的 Python SDK 列式存储的概念;并分析了代码中pk,random,embeddings列插入的数据;以及insert函数的动作含义(将构造好的 entities 发送给 Milvus 服务端)和返回结果insert_result(insert_counts和primary_keys)
还分析了flush的意义(持久化,生成索引,搜索可见性)
4、还用代码展示了集合hello_milvus的创建过程。并介绍了IVF_FLAT索引类型,相似度计算方式metric_type: L2,聚类中心数量params: {"nlist": 128}等概念,以及执行创建索引逻辑。
5、然后介绍将数据加载到内存。
7、接着介绍搜索与查询。包括了向量相似性搜索,以及标量查询。
6、然后展示了使用delete删除字段(逻辑删除)和drop删除集合。剖析:构造表达式,执行删除delete ,删除整个集合drop等原理。
最后,文章详细对比了三种核心数据操作模式:
向量搜索(Search):基于向量相似度(如欧氏距离)寻找 Top-K 结果;
标量查询(Query):类似 SQL 的 WHERE 子句,用于基于元数据的精确过滤;
混合搜索(Hybrid Search):结合了向量相似度与标量过滤(expr),实现更精细的检索;
此外,还简要说明了基于表达式的数据删除(Delete)与集合清理(drop_collection)操作。
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐



所有评论(0)