构建索引
一、向量嵌入
向量嵌入(Embedding)是一种将真实世界中复杂、高维的数据对象(如文本、图像、音频、视频等)转换为数学上易于处理的、低维、稠密的连续数值向量的技术。
想象一下,我们将每一个词、每一段话、每一张图片都放在一个巨大的多维空间里,并给它一个独一无二的坐标。这个坐标就是一个向量,它“嵌入”了原始数据的所有关键信息。这个过程,就是 Embedding。
- 数据对象:任何信息,如文本“你好世界”,或一张猫的图片。
- Embedding 模型:一个深度学习模型,负责接收数据对象并进行转换。
- 输出向量:一个固定长度的一维数组,例如
[0.16, 0.29, -0.88, ...]
。这个向量的维度(长度)通常在几百到几千之间。
Embedding 的真正威力在于,它产生的向量不是随机数值的堆砌,而是对数据语义的数学编码。
-
核心原则:在 Embedding 构建的向量空间中,语义上相似的对象,其对应的向量在空间中的距离会更近;而语义上不相关的对象,它们的向量距离会更远。
-
关键度量
:我们通常使用以下数学方法来衡量向量间的“距离”或“相似度”:
- 余弦相似度 (Cosine Similarity):计算两个向量夹角的余弦值。值越接近 1,代表方向越一致,语义越相似。这是最常用的度量方式。
- 点积 (Dot Product):计算两个向量的乘积和。在向量归一化后,点积等价于余弦相似度。
- 欧氏距离 (Euclidean Distance):计算两个向量在空间中的直线距离。距离越小,语义越相似。
二、多模态嵌入实战——Milvus介绍及多模态检索实践
该笔记是针对文章all-in-rag的第三章节实战的详细说明。若想看理论细节,请移步作者的文章。
向量数据库是专门用于存储和查询向量的数据库,这些向量来自对文本、语音、图像、视频等内容的向量化处理;与传统数据库相比,它不仅能完成添加、读取查询、更新、删除等基本操作,还能对向量数据进行更快速的相似性搜索。当前的大模型,无论是 NLP 领域的 GPT 系列还是 CV 领域的 ResNET 系列,都是经过预先训练的,存在明确的训练截止日,这使得它们对截止日之后发生的事情一无所知,而向量数据库的引入则能极大拓展大模型的应用边界 —— 其内部存储的最新信息向量可让大模型保持准实时性、提高适用性并实现动态调整,进而使大模型具备长期记忆。比如,一个 2021 年底完成训练的新闻摘要预训练模型,到 2023 年面对诸多新的新闻事件和趋势时,可借助向量数据库存储和查询 2023 年的新闻文章向量来处理新信息;在推荐系统中,预训练大模型可能无法识别新用户和新产品的特征,而通过向量数据库实时更新用户和产品的特征向量,能让大模型依据最新信息提供更精准的推荐;此外,向量数据库还支持实时监测和分析,像金融领域中,预训练的股票预测模型可能无法获取训练截止日后的股票价格信息,将最新股票价格向量存储在向量数据库中,大模型就能实时分析和预测未来股票价格走势,在客服领域,向量数据库也能让大模型追溯到对话的开始。
向量数据库自带多模态功能,这意味着它能够通过机器学习方法处理和理解来自不同源的多种模态信息,如文本、图像、音频和视频等,数据向量化过程使得这些不同模态数据的内部隐藏信息得以暴露,进而为多模态应用提供支持。
2.1 Milvus简介
Milvus 是一款云原生向量数据库,具备高可用、高性能、易拓展的特点,用于海量向量数据的实时召回。其官网地址为:Milvus。Milvus 基于 FAISS、Annoy、HNSW 等向量搜索库构建,核心目标是解决稠密向量相似度检索问题;在向量检索库的基础上,它支持数据分区分片、数据持久化、增量数据摄取、标量向量混合查询、time travel 等功能,同时大幅优化了向量检索性能,可满足各类向量检索场景的应用需求,通常建议用户采用 Kubernetes 部署 Milvus,以获得最佳的可用性和弹性。此外,Milvus 采用共享存储架构,实现存储与计算完全分离,计算节点支持横向扩展;从架构来看,它遵循数据流与控制流分离的原则,整体分为接入层(access layer)、协调服务(coordinator service)、执行节点(worker node)和存储层(storage)四个层次,各个层次相互独立,可实现独立扩展和容灾。
2.2 Collection(集合)
在 Milvus 中,Collection 是数据组织的基本逻辑单元,其功能等价于关系型数据库中的表(Table)。它作为向量数据及相关元数据的存储、管理与检索容器,所有操作(插入、删除、查询)均以 Collection 为操作对象。
可以用一个图书馆的比喻来理解 Collection:
- Collection (集合): 相当于一个图书馆,是所有数据的顶层容器。一个 Collection 可以包含多个 Partition,每个 Partition 可以包含多个 Entity。
- Partition (分区): 相当于图书馆里的不同区域(如“小说区”、“科技区”),将数据物理隔离,让检索更高效。
- Schema (模式): 相当于图书馆的图书卡片规则,定义了每本书(数据)必须登记哪些信息(字段)。
- Entity (实体): 相当于一本具体的书,是数据本身。
- Alias (别名): 相当于一个动态的推荐书单(如“本周精选”),它可以指向某个具体的 Collection,方便应用层调用,实现数据更新时的无缝切换。
Collection 是 Milvus 中最基本的数据组织单位,类似于关系型数据库中的一张表 (Table)。是我们存储、管理和查询向量及相关元数据的容器。所有的数据操作,如插入、删除、查询等,都是围绕 Collection 展开的。
2.2.1 Schema(模式):数据结构规范
Collection 的创建需预定义其 Schema,该模式通过字段(Field)属性约束确保数据一致性与查询效率。Schema 包含三类核心字段:
- 主键字段(Primary Key Field)
- 必备字段,全局唯一标识实体(Entity)。
- 数据类型:
INT64
或VARCHAR
,值需满足唯一性约束。
- 向量字段(Vector Field)
- 存储嵌入向量(Embedding Vector),支持单 Collection 多向量字段(如多模态场景)。
- 标量字段(Scalar Field)
- 存储非向量元数据(字符串、数值、布尔值、JSON 等),用于查询过滤与结果聚合。
Schema 设计范式示例(新闻文章场景)
假设 Schema 包含:
- 主键:
article_id
(唯一标识)- 标量字段:
title
(VARCHAR),author
(VARCHAR),image_url
(VARCHAR)- 向量字段:
image_embedding
(密集向量,DENSE_FLOAT_VECTOR)summary_embedding
(密集向量)summary_sparse_embedding
(稀疏向量,SPARSE_FLOAT_VECTOR)
此设计支持多模态混合检索,并通过标量字段实现元数据过滤。
2.2.2 Partition(分区):数据物理隔离机制
Partition 是 Collection 内部的逻辑数据分片,通过物理隔离优化查询性能与管理效率:
- 初始状态:每个 Collection 含默认分区
_default
。 - 容量限制:单 Collection 最多支持 1024 个分区。
分区核心价值:
- 查询性能提升
限定搜索范围至特定分区(如WHERE partition_name="AI_articles"
),减少全量数据扫描。 - 数据生命周期管理
- 支持分区级批量操作:加载/卸载内存、数据删除。
- 示例:按时间分区(
2024Q1
,2024Q2
)可快速归档历史数据。
2.2.3 Alias
Alias (别名) 是为 Collection 提供的一个“昵称”。通过为一个 Collection 设置别名,我们可以在应用程序中使用这个别名来执行所有操作,而不是直接使用真实的 Collection 名称。
为什么使用别名?
- 安全地更新数据:想象一下,你需要对一个在线服务的 Collection 进行大规模的数据更新或重建索引。直接在原 Collection 上操作风险很高。正确的做法是:
- 创建一个新的 Collection (
collection_v2
) 并导入、索引好所有新数据。 - 将指向旧 Collection (
collection_v1
) 的别名(例如my_app_collection
)原子性地切换到新 Collection (collection_v2
) 上。
- 创建一个新的 Collection (
- 代码解耦:整个切换过程对上层应用完全透明,无需修改任何代码或重启服务,实现了数据的平滑无缝升级。
2.3 Index
如果说 Collection 是 Milvus 的骨架,那么索引 (Index) 就是其加速检索的神经系统。从宏观上看,索引本身就是一种为了加速查询而设计的复杂数据结构。对向量数据创建索引后,Milvus 可以极大地提升向量相似性搜索的速度,代价是会占用额外的存储和内存资源。
索引建立由数据节点执行。为了避免频繁为数据更新建立索引,Milvus 将 Collections 进一步划分为多个分段,每个分段都有自己的索引。
Milvus 支持为每个向量场、标量场和主场建立索引。索引构建的输入和输出都与对象存储有关:数据节点将要建立索引的日志快照从段落(在对象存储中)加载到内存,反序列化相应的数据和元数据以建立索引,索引建立完成后序列化索引,并将其写回对象存储。
索引构建主要涉及向量和矩阵操作,因此是计算和内存密集型操作。向量因其高维特性,无法用传统的树形索引高效地建立索引,但可以用这方面比较成熟的技术建立索引,如基于集群或图形的索引。无论其类型如何,建立索引都涉及大规模向量的大量迭代计算,如 Kmeans 或图遍历。
与标量数据的索引不同,建立向量索引必须充分利用 SIMD(单指令、多数据)加速。Milvus 天生支持 SIMD 指令集,例如 SSE、AVX2 和 AVX512。考虑到向量索引构建的 "打嗝 "和资源密集性质,弹性对 Milvus 的经济性而言变得至关重要。Milvus 未来的版本将进一步探索异构计算和无服务器计算,以降低相关成本。
此外,Milvus 还支持标量过滤和主字段查询。为了提高查询效率,Milvus 还内置了布鲁姆过滤索引、哈希索引、树型索引和反转索引等索引,并计划引入更多外部索引,如位图索引和粗糙索引。
具体细节可以查询Milvus帮助文档。
2.4 检索
有了数据容器(Collection)和检索引擎(Index)后,最后一步便是从海量数据中高效检索信息。
基础向量检索(ANN Search)是 Milvus 的核心功能之一,即近似最近邻(Approximate Nearest Neighbor, ANN)检索。与需计算全部数据的暴力检索(Brute-force Search)不同,ANN 检索借助预先构建的索引,能极速从海量数据中找到与查询向量最相似的 Top-K 个结果,是一种在速度和精度间实现极致平衡的策略。其主要参数包括:anns_field(指定检索的向量字段)、data(传入查询向量)、limit(或 top_k,指定返回最相似结果的数量)、search_params(指定检索参数,如距离计算方式 metric_type 和索引相关查询参数)。
在基础 ANN 检索之上,Milvus 还提供多种增强检索功能,以满足更复杂的业务需求。过滤检索(Filtered Search)将向量相似性检索与标量字段过滤结合,先根据过滤表达式(filter)筛选符合条件的实体,再在子集内执行 ANN 检索,大幅提升查询精准度,例如电商场景中 “检索与红色连衣裙相似且价格低于 500 元、有库存的商品”,或知识库中 “从‘技术’分类、2023 年后发布的文章里找与‘人工智能’相关的文档”。
范围检索(Range Search)聚焦于 “所有与查询向量相似度在特定范围内的结果”,通过定义距离(或相似度)阈值范围,返回所有距离落在该范围内的实体,应用于人脸识别中 “查找与目标人脸相似度超 0.9 的人脸” 进行身份验证,或异常检测中 “查找与正常样本向量距离过大的数据点” 以发现异常。
多向量混合检索是强大的高级模式,支持在一个请求中同时检索多个向量字段并智能融合结果:先针对不同向量字段(如文本语义密集向量、关键词匹配稀疏向量、图像内容多模态向量)并行发起 ANN 检索,再通过重排策略(如平衡各方结果的 RRFRanker、可为特定字段加权的 WeightedRanker)合并为统一高质量排序列表,例如多模态商品检索中,用户输入 “安静舒适的白色耳机”,系统同时检索商品文本描述和图片内容向量返回最匹配结果;增强型 RAG 中,结合密集向量(捕捉语义)和稀疏向量(精确匹配关键词)实现更精准的文档检索。
分组检索则解决了检索结果多样性不足的问题,允许指定字段(如 document_id)对结果分组,确保返回结果中每个组(每个 document_id)只出现一次(或指定次数),且为该组内与查询最相似的实体,例如视频检索 “可爱的猫咪” 时确保结果来自不同博主,文档检索 “数据库索引” 时确保结果来自不同书籍或来源。通过这些灵活的检索功能组合,开发者可构建满足各类复杂业务需求的向量检索应用。
2.5 部署安装
首先,我们需要下载一个docker。下载docker步骤如下:
1.安装wsl。首先,搜索“启用或关闭Windows功能”,可以直接在任务栏中搜索。勾选“虚拟机平台”与“适用于Linux的Windows子系统”。其中“虚拟机平台”可能并未被翻译,叫做“Virtual Machine Platform”
勾选完毕之后你的电脑会重启。重启之后你需要以管理员身份打开cmd。依次输入以下两串代码:
wsl --set-default-version 2
wsl --update --web-download
其中“–web-download”可以减少网络问题导致的wsl下载失败。
2.打开docker官方网址,选择amd64下载Docker Desktop Installer.exe文件。
你可以直接安装,如果你想要指定docker的安装目录,你可以将exe文件拖到cmd默认目录下,然后输入下面这段代码:
start /w "" "Docker Desktop Installer.exe" install --installation-dir=地址
3.下载Milvus配置文件
首先移动到你代码所在的目录下,注意这里要使用powershell
cd "code 地址"
接着,使用以下命令下载官方的 docker-compose.yml
文件。这个文件定义了 Milvus Standalone 及其运行所需的两个核心依赖服务:etcd
用于存储元数据,MinIO
用于对象存储(更多架构细节请参考官方文档)。
# Windows (使用 PowerShell)
Invoke-WebRequest -Uri "https://github.com/milvus-io/milvus/releases/download/v2.5.14/milvus-standalone-docker-compose.yml" -OutFile "docker-compose.yml"
下载完毕之后,你的文件夹中会有一个名为“docker-compose.yml”的文件。
在 docker-compose.yml
文件所在的目录中,运行以下命令以后台模式启动 Milvus:
docker compose up -d
Docker 将会自动拉取所需的镜像并启动三个容器:milvus-standalone
, milvus-minio
, 和 milvus-etcd
。这个过程可能需要几分钟,具体取决于你的网络状况。流程截图如下:
可以通过以下方式验证 Milvus 是否成功启动:
- 查看 Docker 容器: 打开 Docker Desktop 的仪表盘 (Windows/macOS) 或在终端运行
docker ps
命令 (Linux),确认三个 Milvus 相关容器(milvus-standalone
,milvus-minio
,milvus-etcd
)都处于running
或up
状态。 - 检查服务端口: Milvus Standalone 默认通过
19530
端口提供服务,这是后续代码连接时需要用到的地址。
并且你的文件夹会变成这样:
2.6 运行代码
完整代码如下:
import os
from tqdm import tqdm
from glob import glob
import torch
from visual_bge.visual_bge.modeling import Visualized_BGE
from pymilvus import MilvusClient, FieldSchema, CollectionSchema, DataType
import numpy as np
import cv2
from PIL import Image# 1. 初始化设置
MODEL_NAME = "BAAI/bge-base-en-v1.5" # 使用的预训练模型名称
MODEL_PATH = r"all-in-rag\models\bge\Visualized_base_en_v1.5.pth" # 模型权重路径
DATA_DIR = r"all-in-rag\data\C3" # 数据集目录
COLLECTION_NAME = "multimodal_demo" # Milvus集合名称
MILVUS_URI = "http://localhost:19530" # Milvus服务器地址# 2. 定义工具 (编码器和可视化函数)
class Encoder:"""编码器类,用于将图像和文本编码为向量。"""def __init__(self, model_name: str, model_path: str):# 初始化多模态模型self.model = Visualized_BGE(model_name_bge=model_name, model_weight=model_path)self.model.eval() # 设置为评估模式def encode_query(self, image_path: str, text: str) -> list[float]:# 使用图像和文本生成多模态嵌入with torch.no_grad(): # 禁用梯度计算query_emb = self.model.encode(image=image_path, text=text)return query_emb.tolist()[0] # 转换为Python列表def encode_image(self, image_path: str) -> list[float]:# 仅使用图像生成嵌入with torch.no_grad():query_emb = self.model.encode(image=image_path)return query_emb.tolist()[0]def visualize_results(query_image_path: str, retrieved_images: list, img_height: int = 300, img_width: int = 300, row_count: int = 3) -> np.ndarray:"""从检索到的图像列表创建一个全景图用于可视化。"""# 创建空白画布panoramic_width = img_width * row_countpanoramic_height = img_height * row_countpanoramic_image = np.full((panoramic_height, panoramic_width, 3), 255, dtype=np.uint8) # 白色背景query_display_area = np.full((panoramic_height, img_width, 3), 255, dtype=np.uint8) # 查询图像区域# 处理查询图像query_pil = Image.open(query_image_path).convert("RGB")query_cv = np.array(query_pil)[:, :, ::-1] # PIL转OpenCV格式(RGB->BGR)resized_query = cv2.resize(query_cv, (img_width, img_height))bordered_query = cv2.copyMakeBorder(resized_query, 10, 10, 10, 10, cv2.BORDER_CONSTANT, value=(255, 0, 0)) # 添加蓝色边框# 将查询图像放置在右侧区域底部query_display_area[img_height * (row_count - 1):, :] = cv2.resize(bordered_query, (img_width, img_height))# 添加"Query"标签cv2.putText(query_display_area, "Query", (10, panoramic_height - 20), cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 0, 0), 2)# 处理检索到的图像for i, img_path in enumerate(retrieved_images):row, col = i // row_count, i % row_count # 计算网格位置start_row, start_col = row * img_height, col * img_width # 计算起始坐标retrieved_pil = Image.open(img_path).convert("RGB")retrieved_cv = np.array(retrieved_pil)[:, :, ::-1] # 转换格式resized_retrieved = cv2.resize(retrieved_cv, (img_width - 4, img_height - 4)) # 调整大小bordered_retrieved = cv2.copyMakeBorder(resized_retrieved, 2, 2, 2, 2, cv2.BORDER_CONSTANT, value=(0, 0, 0)) # 添加黑色边框panoramic_image[start_row:start_row + img_height, start_col:start_col + img_width] = bordered_retrieved # 放置到画布# 添加索引号cv2.putText(panoramic_image, str(i), (start_col + 10, start_row + 30), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 255), 2)# 拼接查询区域和结果区域return np.hstack([query_display_area, panoramic_image])# 3. 初始化客户端
print("--> 正在初始化编码器和Milvus客户端...")
encoder = Encoder(MODEL_NAME, MODEL_PATH) # 创建编码器实例
milvus_client = MilvusClient(uri=MILVUS_URI) # 连接Milvus服务器# 4. 创建 Milvus Collection
print(f"\n--> 正在创建 Collection '{COLLECTION_NAME}'")
# 检查并删除已存在的集合
if milvus_client.has_collection(COLLECTION_NAME):milvus_client.drop_collection(COLLECTION_NAME)print(f"已删除已存在的 Collection: '{COLLECTION_NAME}'")# 获取数据集中的图像文件
image_list = glob(os.path.join(DATA_DIR, "dragon", "*.png"))
if not image_list:raise FileNotFoundError(f"在 {DATA_DIR}/dragon/ 中未找到任何 .png 图像。")# 获取嵌入维度(使用第一张图像)
dim = len(encoder.encode_image(image_list[0]))# 定义集合字段
fields = [FieldSchema(name="id", dtype=DataType.INT64, is_primary=True, auto_id=True), # 主键IDFieldSchema(name="vector", dtype=DataType.FLOAT_VECTOR, dim=dim), # 向量字段FieldSchema(name="image_path", dtype=DataType.VARCHAR, max_length=512), # 图像路径
]# 创建集合
schema = CollectionSchema(fields, description="多模态图文检索")
milvus_client.create_collection(collection_name=COLLECTION_NAME, schema=schema)
print(f"成功创建 Collection: '{COLLECTION_NAME}'")
print("Collection 结构:")
print(milvus_client.describe_collection(collection_name=COLLECTION_NAME))# 5. 准备并插入数据
print(f"\n--> 正在向 '{COLLECTION_NAME}' 插入数据")
data_to_insert = []
# 遍历所有图像并生成嵌入向量
for image_path in tqdm(image_list, desc="生成图像嵌入"):vector = encoder.encode_image(image_path) # 编码图像data_to_insert.append({"vector": vector, "image_path": image_path}) # 准备数据# 批量插入数据
if data_to_insert:result = milvus_client.insert(collection_name=COLLECTION_NAME, data=data_to_insert)print(f"成功插入 {result['insert_count']} 条数据。")# 6. 创建索引
print(f"\n--> 正在为 '{COLLECTION_NAME}' 创建索引")
# 配置HNSW索引参数
index_params = milvus_client.prepare_index_params()
index_params.add_index(field_name="vector",index_type="HNSW", # 分层可导航小世界图算法metric_type="COSINE", # 余弦相似度params={"M": 16, "efConstruction": 256} # HNSW参数
)
# 创建索引
milvus_client.create_index(collection_name=COLLECTION_NAME, index_params=index_params)
# 加载集合到内存
milvus_client.load_collection(collection_name=COLLECTION_NAME)
print("已加载 Collection 到内存中。")# 7. 执行多模态检索
print(f"\n--> 正在 '{COLLECTION_NAME}' 中执行检索")
# 定义查询图像和文本
query_image_path = os.path.join(DATA_DIR, "dragon", "query.png")
query_text = "一条龙"
# 生成多模态查询向量
query_vector = encoder.encode_query(image_path=query_image_path, text=query_text)# 执行相似度搜索
search_results = milvus_client.search(collection_name=COLLECTION_NAME,data=[query_vector], # 查询向量output_fields=["image_path"], # 返回的字段limit=5, # 返回前5个结果search_params={"metric_type": "COSINE", "params": {"ef": 128}} # 搜索参数
)[0] # 获取第一个查询结果# 处理检索结果
retrieved_images = []
print("检索结果:")
for i, hit in enumerate(search_results):print(f" Top {i+1}: ID={hit['id']}, 距离={hit['distance']:.4f}, 路径='{hit['entity']['image_path']}'")retrieved_images.append(hit['entity']['image_path']) # 收集图像路径# 8. 可视化与清理
print(f"\n--> 正在可视化结果并清理资源")
if not retrieved_images:print("没有检索到任何图像。")
else:panoramic_image = visualize_results(query_image_path, retrieved_images)combined_image_path = os.path.join(DATA_DIR, "search_result.png")cv2.imwrite(combined_image_path, panoramic_image)print(f"结果图像已保存到: {combined_image_path}")Image.open(combined_image_path).show()milvus_client.release_collection(collection_name=COLLECTION_NAME)
print(f"已从内存中释放 Collection: '{COLLECTION_NAME}'")
milvus_client.drop_collection(COLLECTION_NAME)
print(f"已删除 Collection: '{COLLECTION_NAME}'")
运行结果如下所示:
E:\anaconda\envs\all-in-rag\Lib\site-packages\timm\models\layers\__init__.py:48:
--> 正在初始化编码器和Milvus客户端...--> 正在创建 Collection 'multimodal_demo'
Schema 结构:
{'auto_id': True, 'description': '多模态图文检索', 'fields': [{'name': 'id', 'description': '', 'type': <DataType.INT64: 5>, 'is_primary': True, 'auto_id': True}, {'name': 'vector', 'description': '', 'type': <DataType.FLOAT_VECTOR: 101>, 'params': {'dim': 768}}, {'name': 'image_path', 'description': '', 'type': <DataType.VARCHAR: 21>, 'params': {'max_length': 512}}], 'enable_dynamic_field': False}
成功创建 Collection: 'multimodal_demo'
Collection 结构:
{'collection_name': 'multimodal_demo', 'auto_id': True, 'num_shards': 1, 'description': '多模态图文检索', 'fields': [{'field_id': 100, 'name': 'id', 'description': '', 'type': <DataType.INT64: 5>, 'params': {}, 'auto_id': True, 'is_primary': True}, {'field_id': 101, 'name': 'vector', 'description': '', 'type': <DataType.FLOAT_VECTOR: 101>, 'params': {'dim': 768}}, {'field_id': 102, 'name': 'image_path', 'description': '', 'type': <DataType.VARCHAR: 21>, 'params': {'max_length': 512}}], 'functions': [], 'aliases': [], 'collection_id': 460171652961143814, 'consistency_level': 2, 'properties': {}, 'num_partitions': 1, 'enable_dynamic_field': False, 'created_timestamp': 460171813451988996, 'update_timestamp': 460171813451988996} --> 正在向 'multimodal_demo' 插入数据
生成图像嵌入: 100%|█████████████████████████████████████████████████████████████████████████████████████████████████| 7/7 [00:01<00:00, 4.45it/s]
成功插入 7 条数据。--> 正在为 'multimodal_demo' 创建索引
成功为向量字段创建 HNSW 索引。
索引详情:
{'M': '16', 'efConstruction': '256', 'metric_type': 'COSINE', 'index_type': 'HNSW', 'field_name': 'vector', 'index_name': 'vector', 'total_rows': 0, 'indexed_rows': 0, 'pending_index_rows': 0, 'state': 'Finished'}
已加载 Collection 到内存中。--> 正在 'multimodal_demo' 中执行检索
检索结果:Top 1: ID=460171652961143835, 距离=0.9466, 路径='all-in-rag\data\C3\dragon\query.png'Top 2: ID=460171652961143829, 距离=0.7443, 路径='all-in-rag\data\C3\dragon\dragon02.png'Top 3: ID=460171652961143833, 距离=0.6851, 路径='all-in-rag\data\C3\dragon\dragon06.png'Top 4: ID=460171652961143830, 距离=0.6049, 路径='all-in-rag\data\C3\dragon\dragon03.png'Top 5: ID=460171652961143832, 距离=0.5360, 路径='all-in-rag\data\C3\dragon\dragon05.png'--> 正在可视化结果并清理资源
结果图像已保存到: all-in-rag\data\C3\search_result.png
已从内存中释放 Collection: 'multimodal_demo'
已删除 Collection: 'multimodal_demo'
整体流程总结:
- 初始化设置:配置模型、路径和Milvus连接参数
- 定义工具:
Encoder
类:处理图像/文本到向量的转换visualize_results
函数:创建查询结果的可视化视图
- Milvus集合管理:
- 创建包含向量和图像路径的集合
- 删除已存在的同名集合
- 数据处理:
- 加载并编码所有图像
- 将向量和元数据插入Milvus
- 索引创建:为向量字段创建HNSW索引
- 多模态检索:
- 结合图像和文本生成查询向量
- 在Milvus中执行相似度搜索
- 结果展示:
- 打印检索结果
- 可视化查询图像和结果图像
- 资源清理:释放并删除Milvus集合
参考文章
[1] https://blog.csdn.net/lsb2002/article/details/132222947
[2] https://datawhalechina.github.io/all-in-rag/#/chapter3/09_milvus