Milvus 分区与分区键
分区(partition)把集合内的数据按业务维度物理划分,检索时可以限定分区,扫描的数据量随之减少。分区键(partition key)面向多租户场景:把某个字段声明为分区键后,写入时数据按键值自动路由到内部分区,查询带上该字段即可天然限定范围。两者解决的问题相似但用法不同——手动分区适合数量少、边界清晰的维度,分区键适合取值多、需要自动扩展的租户维度。
基本信息
| 分区 | 集合下的子集,创建后可指定检索范围 |
|---|---|
| 分区键 | 建集合时用 is_partition_key 声明的字段 |
| 查询方式 | 分区用 partition_names,分区键用 filter 条件 |
| 适用维度 | 少而清晰用分区,多而自动扩展用分区键 |
| 代价 | 分区数量过多带来元数据与调度开销 |
典型使用场景
- 多租户隔离:按租户键分区,查询天然不跨租户
- 业务线隔离:不同产品线数据分开放,减少互相干扰
- 冷热分离:把历史数据放独立分区,日常查询不扫描
- 批量重建:新分区灌好数据后切换,避免原地重建影响线上
- 权限边界:物理隔离配合应用层过滤,双重保证不越权
手动分区
手动分区
client.create_partition('kb', partition_name='tenant_42')
client.insert('kb', data=rows, partition_name='tenant_42')
res = client.search('kb', data=[q_vec], limit=10,
partition_names=['tenant_42'],
output_fields=['source']) # 只在指定分区内检索分区键(建集合时指定)
分区键(建集合时指定)
schema.add_field('tenant_id', datatype='VARCHAR', max_length=32,
is_partition_key=True)
# 写入时按 tenant_id 自动路由;查询必须在 filter 中带上该字段才生效
res = client.search('kb', data=[q_vec], limit=10,
filter='tenant_id == "t-42"')分区与分区键对比
| 维度 | 手动分区 | 分区键 |
|---|---|---|
| 建立方式 | 显式创建并指定名字 | 建集合时声明字段,自动路由 |
| 适用基数 | 少而固定 | 多且持续新增 |
| 查询写法 | partition_names 参数 | filter 条件中带键值 |
| 主要风险 | 分区数量过多,元数据开销上升 | 键值选择不当会导致负载倾斜 |
分区键查询忘记带对应过滤条件,会退化成跨所有分区扫描:既失去隔离收益,也可能把别的租户数据召回到上下文里,属于安全与性能双重问题。