Milvus
本文最后更新于 2026年8月10日
未完待续
概述
Milvus是一个云原生向量数据库,采用存算分离架构,支持向量相似度与标量过滤的混合查询,能在毫秒级完成十亿级向量检索,并可按需选择强一致或最终一致等多种一致性等级。
从业务角度,milvus的数据模型层级是:Database => Collection => Partition => Entity
- Database 数据库,隔离不同业务数据
- Collection 核心的逻辑容器,类似mysql的table
- Partition 分区,是collection的子集,不是必须创建,而且一个collection至少有默认partition
- Entity collection中的一条记录,类似MySQL的一行数据
1.部署和配置
milvus部署方式很多,支持大规模部署在k8s,这里为了学习研究采用docker-compose安装Milvus,以2.6.19版本为例,docker-compose文件从官方github下载即可:https://github.com/milvus-io/milvus/
启动前,先修改docker-compose文件启用认证,否则就算重置了密码仍然能免密登录,找到milvus-standalone,新增common.security.authorizationEnabled: "true",这个是2.6.x版本的做法
... ...
standalone:
container_name: milvus-standalone
image: milvusdb/milvus:v2.6.19
... ...
environment:
... ...
common.security.authorizationEnabled: "true"
... ...然后docker compose启动即可,启动后,有三个容器,还监听了不止一个端口
[root@rocky102 ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
47d071e552f2 milvusdb/milvus:v2.6.19 "/tini -- milvus run…" 25 minutes ago Up 25 minutes (healthy) 0.0.0.0:9091->9091/tcp, [::]:9091->9091/tcp, 0.0.0.0:19530->19530/tcp, [::]:19530->19530/tcp milvus-standalone
a6e864be674d minio/minio:RELEASE.2024-12-18T13-15-44Z "/usr/bin/docker-ent…" 25 minutes ago Up 25 minutes (healthy) 0.0.0.0:9000-9001->9000-9001/tcp, [::]:9000-9001->9000-9001/tcp milvus-minio
c4d5ee2d0bf6 quay.io/coreos/etcd:v3.5.25 "etcd -advertise-cli…" 25 minutes ago Up 25 minutes (healthy) 2379-2380/tcp milvus-etcd19530端口用于连接数据库,9091端口还运行着webui,9000-9001的minio也在运行,以及etcd的2379,为了安全,建议除了19530端口外,其余端口不要暴露

然后,修改用户名密码,先用默认的用户名root,密码Milvus登录进去,然后马上修改密码,连接milvus可以使用工具Attu:https://github.com/zilliztech/attu/
attu应该也是使用某些web包壳工具开发而成,每次数据库对象变动,需要点击View->Reload按钮刷新才能实时展现

除了安装版客户端软件,Attu也有web版的,可以部署后浏览器上使用
docker run -d --network host -e MILVUS_URL=127.0.0.1:19530 zilliz/attu:v2.6.52.Milvus Python API
使用python操作milvus,需安装pymilvus模块
pip install pymilvus2.1 Database API
2.1.1 连接
还可通过MilvusClient的db_name=''参数指定一个库
import os
from dotenv import load_dotenv
from pymilvus import MilvusClient, utility
load_dotenv(encoding='utf-8')
MILVUS_HOST = os.getenv('MILVUS_HOST')
MILVUS_PORT = os.getenv('MILVUS_PORT')
MILVUS_KEY = os.getenv('MILVUS_KEY')
try:
client = MilvusClient(
uri=f'http://{MILVUS_HOST}:{MILVUS_PORT}',
password=MILVUS_KEY,
user="root"
)
print("登录成功")
except Exception as e:
print(f":{e}")2.1.2 获取数据库
dbs = client.list_databases()
for db in dbs:
print(db)2.1.3 建库和删库
创建
dbs = client.list_databases()
name = 'rag_demo'
if name not in dbs:
client.create_database(name)删除,如果下面有collection则无法删除,需要先删除collection
dbs = client.list_databases()
name = 'rag_demo'
if name in dbs:
client.drop_database(db_name=name)切换数据库
name = 'rag_demo'
client.use_database(name)2.2 Collection API
2.2.1 获取Collection
use_database执行后,后续都默认在rag_demo下操作
name = 'rag_demo'
client.use_database(name)
cols = client.list_collections()
print(cols)2.2.2 创建collection
创建collection,指定向量维度1024个,采用余弦相似度
亲测当不指定schema直接创建,会自动创建id,vector字段,并默认启用动态字段,id默认不自增,向量维度和collection名称必须指定
name = 't_doc'
client.create_collection(
collection_name=name,
dimension=1024,
metric_type='COSINE'
)除此外,还能设置
auto_id=True是否自增enable_dynamic_field=False是否启用动态字段
Collections 中的动态字段是一个保留的 JavaScript Object Notation (JSON) 字段,名为$meta。启用该字段后,Milvus 会将每个实体中携带的所有非 Schema 定义字段及其值作为键值对保存在保留字段中。
2.2.3 删除collection
name = 't_doc'
client.drop_collection(collection_name=name)2.2.4 描述信息
元信息描述
name = 't_doc'
metadata = client.describe_collection(collection_name=name)
print(metadata){
'collection_name': 't_doc',
'auto_id': False,
'num_shards': 1,
'description': '',
'fields': [
{
'field_id': 100,
'name': 'id',
'description': '',
'type': <DataType.INT64: 5>,
'params': {},
'is_primary': True
},
{
'field_id': 101,
'name': 'vector',
'description': '',
'type': <DataType.FLOAT_VECTOR: 101>,
'params': {'dim': 1024}
}
],
'functions': [],
'aliases': [],
'collection_id': 468082018063159696,
'consistency_level': 2,
'consistency_level_name': 'Bounded',
'properties': {'timezone': 'UTC'},
'num_partitions': 1,
'enable_dynamic_field': True,
'enable_namespace': False,
'schema_version': 0,
'created_timestamp': 468092261983584273,
'update_timestamp': 468092261983584273
}2.2.5 判断存在
name = 't_doc'
b=metadata = client.has_collection(collection_name=name)
print(b)2.3 Schema API
Schema定义了Collections的数据结构。在创建一个Collection之前,需要设计出它的Schema,Schema有一个主键、至少一个向量字段和几个标量字段
使用时,要先创建出schema对象,再通过add_field()方法指定各个列定义,再在创建collection时指定schema
schema = MilvusClient.create_schema()client.create_collection(
collection_name="customized_setup_2",
schema=schema
)2.3.1 主键字段
is_primary=True指定ID字段datatype=DataType.INT64默认Int64,可以改用VarCharauto_id=True,自增
schema.add_field(
field_name="my_id",
datatype=DataType.INT64,
is_primary=True,
auto_id=True
)2.3.2 向量字段
当前版本的milvus支持最多10个向量字段(实测),不同于文档上说的4个,dim=1024表示的是向量的维度,DataType.FLOAT_VECTOR代表向量字段支持32位浮点数列表,还支持以下位数:
FLOAT16_VECTOR 这种类型的向量场保存一个 16 位半精度浮点数列表,通常适用于内存或带宽受限的深度学习或基于 GPU 的计算场景。
BFLOAT16_VECTOR 这种类型的向量字段保存 16 位浮点数列表,精度有所降低,但指数范围与 Float32 相同。这种类型的数据常用于深度学习场景,因为它能在不明显影响精度的情况下减少内存使用量。
INT8_VECTOR 这种类型的向量字段存储由 8 位有符号整数(int8)组成的向量,每个分量的范围为-128 到 127。它专为量化深度学习架构(如 ResNet 和 EfficientNet)量身定做,可大幅缩小模型大小,提高推理速度,同时只造成极小的精度损失。注:该向量类型仅支持 HNSW 索引。
BINARY_VECTOR 这种类型的向量场保存着一个 0 和 1 的列表。在图像处理和信息检索场景中,它们是表示数据的紧凑特征。
SPARSE_FLOAT_VECTOR 该类型的向量场可保存非零数字及其序列号列表,用于表示稀疏向量嵌入。
schema.add_field(
field_name="my_vector1",
datatype=DataType.FLOAT_VECTOR,
dim=1024
)2.3.3 其他字段
字符串,整数,布尔,以及数组和JSON等复合型字段
schema.add_field(
field_name="my_varchar",
datatype=DataType.VARCHAR,
max_length=512
)
schema.add_field(
field_name="my_int64",
datatype=DataType.INT64
)
schema.add_field(
field_name="my_bool",
datatype=DataType.BOOL
)
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,
)2.3.4 动态字段
创建schema时指定enable_dynamic_field=是否启用动态字段,如启用,该字段以名为$meta的隐藏JSON字段实现,它会自动存储数据中任何未在schema中明确定义的字段。
schema = client.create_schema(
enable_dynamic_field=True,
)2.4 DML API
关于数据的编辑
2.4.1 添加数据
通过维度同是1024的嵌入模型qwen3.7-text-embedding,将一组文本转换为向量,连同内容一起插入到milvus中,并flush()落盘
from dotenv import load_dotenv
from openai import OpenAI
import os
from pymilvus import MilvusClient, utility
load_dotenv(encoding='utf-8')
MILVUS_HOST = os.getenv('MILVUS_HOST')
MILVUS_PORT = os.getenv('MILVUS_PORT')
MILVUS_KEY = os.getenv('MILVUS_KEY')
client = OpenAI(
api_key=os.getenv('QWEN_KEY'),
base_url='https://llm-aryq90lbx0u4xri7.cn-beijing.maas.aliyuncs.com/compatible-mode/v1',
)
texts = [
"中国河北发生滦河第一号洪水",
"菲律宾和中国就南海问题进行交涉",
"武大靖被韩国人在ins上谩骂",
"日本政府决定将核污染水进行排海",
"中华人民共和国全运会在天津开幕",
"在中国的调节下,沙特和伊朗和解",
"谷爱凌在2022北京冬奥会上获得滑雪冠军",
"缅甸曼德勒发生8.0级地震",
"无法忍受北约东扩,俄罗斯进攻乌克兰",
"湘潭大学周立人因投毒被判处死刑",
"全红婵在东京奥运会获得跳水金牌"
]
try:
res = client.embeddings.create(
model="qwen3.7-text-embedding",
input=texts,
)
data = [
{
"id": i,
"vector": res.data[i].embedding,
"text": texts[i],
"source": "demo"
}
for i in range(len(texts))
]
client = MilvusClient(
uri=f'http://{MILVUS_HOST}:{MILVUS_PORT}',
password=MILVUS_KEY,
user="root",
db_name='rag_demo'
)
insert_res = client.upsert(
collection_name='t_doc',
data=data,
)
print("insert result : ", insert_res)
client.flush(collection_name='t_doc')
except Exception as e:
print(f":{e}")insert result : {'upsert_count': 11, 'ids': [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]}2.4.2 状态
name = 't_doc'
stats = client.get_collection_stats(collection_name=name)
print(stats) #{'row_count': 11}2.5 DQL API
关于数据查询
2.5.1 查询全部
name = 't_doc'
iterator = client.query_iterator(
collection_name=name,
filter="",
output_fields=["*"]
)
while True:
rows = iterator.next()
if not rows:
break
for row in rows:
print(f"id : {row["id"]},vector = {row["vector"][:5]}......,text = {row["text"]},source = {row["source"]}")
iterator.close()id : 0,vector = [0.023675184696912766, -0.005329845007508993, -0.010327795520424843, -0.007353754714131355, 0.03331966698169708]......,text = 中国河北发生滦河第一号洪水,source = demo
id : 1,vector = [0.03367263078689575, 0.0308539941906929, 0.0456014983355999, -0.05586938560009003, -0.04142387956380844]......,text = 菲律宾和中国就南海问题进行交涉,source = demo
id : 2,vector = [0.022217441350221634, 0.08715223520994186, 0.03312373906373978, 0.0017420633230358362, 0.014378155581653118]......,text = 武大靖被韩国人在ins上谩骂,source = demo
id : 3,vector = [0.026949338614940643, -0.025609316304326057, -0.011805844493210316, -0.06710037589073181, -0.01656416431069374]......,text = 日本政府决定将核污染水进行排海,source = demo
id : 4,vector = [0.023202229291200638, 0.03087700717151165, -0.040330708026885986, 9.698700159788132e-05, -0.03369786962866783]......,text = 中华人民共和国全运会在天津开幕,source = demo
id : 5,vector = [0.030343549326062202, 0.1002483069896698, -0.03368183597922325, -0.02625788189470768, -0.028873704373836517]......,text = 在中国的调节下,沙特和伊朗和解,source = demo
id : 6,vector = [0.017193175852298737, 0.05799376219511032, -0.049061913043260574, 0.0675581768155098, -0.012638692744076252]......,text = 谷爱凌在2022北京冬奥会上获得滑雪冠军,source = demo
id : 7,vector = [0.03244605287909508, 0.015612950548529625, 0.04743647575378418, 0.00950597133487463, 0.023170415312051773]......,text = 缅甸曼德勒发生8.0级地震,source = demo
id : 8,vector = [0.02195076085627079, 0.07907696813344955, 0.034633148461580276, 0.00758601538836956, 0.020570363849401474]......,text = 无法忍受北约东扩,俄罗斯进攻乌克兰,source = demo
id : 9,vector = [0.0225443746894598, -0.00823928415775299, -0.012978585436940193, -0.0132401492446661, 0.0005052244523540139]......,text = 湘潭大学周立人因投毒被判处死刑,source = demo
id : 10,vector = [0.023601844906806946, 0.0007014941074885428, 0.0010958664352074265, 0.06690911948680878, 0.03573780879378319]......,text = 全红婵在东京奥运会获得跳水金牌,source = demo2.5.2 根据ID
name = 't_doc'
res = client.get(
collection_name=name,
ids=[0,1]
)
for i in range(len(res)):
print(f"id : {res[i]["id"]},vector = {res[i]["vector"][:5]},text = {res[i]["text"]},source = {res[i]["source"]}")2.4.3 相似度检索
将待查关键字通过嵌入模型转化为向量,传给milvus进行检索,取出最匹配的前6个,并指定返回字段:["text", "source", "id"]
from dotenv import load_dotenv
from openai import OpenAI
import os
from pymilvus import MilvusClient, utility
load_dotenv(encoding='utf-8')
MILVUS_HOST = os.getenv('MILVUS_HOST')
MILVUS_PORT = os.getenv('MILVUS_PORT')
MILVUS_KEY = os.getenv('MILVUS_KEY')
client = OpenAI(
api_key=os.getenv('QWEN_KEY'),
base_url='https://llm-aryq90lbx0u4xri7.cn-beijing.maas.aliyuncs.com/compatible-mode/v1',
)
try:
res = client.embeddings.create(
model="qwen3.7-text-embedding",
input=['体育赛事'],
)
vector = res.data[0].embedding
client = MilvusClient(
uri=f'http://{MILVUS_HOST}:{MILVUS_PORT}',
password=MILVUS_KEY,
user="root",
db_name='rag_demo'
)
results = client.search(
collection_name='t_doc',
data=[vector],
anns_field='vector',
limit=6,
output_fields=["text", "source", "id"]
)
for res in results[0]:
print(res)
except Exception as e:
print(e){'id': 4, 'distance': 0.4277065396308899, 'entity': {'id': 4, 'text': '中华人民共和国全运会在天津开幕', 'source': 'demo'}}
{'id': 2, 'distance': 0.2563920021057129, 'entity': {'id': 2, 'text': '武大靖被韩国人在ins上谩骂', 'source': 'demo'}}
{'id': 6, 'distance': 0.2262747436761856, 'entity': {'id': 6, 'text': '谷爱凌在2022北京冬奥会上获得滑雪冠军', 'source': 'demo'}}
{'id': 0, 'distance': 0.22332191467285156, 'entity': {'id': 0, 'text': '中国河北发生滦河第一号洪水', 'source': 'demo'}}
{'id': 5, 'distance': 0.18999835848808289, 'entity': {'id': 5, 'text': '在中国的调节下,沙特和伊朗和解', 'source': 'demo'}}
{'id': 7, 'distance': 0.17732326686382294, 'entity': {'id': 7, 'text': '缅甸曼德勒发生8.0级地震', 'source': 'demo'}}"如果文章对您有帮助,可以请作者喝杯咖啡吗?"
微信支付
支付宝