Chapter 3: Milvus 基础操作 - PyMilvus 核心API实战 3.1 学习目标 掌握向量数据库在实际应用中的基础操作,理解其在应用系统中的核心作用 熟悉 PyMilvus 的核心 API 使用方式,包括数据库连接与基本配置 理解 Collection 的创建与管理流程,能够进行合理的 Schema 设计 掌握向量与结构化数据的写入方法,确保数据高效入库 熟练使用查询(Query)与向量搜索(Search)接口,实现向量检索功能 了解并掌握索引的创建与管理机制,提升向量检索性能 能够综合运用以上能力,基于 Milvus 构建完整的向量检索应用系统 3.
Milvus 提供了两种部署模式:Milvus Standalone(单机版)和 Milvus Cluster(集群版)。对于开发测试和小规模应用,可以直接使用 Milvus Lite,这是一个轻量级的 Python 库,可以将数据存储在本地文件中。
Milvus Lite只支持linux系统,相关的部分应用可见第6章 【Milvus Lite部署与应用】
Milvus Cluster(集群版)需要使用集群服务器,并不太适合教程学习,因此本项目更加推荐Milvus Standalone模型来进行学习。
首先需要安装 PyMilvus 客户端库:
pip install pymilvus
如果你的网络环境无法访问 PyPI,可以考虑使用国内镜像源:
pip install pymilvus -i https://pypi.tuna.tsinghua.edu.cn/simple
PyMilvus 提供了 MilvusClient 类作为与 Milvus 交互的主要接口。根据部署方式的不同,连接方式也有所区别。
MilvusClient 是 PyMilvus 提供的客户端接口,用于以更简单直观的方式完成 Milvus 的连接、数据写入、查询、向量搜索和集合管理等常见操作。
本地文件模式(Milvus Lite)
这种方式适用于快速原型开发和小规模数据场景,所有数据存储在本地文件中:
from pymilvus import MilvusClient # 连接到本地数据库文件,如果文件不存在会自动创建 client = MilvusClient("./milvus_demo.db")
服务器模式
连接到运行在本地的 Milvus 服务器:
client = MilvusClient(uri="http://localhost:19530")
如果 Milvus 服务器启用了认证功能,需要提供用户名和密码:
client = MilvusClient( uri="https://localhost:19530", token="root:Milvus" )
连接成功后,可以通过以下命令检查服务器状态:
from pymilvus import utility # 检查服务器连接状态 print(utility.get_server_version(client))
如果上述命令成功返回版本号,说明连接已建立。但是如果报错:pymilvus.exceptions.ConnectionConfigException: <ConnectionConfigException: (code=1, message=Alias should be string, but <class 'pymilvus.milvus_client.milvus_client.MilvusClient'> is given.)>,是因为新版pymilvus打印版本号的api发生了更改:
# 检查服务器连接状态 print(client.get_server_version())
Collection 是 Milvus 中存储和管理数据的基本容器,可以将其类比为关系数据库中的表。每个 Collection 都需要一个 Schema 来定义其结构,包括字段名称、数据类型、主键等。
Schema 定义了 Collection 的数据结构,包括:
Milvus 支持多种数据类型:
| 数据类型 | 说明 | 示例用途 |
|---|---|---|
| INT8 | 8位整数 | 小范围计数 |
| INT16 | 16位整数 | 中等范围计数 |
| INT32 | 32位整数 | 标准整数 |
| INT64 | 64位整数 | 主键ID、大范围计数器 |
| FLOAT | 单精度浮点数 | 价格、分数 |
| DOUBLE | 双精度浮点数 | 高精度数值 |
| 数据类型 | 说明 | 注意事项 |
|---|---|---|
| VARCHAR | 变长字符串 | 需要指定 max_length 参数 |
| BOOL | 布尔值 | 是/否标记 |
| 数据类型 | 说明 | 适用场景 |
|---|---|---|
| FLOAT_VECTOR | 32位浮点向量 | 标准嵌入向量,科学计算和机器学习 |
| FLOAT16_VECTOR | 16位半精度浮点向量 | 深度学习和GPU计算 |
| BFLOAT16_VECTOR | 16位Brain Floating Point向量 | 提供与Float32相同的指数范围但精度降低 |
| INT8_VECTOR | 8位整数向量 | 量化深度学习模型(仅支持HNSW索引) |
| BINARY_VECTOR | 二进制向量 | 高效的二进制表示 |
| SPARSE_FLOAT_VECTOR | 稀疏浮点向量 | 稀疏数据表示 |
| 数据类型 | 说明 | 配置要求 |
|---|---|---|
| JSON | JSON对象 | 存储半结构化数据 |
| ARRAY | 数组 | 需要指定 element_type 和 max_capacity |
from pymilvus import MilvusClient, DataType client = MilvusClient(uri="http://localhost:19530") # 创建 schema schema = MilvusClient.create_schema( auto_id=False, # 是否自动为主键字段生成唯一 ID。False 表示主键由你自己提供 enable_dynamic_field=True, # 是否开启动态字段。True 表示可在插入数据时携带未在 schema 中显式定义的额外键值对,MILVUS 会以动态列存储 ) # 添加主键字段 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_varchar", datatype=DataType.VARCHAR, max_length=512)
主键字段有以下特点:
Milvus 支持两种主键管理模式:
1. 自动生成 ID (AutoID)
schema.add_field( field_name="id", is_primary=True, auto_id=True, # Milvus 自动生成 ID datatype=DataType.INT64 )
使用 AutoID 时:
2. 手动指定 ID
schema.add_field( field_name="product_id", is_primary=True, auto_id=False, # 手动提供 ID datatype=DataType.VARCHAR, max_length=100 )
手动指定 ID 时:
向量字段需要指定维度:
schema.add_field( field_name="embedding", datatype=DataType.FLOAT_VECTOR, dim=768 # 向量维度 )
维度限制:
Proxy.maxDimension 支持更大维度启用动态字段后,可以存储未在 Schema 中定义的字段:
schema = MilvusClient.create_schema( auto_id=False, enable_dynamic_field=True, # 启用动态字段 )
启用动态字段时:
$meta 的保留字段创建 Schema 有两种方式:使用 create_schema() 方法或使用 FieldSchema 和 CollectionSchema 类。
方式一:使用 create_schema()
from pymilvus import MilvusClient, DataType client = MilvusClient("milvus_demo.db") # 创建 Schema schema = client.create_schema( auto_id=False, # 手动指定ID,不自动生成 enable_dynamic_field=True # 启用动态字段,可以插入未预定义的字段 ) # 添加字段 schema.add_field( field_name="id", datatype=DataType.INT64, is_primary=True ) schema.add_field( field_name="title", datatype=DataType.VARCHAR, max_length=256 ) schema.add_field( field_name="embedding", datatype=DataType.FLOAT_VECTOR, dim=768 # 向量维度,要与使用的嵌入模型维度一致 ) schema.add_field( field_name="price", datatype=DataType.FLOAT )
方式二:使用 CollectionSchema
from pymilvus import FieldSchema, CollectionSchema, DataType # 定义字段 id_field = FieldSchema( name="id", dtype=DataType.INT64, is_primary=True, auto_id=False ) title_field = FieldSchema( name="title", dtype=DataType.VARCHAR, max_length=256 ) embedding_field = FieldSchema( name="embedding", dtype=DataType.FLOAT_VECTOR, dim=768 ) price_field = FieldSchema( name="price", dtype=DataType.FLOAT ) # 创建 Schema schema = CollectionSchema( fields=[id_field, title_field, embedding_field, price_field], description="Product collection", enable_dynamic_field=True )
创建 Collection 需要指定集合名称、Schema 和可选的索引参数。
# 基本创建方式 client.create_collection( collection_name="products", schema=schema ) # 创建带索引的 Collection index_params = client.prepare_index_params() index_params.add_index( field_name="embedding", # 需要建立索引的字段名。应为向量字段 index_type="IVF_FLAT", # 索引类型。IVF_FLAT表示倒排文件平铺索引,适合大规模向量的近似搜索;常见还有IVF_SQ8`、`HNSW` 等 metric_type="COSINE", # 距离度量方式。COSINE余弦相似度;常用还有L2`(欧氏距离)、`IP`(内积)。使用 `COSINE` 时一般需要对向量做归一化。 params={"nlist": 128} # 索引的超参数字典。{"nlist": 128} 中nlist` 表示聚类中心数量(分桶数),影响召回与性能;值越大召回率越高但索引与搜索更慢。根据数据规模调优(例如 10K~1M 样本可从 64~4096 试配)。 ) client.create_collection( collection_name="products", schema=schema, index_params=index_params )
常用的度量类型
| 度量类型 | 说明 | 距离范围 | 适用场景 |
|---|---|---|---|
| COSINE | 余弦相似度 | [-1, 1] | 文本向量,关注方向而非大小 |
| L2 | 欧几里得距离 | [0, ∞) | 通用向量,关注绝对距离 |
| IP | 内积 | [-∞, ∞) | 归一化向量,与余弦相似度相关 |
列出数据库中所有已创建的 Collection:
# 列出所有 Collection collections = client.list_collections() print(collections)
重命名现有的 Collection。注意:为 Collection 创建的别名在此操作后保持不变:
client.rename_collection( old_name="products", new_name="product_catalog" )
删除不再需要的 Collection。此操作不可逆,请谨慎使用:
client.drop_collection(collection_name="product_catalog")
为什么需要加载?
在执行相似性搜索或查询之前,必须将 Collection 加载到内存中。 加载操作会将索引文件和所有字段的原始数据加载到内存,以实现快速响应。
加载整个 Collection
对于小规模数据,可以加载整个 Collection:
# 由于之前rename和drop操作,重新创建名为"products"的Collection client.create_collection( collection_name="products", schema=schema ) # 创建带索引的 Collection index_params = client.prepare_index_params() index_params.add_index( field_name="embedding", index_type="IVF_FLAT", metric_type="COSINE", params={"nlist": 128} ) client.create_collection( collection_name="products", schema=schema, index_params=index_params ) # 列出所有 Collection collections = client.list_collections() print(collections) # 加载整个 Collection client.load_collection( collection_name="products" )
选择性加载字段(优化内存使用)
对于大规模数据,可以只加载搜索和查询所需的字段,以减少内存占用并提升性能:
# 只加载指定字段 client.load_collection( collection_name="products", load_fields=["id", "embedding"], # load_fields: 可选,指定需预加载的字段列表。只加载这些字段,其它字段不加载以省内存。向量检索至少应包含向量字段(如 embedding),通常也加载主键(如 id)。若查询/输出引用未加载字段会失败或无法返回该列。默认 None 表示加载全部字段。 skip_load_dynamic_field=True # 可选,布尔值。集合启用动态字段时,是否跳过动态列(如内部的 \$meta)的加载。True 跳过以节省内存;False 一并加载。默认通常为 False )
注意事项:
load_fields 中必须包含主键字段和至少一个向量字段load_fields 中指定的字段可用于过滤条件和输出字段skip_load_dynamic_field=True 会跳过加载动态字段($meta),使其无法用于过滤和输出释放 Collection
搜索和查询是内存密集型操作。使用完毕后应释放 Collection 以节省成本:
# 释放 Collection client.release_collection(collection_name="products") # 检查加载状态 status = client.get_load_state(collection_name="products") print(status) # 输出: {'state': <LoadState: Loaded>} 或 {'state': <LoadState: NotLoad>}
get_load_state() 返回的状态包括:
Loaded:Collection 已加载
Loading:Collection 正在加载中
NotLoad:Collection 未加载
Milvus 接受的数据格式是字典列表,每个字典代表一条记录。在插入数据之前,需要准备好向量数据和元数据。向量数据通常由嵌入模型生成,这里我们使用随机数据进行演示。
import random # 生成模拟向量数据 def generate_embeddings(num_vectors, dim=768): return [[random.random() for _ in range(dim)] for _ in range(num_vectors)] # 准备数据 data = [ { "id": 1, "title": "Apple iPhone 15 Pro", "embedding": generate_embeddings(1)[0], "price": 999.99, "brand": "Apple", "category": "smartphone" }, { "id": 2, "title": "Samsung Galaxy S24", "embedding": generate_embeddings(1)[0], "price": 899.99, "brand": "Samsung", "category": "smartphone" }, { "id": 3, "title": "Sony WH-1000XM5", "embedding": generate_embeddings(1)[0], "price": 349.99, "brand": "Sony", "category": "headphones" } ]
数据格式要求:
id)必须提供,除非设置了 auto_id=True单次插入
使用 insert() 方法将数据插入到 Collection 中:
insert_result = client.insert( collection_name="products", data=data ) print(f"插入的记录数: {insert_result['insert_count']}")
insert() 方法返回一个包含以下信息的结果对象:
insert_count:成功插入的实体数量primary_keys:插入实体的主键列表timestamp:操作完成的时间戳注意,在新版本的 PyMilvus 中,insert() 方法的返回值是一个字典,而不是之前版本中的 InsertResult 对象。Returns: Dict: Number of rows that were inserted and the inserted primary key list.,如:{'insert_count': 3, 'ids': [1, 2, 3]}
批量插入
对于大规模数据,建议分批插入以提高性能和稳定性:
def batch_insert(client, collection_name, data, batch_size=1000): """分批插入数据""" total = len(data) for i in range(0, total, batch_size): batch = data[i:i + batch_size] result = client.insert( collection_name=collection_name, data=batch ) print(f"已插入 {min(i + batch_size, total)}/{total} 条记录") print("所有数据插入完成") # 使用示例 large_data = [ { "id": i, "embedding": generate_embeddings(1)[0], "title": f"Product {i}", "price": 100.0 + i } for i in range(10000) ] batch_insert(client, "products", large_data, batch_size=500)
插入到指定分区
如果 Collection 中有多个分区,可以指定插入到特定分区:
# 创建分区 client.create_partition( collection_name="products", partition_name="electronics" ) client.insert( collection_name="products", data=data, partition_name="electronics" )
注意事项:
auto_id=True,则不要在数据中包含主键字段flush() 确保数据持久化Upsert 操作结合了"更新"和"插入":如果记录已存在(根据主键判断),则更新该记录;否则插入新记录。这是一个数据级操作,会覆盖已存在的实体。
update_data = [ { "id": 1, # 已存在的记录,会被更新 "title": "Apple iPhone 15 Pro Max", "price": 1099.99, "embedding": generate_embeddings(1)[0], "brand": "Apple", "category": "smartphone" }, { "id": 999, # 不存在的记录,会被插入 "title": "Google Pixel 8", "price": 699.99, "embedding": generate_embeddings(1)[0], "brand": "Google", "category": "smartphone" } ] upsert_result = client.upsert( collection_name="products", data=update_data ) print(f"Upsert 处理的记录数: {upsert_result['upsert_count']}")
upsert() 方法返回的结果对象包含:
upsert_count:成功 upsert 的实体数量primary_keys:受影响实体的主键列表timestamp:操作完成的时间戳Upsert 到指定分区
同样可以将 upsert 操作限定在特定分区:
client.upsert( collection_name="products", data=update_data, partition_name="electronics" )
使用场景:
注意事项:
向量搜索是 Milvus 的核心功能,用于找出与查询向量最相似的数据记录。
单向量搜索
# 加载 Collection client.load_collection( collection_name="products" ) # 检查加载状态 status = client.get_load_state(collection_name="products") print(status) query_vector = generate_embeddings(1)[0] results = client.search( collection_name="products", data=[query_vector], # 查询向量列表 limit=5, # 返回前5个最相似的结果 output_fields=["title", "price", "brand"] # 返回的字段 ) # 处理搜索结果 for i, hits in enumerate(results): print(f"查询 {i+1} 的结果:") for hit in hits: print(f" ID: {hit['id']}") print(f" 距离: {hit['distance']:.4f}") print(f" 标题: {hit['title']}") print(f" 价格: ${hit['price']}") print()
批量向量搜索
Milvus 支持在一次请求中处理多个查询向量:
query_vectors = generate_embeddings(3) # 3个查询向量 results = client.search( collection_name="products", data=query_vectors, limit=3, output_fields=["title", "price"] ) print(results) # results[0] 对应第一个查询向量的结果 # results[1] 对应第二个查询向量的结果 # 以此类推
在实际应用中,经常需要在向量搜索的同时添加标量过滤条件,实现精确检索和语义检索的结合。
# 只搜索电子产品类别 results = client.search( collection_name="products", data=[query_vector], filter='category == "smartphone"', limit=5, output_fields=["title", "category", "price"] ) print(results) # 复杂过滤条件 results = client.search( collection_name="products", data=[query_vector], filter='category == "smartphone" and price < 1000', limit=5, output_fields=["title", "price"] ) print(results) # 使用 IN 操作符 results = client.search( collection_name="products", data=[query_vector], filter='brand in ["Apple", "Samsung", "Google"]', limit=5, output_fields=["title", "brand"] ) print(results)
支持的过滤表达式
Milvus 支持丰富的布尔表达式用于标量过滤:
| 操作符 | 说明 | 示例 |
|---|---|---|
| ==, != | 等于、不等于 | price == 999 |
| >, >=, <, <= | 比较运算符 | price > 500 |
| in, not in | 包含、不包含 | brand in ["Apple", "Samsung"] |
| and, or, not | 逻辑运算符 | price > 500 and price < 1000 |
| like | 模糊匹配 | title like "%Pro%" |
搜索行为可以通过 search_params 参数进行精细控制:
results = client.search( collection_name="products", data=[query_vector], limit=10, search_params={ "metric_type": "COSINE", # 距离度量类型 "params": {"nprobe": 10} # 搜索参数 } ) print(results)
不同索引类型的搜索参数:
IVF 系列索引(IVF_FLAT, IVF_SQ8, IVF_PQ):
nprobe:要查询的聚类单元数量,范围 [1, nlist],默认值 8HNSW 索引:
ef:控制查询时间/准确度权衡的参数,更高的 ef 会带来更准确但更慢的搜索,范围 [top_k, int_max]SCANN 索引:
nprobe:要查询的聚类单元数量reorder_k:要查询的候选单元数量,范围 [top_k, ∞],默认值为 top_k使用 offset 参数实现分页:
# 第一页:前10条结果 page1 = client.search( collection_name="products", data=[query_vector], limit=10, offset=0 ) print(page1) # 第二页:跳过前10条,返回第11-20条 page2 = client.search( collection_name="products", data=[query_vector], limit=10, offset=10 ) print(page2)
注意事项:
offset 与 limit 的总和应小于 16,384search_iterator() 方法以获得更好的性能标量查询(Query)不涉及向量相似度计算,直接根据标量字段的值进行数据检索。
标量查询就体现了数据库特有优势,Miluvs相比faiss来说会更像数据库一些,保留非向量查询的一些基础功能
# 查询所有数据(限制返回数量) results = client.query( collection_name="products", filter="", # 空过滤条件表示查询所有 output_fields=["id", "title", "price"], limit=100 ) print(results) # 根据ID查询 results = client.query( collection_name="products", filter='id in [1, 2, 3]', output_fields=["id", "title", "price"] ) print(results) # 条件查询 results = client.query( collection_name="products", filter='category == "smartphone" and price > 500', output_fields=["id", "title", "brand", "price"] ) print(results)
重要说明:
filter 设置为空字符串时,必须设置 limit 来限制返回的实体数量offset 和 limit 的总和应小于 16,384# 精确匹配 results = client.query( collection_name="products", filter='brand == "Apple"', output_fields=["id", "title"] ) print(results) # 模糊匹配 results = client.query( collection_name="products", filter='title like "%Pro%"', # 标题包含 "Pro" output_fields=["id", "title"] ) print(results)
# 价格区间查询 results = client.query( collection_name="products", filter='price >= 100 and price <= 1000', output_fields=["id", "title", "price"] ) print(results) # 多条件组合 results = client.query( collection_name="products", filter='(category == "smartphone" and price > 800) or (category == "headphones" and price < 200)', output_fields=["id", "category", "title", "price"] ) print(results)
Milvus 支持使用 count(*) 来统计满足条件的实体数量:
# 统计总数 count_result = client.query( collection_name="products", filter="", output_fields=["count(*)"] ) total_count = count_result[0]["count(*)"] print(f"总记录数: {total_count}") # 按类别统计 categories = ["smartphone", "headphones", "tablet"] for category in categories: result = client.query( collection_name="products", filter=f'category == "{category}"', output_fields=["count(*)"] ) count = result[0]["count(*)"] print(f"{category}: {count} 条记录")
查询优化建议:
query_iterator() 方法进行迭代查询。query():一次性返回满足过滤条件的所有结果(可配合limit、output_fields)。适合结果集较小的场景。consistency_level 参数调整一致性级别以平衡性能和准确性举个query()和query_iterator()的对比例子:
# 一次性查询:直接拿到所有匹配记录 all_results = client.query( collection_name="products", filter='category == "smartphone" and price < 1000', output_fields=["id", "title", "price", "category"], limit=1000 # 可选,控制最大返回条数 ) print(f"总结果数: {len(all_results)}") for row in all_results: print(row["id"], row["title"], row["price"]) # 迭代式查询:分批获取,适合海量数据 it = client.query_iterator( collection_name="products", filter='category == "smartphone" and price < 1000', output_fields=["id", "title", "price", "category"], batch_size=200 ) total = 0 while True: batch = it.next() if not batch: break for row in batch: total += 1 # 处理每条记录 print(row["id"], row["title"], row["price"]) print(f"累计结果数: {total}")
索引是提升向量搜索性能的关键。Milvus 支持多种索引类型,不同的索引适用于不同的场景。
如果忘记了索引相关的内容,可以跳转到向量基础【向量ANN搜索算法】重新复习一下~
| 索引类型 | 特点 | 适用场景 |
|---|---|---|
| FLAT | 精确搜索,无压缩 | 相对较小的数据集,需要100%召回率 |
| IVF_FLAT | 高速查询,尽可能高的召回率 | 中等规模数据 |
| IVF_SQ8 | 非常高速查询,内存资源有限,可接受轻微召回率损失 | 内存受限场景 |
| IVF_PQ | 高速查询,内存资源有限,可接受轻微召回率损失 | 大规模数据 |
| IVF_RABITQ | 高精度1-bit量化 | 大规模数据集,需要高召回率同时优化资源利用 |
| HNSW | 非常高速查询,尽可能高的召回率,大内存资源 | 高性能需求 |
| HNSW_SQ | 非常高速查询,内存资源有限,可接受轻微召回率损失 | 高性能需求且内存受限 |
| HNSW_PQ | 中速查询,非常有限的内存资源,可接受轻微召回率损失 | 内存极度受限 |
| HNSW_PRQ | 中速查询,非常有限的内存资源,可接受轻微召回率损失 | 内存极度受限 |
| SCANN | 非常高速查询,尽可能高的召回率,大内存资源 | 高性能需求 |
| DISKANN | 磁盘索引 | 超大规模数据 |
| AUTOINDEX | 自动优化 | 快速启动,所有字段类型 |
创建向量索引
# 准备索引参数 index_params = client.prepare_index_params() # 添加向量字段索引 index_params.add_index( field_name="embedding", index_type="HNSW", metric_type="COSINE", params={ "M": 16, "efConstruction": 256 } ) # 在创建 Collection 时指定索引 client.create_collection( collection_name="products1", schema=schema, index_params=index_params )
为已存在的 Collection 创建索引
index_params = client.prepare_index_params() index_params.add_index( field_name="embedding", index_type="IVF_FLAT", metric_type="COSINE", params={"nlist": 128} ) client.create_index( collection_name="products", index_params=index_params )
对于经常用于过滤的标量字段,可以创建标量索引以提升查询性能(3):
# 为数值字段创建索引 index_params.add_index( field_name="price", index_type="INVERTED" ) client.create_index( collection_name="products", index_params=index_params )
标量字段支持的索引类型:
# 查看索引信息 indexes = client.list_indexes(collection_name="products") print(indexes) # 描述索引详情 index_info = client.describe_index( collection_name="products", index_name="embedding_vector_idx" ) print(index_info) # 删除索引 client.drop_index( collection_name="products", index_name="embedding_vector_idx" )
AUTOINDEX 是 Milvus 提供的智能索引选项,会根据数据类型自动选择最合适的索引类型:
index_params = client.prepare_index_params() index_params.add_index( field_name="embedding", index_type="AUTOINDEX", metric_type="COSINE" ) client.create_collection( collection_name="products2", schema=schema, index_params=index_params )
AUTOINDEX 自动选择规则:
| 数据类型 | 自动选择的索引算法 |
|---|---|
| VARCHAR | 倒排索引 |
| INT8/INT16/INT32/INT64 | 倒排索引 |
| FLOAT/DOUBLE | 倒排索引 |
# 删除指定ID的记录 client.delete( collection_name="products", ids=[1, 2, 3] # 要删除的主键ID列表 )
# 加载 Collection client.load_collection( collection_name="products" ) # 根据单个条件删除 client.delete( collection_name="products", filter='price < 100' ) # 根据复杂条件删除 client.delete( collection_name="products", filter='brand == "OldBrand" or (category == "discontinued" and price < 50)' ) # 删除特定时间之前的数据 client.delete( collection_name="products", filter='created_at < "2024-01-01"' )
注意:Milvus 的删除操作是异步执行的,数据不会立即从磁盘中删除,而是在后续的数据压缩过程中清理。
根据可用的信息源,我对您的文档进行了修改和补充。以下是修改后的完整内容:
Milvus 支持通过布尔表达式删除实体。对于大规模数据删除,建议使用过滤表达式:
# 使用过滤表达式删除 res = client.delete( collection_name="products", filter='price < 100 and category == "old_items"' )
在分区中删除数据
# 在指定分区中删除 client.delete( collection_name="products", partition_name="electronics", filter="id in [0, 1]" )
删除操作的注意事项:
分区是集合的子集,每个分区与其父集合共享相同的数据结构,但只包含集合中数据的一个子集。合理使用分区可以提升查询性能并简化数据管理。
默认分区
创建集合时,Milvus 会自动创建一个名为 _default 的分区。如果不添加其他分区,所有插入的实体都会进入默认分区。
创建分区
一个集合最多可以有 1,024 个分区。
# 创建分区 client.create_partition( collection_name="products", partition_name="partitionA" )
查看分区
# 列出所有分区 res = client.list_partitions( collection_name="products" ) print(res)
检查分区是否存在
res = client.has_partition( collection_name="products", partition_name="partitionA" ) print(res) # 输出: True
删除分区
删除分区前需要确保分区已释放。
# 释放分区 client.release_partitions( collection_name="products", partition_names=["partitionA"] ) # 删除分区 client.drop_partition( collection_name="products", partition_name="partitionA" ) # 验证删除 res = client.list_partitions( collection_name="products" ) print(res)
加载分区
您可以单独加载集合中的特定分区。如果集合中有未加载的分区,集合的加载状态将保持为未加载。
# 创建分区 client.create_partition( collection_name="products", partition_name="partitionA" ) client.load_partitions( collection_name="products", partition_names=["partitionA"] ) res = client.get_load_state( collection_name="products", partition_name="partitionA" ) print(res) # 输出: {"state": "<LoadState: Loaded>"}
释放分区
client.release_partitions( collection_name="products", partition_names=["partitionA"] ) res = client.get_load_state( collection_name="products", partition_name="partitionA" ) print(res) # 输出: {"state": "<LoadState: NotLoaded>"}
Partition Key 是一种基于分区的搜索优化解决方案。通过指定特定的标量字段作为 Partition Key,并在搜索时基于 Partition Key 指定过滤条件,可以将搜索范围缩小到若干分区,从而提升搜索效率。
设置 Partition Key
在添加标量字段时,将其 is_partition_key 属性设置为 True:
schema.add_field( field_name="my_varchar", datatype=DataType.VARCHAR, max_length=512, is_partition_key=True, )
设置分区数量
当指定标量字段作为 Partition Key 时,Milvus 会自动在集合中创建 16 个分区。您也可以自定义分区数量:
client.create_collection( collection_name="my_collection", schema=schema, num_partitions=128 )
基于 Partition Key 的过滤
在启用 Partition Key 功能的集合中进行 ANN 搜索时,需要在搜索请求中包含涉及 Partition Key 的过滤表达式:
# 基于单个 partition key 值过滤 filter='partition_key == "x" && <other conditions>' # 基于多个 partition key 值过滤 filter='partition_key in ["x", "y", "z"] && <other conditions>'
启用 Partition Key Isolation
Partition Key Isolation 功能可以进一步提升搜索性能。启用后,Milvus 会基于 Partition Key 值对实体进行分组,并为每个组创建单独的索引。
client.create_collection( collection_name="my_collection1", schema=schema, properties={"partitionkey.isolation": True} )
启用 Partition Key Isolation 后,基于 Partition Key 的过滤器应仅包含一个特定的 Partition Key 值。目前,Partition Key Isolation 功能仅适用于索引类型设置为 HNSW 的搜索。
对于某些应用场景,如临时数据存储或会话数据,可以设置 Collection 的 TTL(Time To Live),让数据在指定时间后自动过期。
TTL(Time-to-Live)是数据库中常用的功能,用于在插入或修改数据后的特定时间段内保持数据有效或可访问。例如,如果您每天导入数据但只需要保留 14 天的记录,可以通过将集合的 TTL 设置为 14 × 24 × 3600 = 1209600 秒来配置 Milvus 自动删除超过该时间的数据。
TTL 工作原理:
dataCoord.compaction.expiry.tolerance 配置项来控制何时触发数据压缩-1,表示使用现有的数据压缩间隔。当更改为正整数(如 12)时,数据压缩将在任何实体过期后的指定小时数后触发Python
from pymilvus import MilvusClient # 创建 Collection 时设置 TTL client.create_collection( collection_name="my_collection2", schema=schema, properties={ "collection.ttl.seconds": 1209600 # 14天 } )
Python
client.alter_collection_properties( collection_name="my_collection2", properties={"collection.ttl.seconds": 1209600} )
如果您决定无限期保留集合中的数据,可以从该集合中删除 TTL 设置。
Python
client.drop_collection_properties( collection_name="my_collection2", property_keys=["collection.ttl.seconds"] )
本章介绍了 PyMilvus 的核心 API 和基础操作,包括:
看到这里,恭喜你掌握Milvus相关基础知识,那么现在你就可以开始构建基于 Milvus 的向量检索应用了。
还等什么,出发吧~