接上篇,本文主要介绍 Milvus 数据库的连接方法,以及图片相关数据(向量+元数据)的保存程序逻辑实现 。
一、Milvus 数据库连接
1. 安装 Milvus
首先需要安装 pymilvus
库,确保版本与 Milvus 服务端兼容(建议使用最新稳定版):
pip install pymilvus==2.4.5 # 版本需与 Milvus 服务端匹配,可根据实际情况调整
2. 初始化连接
连接 Milvus 需指定服务端的 主机地址(host) 和 gRPC 端口(默认 19530)。如果 Milvus 启用了认证,还需要提供用户名和密码。
from pymilvus import connections
# 连接 Milvus 服务
connections.connect(
alias="default", # 连接别名(可自定义,用于后续操作)
host="localhost", # Milvus 服务的主机地址,如远程服务器则填IP
port="19530", # 默认 gRPC 端口,HTTP 端口为 9091(较少用)
# 若启用认证,需添加以下参数
# user="username",
# password="password"
)
# 验证连接是否成功
print("连接状态:", connections.has_connection("default")) # 输出 True 表示连接成功
- 注意:连接前需确保 Milvus 服务已启
3. 关闭连接(可选)
操作完成后,可关闭连接释放资源:
connections.disconnect("default") # 关闭指定别名的连接
二、图片在 Milvus 中的保存逻辑
Milvus 不直接存储图片文件,而是存储图片的特征向量(通过模型提取的高维向量)和关联的元数据(如图片 ID、路径、描述等)通过元数据与 Milvus 中的向量关联。
完整流程:图片加载 → 特征向量提取 → 创建 Milvus 集合 → 插入向量+元数据。
1. 图片加载与特征向量提取
需使用预训练模型(如 ResNet、CLIP 等)将图片转换为向量。以下以 ResNet50 为例(需安装 torch
、torchvision
、PIL
):
import torch
from torchvision import models, transforms
from PIL import Image
import numpy as np
# 加载预训练的 ResNet50 模型(用于提取图片特征)
model = models.resnet50(pretrained=True)
# 移除最后一层分类层,保留特征提取部分
feature_extractor = torch.nn.Sequential(*list(model.children())[:-1])
feature_extractor.eval() # 切换到评估模式
# 图片预处理(与模型训练时的预处理一致)
preprocess = transforms.Compose([
transforms.Resize(256),
transforms.CenterCrop(224),
transforms.ToTensor(),
transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]),
])
def extract_image_vector(image_path):
"""将图片转换为特征向量"""
# 加载图片
img = Image.open(image_path).convert('RGB')
# 预处理
img_tensor = preprocess(img).unsqueeze(0) # 增加 batch 维度
# 提取特征(关闭梯度计算加速)
with torch.no_grad():
features = feature_extractor(img_tensor)
# 转换为一维向量(ResNet50 输出为 2048 维)
vector = features.squeeze().numpy() # 形状为 (2048,)
return vector
# 示例:提取一张图片的向量
image_path = "test.jpg"
vector = extract_image_vector(image_path)
print("向量维度:", vector.shape) # 输出 (2048,)
2. 创建 Milvus 集合(Collection)
集合是 Milvus 中存储数据的基本单元,需定义** schema **(包含字段名、类型、是否为主键等)。对于图片向量,通常需要:
- 主键字段(如
image_id
,用于唯一标识图片); - 向量字段(如
vector
,存储图片的特征向量,需指定维度); - 元数据字段(如
image_path
,存储原始图片的路径,方便后续关联)。
from pymilvus import Collection, FieldSchema, CollectionSchema, DataType
# 1. 定义字段
fields = [
# 主键字段:整数类型,自增(可选,也可手动指定)
FieldSchema(name="image_id", dtype=DataType.INT64, is_primary=True, auto_id=True),
# 向量字段:浮点型向量,维度需与提取的向量一致(如 ResNet50 为 2048 维)
FieldSchema(name="vector", dtype=DataType.FLOAT_VECTOR, dim=2048),
# 元数据字段:存储图片路径(字符串类型)
FieldSchema(name="image_path", dtype=DataType.VARCHAR, max_length=255)
]
# 2. 定义集合 schema
schema = CollectionSchema(fields=fields, description="存储图片特征向量及元数据的集合")
# 3. 创建集合(若已存在可跳过)
collection_name = "image_features"
collection = Collection(name=collection_name, schema=schema)
# 4. 加载集合到内存(Milvus 操作前需加载集合)
collection.load()
3. 插入图片向量及元数据
将提取的向量与元数据(如图片路径)一起插入到集合中:
# 准备插入的数据(可批量插入,效率更高)
# 格式:[ [向量1, 向量2, ...], [图片路径1, 图片路径2, ...] ]
data = [
[vector], # 向量列表(此处为单张图片,批量可传入多个向量)
[image_path] # 对应的图片路径列表
]
# 插入数据
insert_result = collection.insert(data)
print("插入的主键 ID:", insert_result.primary_keys) # 输出自动生成的 image_id
# 插入后建议创建索引(加速后续检索,可选但推荐)
# 以 IVF_FLAT 索引为例(适用于中小规模数据)
index_params = {
"index_type": "IVF_FLAT",
"metric_type": "L2", # 距离度量方式(L2 为欧氏距离,IP 为内积)
"params": {"nlist": 128} # 聚类数量,根据数据量调整
}
collection.create_index(field_name="vector", index_params=index_params)
print("索引创建完成")
三、关键注意事项
- 向量维度匹配:提取的图片向量维度必须与集合中定义的
dim
一致,否则插入会失败。 - 原始图片存储:Milvus 仅存储向量和元数据,原始图片需单独存储(如本地文件夹、S3、OSS 等),通过
image_path
或其他元数据关联。 - 批量操作优先:批量插入/查询的效率远高于单条操作,实际应用中建议批量处理图片。
- 索引选择:根据数据量和检索需求选择合适的索引(如 IVF_FLAT、HNSW 等),并合理调整参数。
- 连接管理:生产环境中需处理连接超时、重连等问题,避免频繁创建/关闭连接。