文章目录
-
- python连接milvus数据库
-
- [1、采用配置文件的形式 # .env文件(支持多数据源)](# .env文件(支持多数据源))
- 查询
- 删除-单条数据
- 删除-批量删除
- 报错
-
-
- [报错 pymilvus.exceptions.MilvusException: <MilvusException: (code=65535, message=fail to search on QueryNode 1: worker(1) query failed: parser searchRequest failed: => ==vector dimension mismatch, expected vector size(byte) 512, actual 16==. at /go/src/github.com/milvus-io/milvus/internal/core/src/query/Plan.cpp:76](#报错 pymilvus.exceptions.MilvusException: <MilvusException: (code=65535, message=fail to search on QueryNode 1: worker(1) query failed: parser searchRequest failed: => ==vector dimension mismatch, expected vector size(byte) 512, actual 16==. at /go/src/github.com/milvus-io/milvus/internal/core/src/query/Plan.cpp:76)
- milvus集合数据为什么需要先加载?
-
- 文档
chromadb是轻量级向量库,那么milvus则是企业级向量库,必须会用。
是通过什么形式管理milvus的呢? sql命令? api接口?
推荐用api接口,规范及体系已经很成熟。
规范是v2:
sdk v2 # sdk形式的v2版本,pymilvus包已基本实现
restful api v2 # rest形式的v2版本
文中用的pymilvus版本为2.6.11。
为了方便,文中大量使用from custom_milvus_client import client。
python连接milvus数据库
采用最标准的方式,实现如下:
1、采用配置文件的形式 # .env文件
2、封装milvusClient工具类
3、实现调用
1、采用配置文件的形式 # .env文件(支持多数据源)
替换密码为实际的数据库密码。
(1)项目下创建.env文件,内容:
python
MILVUS_URI=http://c-a9d8c17bbd5c5d2a.milvus.aliyuncs.com:19530
MILVUS_USERNAME=root
MILVUS_PASSWORD=实际的密码
MILVUS_DB_NAME=default
MILVUS_DB_NAME_SECOND=second_milvus
(2)项目下创建config.py,内容:
python
# config.py
from pydantic_settings import BaseSettings, SettingsConfigDict
class Settings(BaseSettings):
# Milvus 配置
milvus_uri: str
milvus_username: str
milvus_password: str
milvus_db_name: str = "default",
milvus_db_name_second: str = "default"
# 其他配置...
debug: bool = False
model_config = SettingsConfigDict(env_file=".env", extra="ignore")
# 创建一个全局实例(单例模式)
# 这样你在 main.py 里直接 `from config import settings` 就能用了
settings = Settings()
2、封装milvusClient工具类
创建custom_milvus_client.py,代码:
python
from pymilvus import MilvusClient
from config import settings # 导入你之前写好的配置
# 1. 初始化客户端
# 使用 settings 中的参数进行连接
# 注意:MilvusClient 的 token 参数格式通常是 "user:password"
client = MilvusClient(
uri=settings.milvus_uri,
token=f"{settings.milvus_username}:{settings.milvus_password}",
db_name=settings.milvus_db_name # <--- 动态指定
)
print(f"✅ Milvus 客户端已初始化,连接地址: {settings.milvus_uri}")
# 2. 实例化一个专门连 销售 库的客户端
second_client = MilvusClient(
uri=settings.milvus_uri,
token=f"{settings.milvus_username}:{settings.milvus_password}",
db_name=settings.milvus_db_name_second # <--- 初始化时定死
)
print(f"✅ Milvus sencond客户端已初始化,连接地址: {settings.milvus_uri}")
3、实现调用
替换集合名称为实际的集合名称。
替换查询向量为实际的维度向量(如128维数组)。
创建milvus_demo.py,代码:
python
# main.py
# 方式一:直接导入封装好的 client 实例(最简单)
from custom_milvus_client import client,second_client
def search_example():
collection_name = "fashion_item"
# 简单的查询示例
query_vector = [[0.8205300569534302,0.4099404215812683,0.39627617597579956,-0.7741699814796448,-0.4928055703639984,0.3399009704589844,0.3189021348953247,0.5187330842018127,0.2883453965187073,-0.7719671130180359,-0.08381801098585129,-0.8046928644180298,-0.1952885240316391,0.12886777520179749,-0.2597646117210388,-0.17221087217330933,-0.9784966111183167,-0.5716061592102051,0.37882983684539795,-0.34292125701904297,-0.6309902667999268,0.27827078104019165,-0.47276338934898376,0.1738283783197403,0.9165683388710022,-0.5660313367843628,-0.3803914785385132,-0.30034804344177246,0.6518695950508118,0.6775507926940918,0.17429892718791962,0.7504568696022034,0.6146184206008911,-0.17610716819763184,-0.7063156366348267,-0.8314393758773804,-0.3886834979057312,0.842677652835846,-0.8377030491828918,0.1993316113948822,-0.9610193967819214,0.7499078512191772,0.4662572145462036,-0.811089038848877,0.3537338376045227,-0.7749398350715637,0.559476375579834,0.5925202369689941,-0.2932983636856079,0.079729363322258,-0.89405357837677,-0.48456451296806335,0.7873122692108154,-0.41849103569984436,0.8095035552978516,0.8411709070205688,0.24906544387340546,-0.2396702617406845,-0.8429192900657654,-0.6976824998855591,0.24479956924915314,-0.266379177570343,-0.25824326276779175,-0.3464970886707306,0.5343883037567139,0.7019475698471069,0.6393605470657349,0.32661187648773193,-0.1667490005493164,-0.3554096519947052,-0.8155046701431274,0.6531398892402649,-0.5637432932853699,0.06950384378433228,0.47567635774612427,-0.30726751685142517,-0.7929423451423645,-0.7991929650306702,0.048295482993125916,-0.30530187487602234,0.3513074517250061,-0.30239230394363403,0.8689589500427246,0.03430260717868805,0.3641439378261566,0.2765483856201172,-0.6383322477340698,0.8168131113052368,0.9978047609329224,0.8768131136894226,-0.09796279668807983,0.24167074263095856,0.02407880872488022,-0.7623790502548218,-0.20949691534042358,-0.23544828593730927,-0.6273159980773926,-0.8625620603561401,0.8881083726882935,0.8987827301025391,-0.780926525592804,0.6973945498466492,0.6470697522163391,-0.12261192500591278,0.3772689700126648,-0.044691625982522964,0.5931768417358398,0.6109945774078369,-0.9108550548553467,0.09018359333276749,-0.4908239245414734,-0.7361722588539124,0.48472604155540466,0.7651014924049377,-0.38261428475379944,0.8098018765449524,0.5474557876586914,0.09784401953220367,0.7661294937133789,0.26230376958847046,0.15331418812274933,0.8528333306312561,0.3935127556324005,-0.6476650834083557,0.3295937478542328,-0.22980983555316925,-0.7503023743629456,-0.2237066775560379]] # 示例向量
print("正在查询 Milvus...")
# 使用 MilvusClient 的 search 方法
res = client.search(
collection_name=collection_name,
data=query_vector,
limit=3,
output_fields=["*"]
)
res2 = second_client.search(
collection_name=collection_name,
data=query_vector,
limit=3,
output_fields=["*"]
)
print("查询结果:", res)
print("查询结果:", res2)
if __name__ == "__main__":
search_example()
查询
主要有如下方法:
search() # 查询向量用search
query() # 常规查询用query
hybrid_search() # 混合检索,例如根据两个向量查询
search()方法
anns_field # 有多个向量字段时,指定根据哪个向量查询
可以只查常规字段(也就是scalar标量)吗?
当然可以,用query()方法即可。
search()方法可以查常规字段吗?
可以,但是不推荐,因为也会尝试查询向量,非常不推荐。
查询总条数-快速但非实时(有数秒延迟)
python
from custom_milvus_client import client
# 获取统计信息
stats = client.get_collection_stats("fashion_item")
# 解析条数
count = stats['row_count']
print(f"fashion_item 集合总条数: {count}")
一个集合有两个向量字段,如何指定根据某个查询?
用anns_field字段指定,如:
python
results_1 = client.search(
collection_name="multi_vector_demo",
data=[query_vector], # 查询数据
anns_field="vector_1", # 👈 关键:指定使用 vector_1 字段
limit=3, # 返回最相似的 3 条
output_fields=["username", "search_text"] # 指定返回哪些非向量字段
)
根据两个向量一起查询 (混合检索)
混合检索的要点是分别定义两个请求,作为reqs传进去,并分别指定权重,再查询。
代码:
python
from custom_milvus_client import client
import random
from pymilvus import AnnSearchRequest, WeightedRanker
# ==========================================
# 1. 模拟数据准备 (在实际业务中,这里通常由 Embedding 模型生成)
# ==========================================
# 假设你的向量维度是 4 维 (根据之前的上下文)
# 模拟一个 "图片特征" 查询向量
query_vector_img = [round(random.random(), 4) for _ in range(4)]
# 模拟一个 "文本特征" 查询向量
query_vector_txt = [round(random.random(), 4) for _ in range(4)]
print(f"🔍 准备查询 - 图片向量: {query_vector_img}")
print(f"🔍 准备查询 - 文本向量: {query_vector_txt}")
# ==========================================
# 2. 构建搜索请求
# ==========================================
# 请求 1: 针对 vector_1 (图片) 的搜索
req_img = AnnSearchRequest(
data=[query_vector_img],
anns_field="vector_1", # 指定字段
param={"metric_type": "COSINE", "params": {"nprobe": 10}}, # 搜索参数
limit=10 # 召回数量 (混合检索通常先多召回一点)
)
# 请求 2: 针对 vector_2 (文本) 的搜索
req_txt = AnnSearchRequest(
data=[query_vector_txt],
anns_field="vector_2", # 指定字段
param={"metric_type": "COSINE", "params": {"nprobe": 10}},
limit=10
)
# 将两个请求放入列表
reqs = [req_img, req_txt]
# ==========================================
# 3. 执行混合检索 (Hybrid Search)
# ==========================================
try:
# 核心代码:调用 hybrid_search
# ranker=WeightedRanker(0.5, 0.5) 表示图片和文本权重各占 50%
results = client.hybrid_search(
collection_name="multi_vector_demo",
reqs=reqs,
ranker=WeightedRanker(0.5, 0.5),
limit=5, # 最终返回 Top 5 个结果
output_fields=["username"] # 返回额外字段
)
# ==========================================
# 4. 打印结果
# ==========================================
print("\n✅ 混合检索结果如下:")
for hits in results:
for hit in hits:
# hit 包含 id, distance (融合后的分数), 和 entity (包含 output_fields)
print(f"ID: {hit.id} | 融合分数: {hit.distance:.4f} | 用户名: {hit.entity.get('username')}")
except Exception as e:
print(f"❌ 检索失败: {e}")
新建集合(schema表结构)
通过代码的方式新建表结构:
python
from custom_milvus_client import client
from pymilvus import DataType
collection_name = "multi_vector_demo"
# 1. 初始化 Schema
# auto_id=True 表示 id 由数据库自动生成,如果需手动指定 id 则设为 False
schema = client.create_schema(auto_id=True, enable_dynamic_field=False)
# 2. 添加字段
# --- 主键字段 ---
# 注意:如果 auto_id=True,这里只需定义类型和主键属性,不需要手动插入 id
schema.add_field(field_name="id", datatype=DataType.INT64, is_primary=True)
# --- 标量字段 (元数据) ---
schema.add_field(field_name="username", datatype=DataType.VARCHAR, max_length=256)
schema.add_field(field_name="search_text", datatype=DataType.VARCHAR, max_length=2048)
# --- 向量字段 1 ---
# dim=4 对应你要求的 4 维向量
schema.add_field(field_name="vector_1", datatype=DataType.FLOAT_VECTOR, dim=4)
# --- 向量字段 2 ---
schema.add_field(field_name="vector_2", datatype=DataType.FLOAT_VECTOR, dim=4)
# 3. 准备索引参数
# 在创建集合的同时定义索引,可以一步到位完成部署
index_params = client.prepare_index_params()
# 为 vector_1 添加索引 (使用默认的 AUTOINDEX 或指定 IVF_FLAT)
index_params.add_index(
field_name="vector_1",
metric_type="COSINE", # 相似度度量方式:COSINE, L2, IP
index_type="AUTOINDEX" # 自动选择最适合的索引类型
)
# 为 vector_2 添加索引
index_params.add_index(
field_name="vector_2",
metric_type="COSINE",
index_type="AUTOINDEX"
)
# 为 username 添加标量索引 (可选,但推荐,用于加速过滤)
index_params.add_index(
field_name="username",
index_type="INVERTED" # 倒排索引,适合字符串精确匹配
)
# 4. 创建集合
# 如果集合已存在,建议先删除或捕获异常
try:
client.create_collection(
collection_name=collection_name,
schema=schema,
index_params=index_params
)
print(f"集合 '{collection_name}' 创建成功!")
except Exception as e:
print(f"创建集合时出错(可能已存在): {e}")
为什么会有延迟呢?
get_collection_stats()返回的数字是最近一次系统记账时的结果,而不是"现在的结果"。
适用于做监控,大屏等对数据精确度要求不高的场景。
查询总条数-实时
这个就是直接查库了。
python
from custom_milvus_client import client
# 使用 count(*) 聚合查询
res = client.query(
collection_name="fashion_item",
filter="", # 空过滤表示查询所有
output_fields=["count(*)"]
)
# 解析结果
count = res[0].get("count(*)")
print(f"fashion_item 实时精准条数: {count}")
新增
milvus新增和修改并没有拆分开,而是用一个方法来实现upsert()。
修改-先查询再修改
替换collection_name为实际集合名。
替换target_id为实际id。
python
from custom_milvus_client import client
target_id = -184695224
# 1. 先查出旧数据,把原来的 embedding 捞出来
res = client.query(
collection_name="fashion_item",
filter=f"id == {target_id}",
output_fields=["embedding"] # 只查向量字段
)
if not res:
print("未找到该商品")
else:
# 2. 取出旧的 embedding
old_embedding = res[0].get("embedding")
# 3. 组装完整数据 (保留旧向量,更新新字段)
data_to_update = [{
"id": target_id,
"price": 299.0,
"product_name": "春季新款风衣",
"embedding": old_embedding # 【关键】把查出来的旧向量放回去
}]
# 4. 执行 upsert (不需要 partial_update,因为数据是完整的)
res = client.upsert(
collection_name="fashion_item",
data=data_to_update
)
print("更新成功")
修改-全量字段
替换collection_name为实际集合名。
替换target_id为实际id。# 如果不替换也行,相当于新增。
python
from custom_milvus_client import client
import random
# 1. 构造数据
# 既然不查询,我们就必须手动编造一个 128 维的向量填进去,否则报错
# 这里生成一个随机的 128 维向量作为占位符
dummy_embedding = [random.uniform(-1, 1) for _ in range(128)]
data = [{
"id": 101, # 指定要修改的主键
"price": 299.0, # 修改价格
"product_name": "春季风衣", # 修改名称
"embedding": dummy_embedding # 【必须】手动补全向量字段,否则会报 fieldSchema 错误
}]
# 2. 执行 upsert
# 注意:这里不要加 partial_update=True,因为我们提供了完整字段(虽然向量是假的)
res = client.upsert(
collection_name="fashion_item",
data=data
)
print(f"更新完成。注意:embedding 已被重置为随机向量")
修改-只修改一个字段
python
from custom_milvus_client import client
# 1. 准备要修改的数据(只包含主键和要修改的字段)
data_to_update = [{
"id": 101, # 必须提供主键,定位数据
"price": 299.0, # 修改价格
"product_name": "春季新款风衣333" # 修改名称
# 注意:这里故意不提供 embedding
}]
# 2. 执行 Upsert
try:
res = client.upsert(
collection_name="fashion_item",
data=data_to_update,
partial_update=True # 【核心关键】开启局部更新
# 告诉 Milvus:只更新我提供的字段,没提供的字段(如 embedding)保持原样
)
print(f"修改成功,影响行数: {res.get('upsert_count', 0)}")
except Exception as e:
print(f"修改失败: {e}")
删除-单条数据
python
from custom_milvus_client import client
target_id = 101 # 假设你要删除 ID 为 101 的商品
# 执行删除
res = client.delete(
collection_name="fashion_item",
ids=[target_id] # 传入一个 ID 列表,即使只有一个 ID
)
print(f"删除成功,共删除 {res.get('delete_count', 0)} 条数据")
删除-批量删除
python
from custom_milvus_client import client
ids_to_delete = [101, 102, 105]
res = client.delete(
collection_name="fashion_item",
ids=ids_to_delete
)
print(f"批量删除完成,共删除 {res.get('delete_count', 0)} 条数据")
注:删除的时候是逻辑条数,不是物理条数,即使ids实际不存在,这里还会打印出3条,所以这个当不得真。
报错
报错 pymilvus.exceptions.MilvusException: <MilvusException: (code=65535, message=fail to search on QueryNode 1: worker(1) query failed: parser searchRequest failed: => vector dimension mismatch, expected vector size(byte) 512, actual 16. at /go/src/github.com/milvus-io/milvus/internal/core/src/query/Plan.cpp:76
重点在这一句:
bash
vector dimension mismatch, expected vector size(byte) 512, actual 16
翻译:向量维度不匹配,期待的维度是512,实际是16。
看了下确实是,数据库是128维,传的是4维,改为128维即可。
注:具体大小和浮点数精度有关,例如数据库这里用的是float32(32位4字节)
所以数据库float32的128维=128*4=512字节长度,报错时提示512。
milvus集合数据为什么需要先加载?
因为采用的是存储和计算分离的策略,数据存储在磁盘上,当需要计算时,加载到内存中。
这就是为什么需要加载的原因,如果所有数据都放到内存中,太贵了,消耗不起。
生成指定维度的向量
例如需要128维的数据,一行代码搞定:
python
import random
query_vector = [round(random.random(), 4) for _ in range(4)]
给大模型的话术?
为了避免大模型每次生成都从头开始创建client,可以给如下话术:
bash
client已经创建好,省掉创建client的代码,后续的代码只需先导入,关注业务即可:
from custom_milvus_client import client
文档
Python SDK v2 (pymilvus)
文档地址: Milvus Python SDK v2.5.x API Reference
核心类: pymilvus.MilvusClient (这是 v2 版本推荐使用的统一客户端)
RESTful API v2
文档地址: Milvus RESTful API v2.5.x Reference
用途: 如果你不使用 SDK,而是通过 HTTP/JSON 调用,请参考此文档。