当前位置: 首页 > backend >正文

Milvus快速入门以及用 Java 操作 Milvus

目录

  • Milvus 核心概念
    • 向量数据库
    • 核心概念
  • Milvus 的基本工作流程
  • 用 Java 操作 Milvus
    • 引入依赖
    • springBoot中注入Milvus客户端bean
    • 创建集合
    • 插入数据
    • 创建索引
    • 检索并获取原始数据
  • 工程建议

Milvus 核心概念

向量数据库

  • 可以把 Milvus 理解成一个专门处理“向量”这种特殊数据的数据库。传统数据库(如 MySQL)擅长处理数字、文字这类结构化数据,并按精确条件查询(比如 WHERE age > 18)。而向量数据库的核心是​​相似性搜索​​,它通过计算向量之间的“距离”或“相似度”,来找到最相近的结果。
  • “向量”在这里,通常是由各种 AI 模型(如 BERT、ResNet)从文本、图片、音频等非结构化数据中提取出的特征表示。这些向量本身是一串数字,在高维空间中代表原始数据的意义。

核心概念

  • 集合 (Collection) ​​:这是 Milvus 中最顶层的概念,类似于关系型数据库中的“表”。一个 Collection 用来存储具有相同结构的实体。
  • 字段 (Field)​​:定义了 Collection 的结构,类似于表中的“列”。Milvus 支持多种数据类型,但对于向量搜索,最重要的就是 ​​FloatVector​​ 类型的字段。
  • 向量维度 (Dimension)​​:这是向量的一个关键属性。它定义了向量中数字的个数。例如,一个由 BERT-base 模型生成的句子向量可能是 768 维,这就意味着它是一个包含 768 个浮点数的数组。在定义向量字段时,必须指定其维度。
  • 索引 (Index) ​​:为了在亿级数据中快速搜索,Milvus 不会进行暴力比对,而是为向量数据构建索引。不同的索引类型在​​构建速度、内存占用、查询速度和精度​​之间有不同的权衡,常见的索引类型有:
​​索引类型说明
FLAT暴力搜索,精度100%但速度慢,适合小数据集或验证结果
​​IVF_FLAT​​先通过聚类将数据分桶(nlist 参数决定桶数),搜索时只查询最近的几个桶(nprobe 参数控制),大大提升速度
​​HNSW​​基于图论的索引,适合高精度、低延迟的搜索场景,但内存消耗较高
  • ​​度量类型(Metric Type)​​:定义了计算向量之间距离或相似度的方式。常见的有:
​​度量类型说明
​​L2​​ (欧氏距离)距离越小,向量越相似。
​​IP​​ (内积)内积越大,向量越相似。
​​​​COSINE​​ (余弦相似度)忽略向量大小,只比较方向,相似度值越接近 1 越相似。这在自然语言处理中非常常用

Milvus 的基本工作流程

在这里插入图片描述

上面这个图是Milvus的核心系统架构图,和mysql、pg等数据库的系统架构很像,其核心工作流程可以概括为以下几个步骤:

  1. 连接 Milvus​​:你的应用程序通过 Milvus 提供的 SDK(如 Python 或 Java SDK)连接到 Milvus 服务。
  2. 创建集合​​:定义一个 Collection,并指定它的字段结构(例如,一个主键字段 id ,一个向量字段 embedding和对应的原始数据字段,一般一个Collection最少要包含这三个字段)。
  3. 插入数据​​:将你的数据(向量和相关的元数据,包括原始数据)插入到 Collection 中。
  4. 创建索引​​:在向量字段上构建索引(例如 IVF_FLAT)。​​这一步至关重要,只有在构建索引后,才能进行高效的向量搜索。
  5. 加载集合​​:将 Collection 从存储层加载到内存中,以便执行查询。
  6. 向量搜索​​:提供一个查询向量,让 Milvus 在 Collection 中搜索最相似的向量,并返回结果,值得注意的是,一般情况下返回的是最相似向量对应的原始数据或者自定义的元数据,而不是返回embedding
  7. 下面这个流程图是Milvus 的核心工作流程图,很清晰地展示了 Milvus 如何通过向量查找内容的工作过程
    在这里插入图片描述

用 Java 操作 Milvus

可以总结为,在boot项目中将Milvus客户端bean注入IOC容器,以便后续通过客户端对象操作Milvus服务器,包括创建集合、插入数据、创建索引、搜索向量等。主要是核心代码片段,有boot项目经验的很容易掌握。

引入依赖

<dependency><groupId>io.milvus</groupId><artifactId>milvus-sdk-java</artifactId><version>2.4.4</version> <!-- 请查看GitHub更新最新版本 -->
</dependency>

springBoot中注入Milvus客户端bean

@Configuration
public class MilvusConfig {@Value("${milvus.host}")private String host;@Value("${milvus.port}")private Integer port;@Beanpublic MilvusServiceClient milvusServiceClient() {ConnectParam connectParam = ConnectParam.newBuilder().withHost(host).withPort(port).build();return new MilvusServiceClient(connectParam);}
}

创建集合

  • 一般三个字段,主键字段,embedding字段,元数据(原始数据)字段
import io.milvus.param.collection.FieldType;
import io.milvus.param.collection.CreateCollectionParam;
import io.milvus.param.collection.FieldType;
import static io.milvus.param.Constant.*;// 定义主键id字段
FieldType idField = FieldType.newBuilder().withName("id").withDataType(DataType.Int64).withPrimaryKey(true).withAutoID(false) // 是否由Milvus自动生成ID.build();
// 定义embedding字段
FieldType vectorField = FieldType.newBuilder().withName("embedding").withDataType(DataType.FloatVector).withDimension(768) // 重要:指定向量维度,必须与你生成的向量一致.build();
// 定义字段:原始文本字段(用于绑定)
FieldType textField = FieldType.newBuilder().withName("original_text").withDataType(DataType.VarChar).withMaxLength(65535) // 设置足够长度存储文本.build();// 构建创建集合的请求
CreateCollectionParam createCollectionParam = CreateCollectionParam.newBuilder().withCollectionName("my_book_collection") // 集合名称.withDescription("Test collection for book vectors").addFieldType(idField).addFieldType(vectorField).addFieldType(textField) // 将原始文本字段加入Schema.build();// 执行创建
milvusClient.createCollection(createCollectionParam);
System.out.println("Collection created successfully!");

插入数据

插入数据包含主键字段、向量数组、和对应的原始文本数组​​,并确保它们的顺序一致,这样每条向量就与它对应的文本通过相同的数组索引关联起来了

import io.milvus.param.collection.InsertParam;
import java.util.Arrays;
import java.util.List;// 准备数据。假设我们有3本书的向量和ID
List<Long> ids = Arrays.asList(1L, 2L);
List<List<Float>> vectors = Arrays.asList(Arrays.asList(0.12f, 0.23f, 0.45f, ...), // 768维的向量Arrays.asList(0.56f, 0.67f, 0.78f, ...),
);
// 对应的原始文本列表,顺序必须与vectors一致!
List<String> originalTexts = Arrays.asList("这是第一段文本的原始内容", // 对应vectors中的第一个向量"这是第二段文本的原始内容"  // 对应vectors中的第二个向量
);// 构建插入请求
InsertParam insertParam = InsertParam.newBuilder().withCollectionName("my_book_collection").addField("id", ids).addField("embedding", vectors).addField("original_text", originalTexts) // 插入原始文本.build();// 执行插入
milvusClient.insert(insertParam);
System.out.println("Data inserted successfully!");

创建索引

import io.milvus.param.index.CreateIndexParam;
import io.milvus.param.index.IndexType;
import io.milvus.param.index.MetricType;CreateIndexParam createIndexParam = CreateIndexParam.newBuilder().withCollectionName("my_book_collection").withFieldName("embedding") // 在哪个向量字段上建索引.withIndexType(IndexType.IVF_FLAT) // 选择索引类型.withMetricType(MetricType.COSINE) // 选择度量类型.withExtraParam("{\"nlist\":1024}") // 索引参数,nlist是聚类中心数.build();milvusClient.createIndex(createIndexParam);
System.out.println("Index created successfully!");

检索并获取原始数据

import io.milvus.param.dml.SearchParam;
import io.milvus.response.SearchResultsWrapper;
import java.util.Collections;// 1. 将查询语句转换为向量(省略模型推理步骤)
List<Float> queryVector = Arrays.asList(0.34f, 0.25f, 0.67f, ...);// 2. 构建搜索参数,特别指定要返回的字段
SearchParam searchParam = SearchParam.newBuilder().withCollectionName("your_collection_name")// 指定要搜索的集合.withVectorFieldName("embedding")// 指定要搜索的向量字段名// 传入查询向量,将查询向量包装成一个列表传入。Milvus 支持一次性传入多个查询向量进行批量搜索,这里只用了一个.withVectors(Collections.singletonList(queryVector)).withTopK(5) // 返回最相似的5个结果.withMetricType(MetricType.COSINE)// 设置相似度度量类型(如COSINE, L2).addOutField("original_text") // 指定要返回的元数据字段:原始文本.addOutField("id") // 指定要返回的元数据字段:主键ID.build();// 3. 执行搜索
SearchResultsWrapper results = milvusClient.search(searchParam).getData();// 4. 处理结果:提取ID和原始文本
//results.getRowCount(0): 获取第一个(索引为 0)查询向量的返回结果数量(应该等于或小于 topK)
for (int i = 0; i < results.getRowCount(0); i++) {// 获取原始文本String originalText = results.getFieldData(0, i, "original_text", String.class);// 获取对应的向量IDLong id = results.getFieldData(0, i, "id", Long.class);System.out.println("ID: " + id + ", Original Text: " + originalText);
}

工程建议

  1. 索引选择​​:如果你的数据量巨大(十亿级)且对查询速度要求极高,可以考虑 HNSW 索引。如果对内存敏感,可以考虑量化索引如 IVF_PQ
  2. 参数调优​​:nprobe(对于 IVF 系列索引)和 ef(对于 HNSW 索引)等参数对搜索性能和精度有直接影响。通常需要在你的数据集上进行实验,找到平衡点
  3. 硬件加速​​:Milvus 支持 GPU 加速索引构建和查询,如果你的环境有 GPU,可以显著提升性能
  4. 官方文档 https://milvus.io/docs
http://www.xdnf.cn/news/19975.html

相关文章:

  • PAT 1093 Count PAT‘s
  • [技术革命]Harmonizer:仅20MB模型如何实现8K图像_视频的完美和谐化?
  • 三高项目-缓存设计
  • k8s证书理论知识之/etc/kubernetes/pki/ 和/var/lib/kubelet/pki/的区别
  • 将 PDF 转换为 TIFF 图片:简单有效的 Java 教程
  • 23种设计模式——抽象工厂模式(Abstract Factory Pattern)详解
  • 实战复盘:pnpm Monorepo 中的 Nuxt 依赖地狱——Unhead 升级引发的连锁血案
  • Node.js 18+安装及Claude国内镜像使用、idea中claude插件下载指南
  • MMD动画(二)动作制作
  • Spring线程池ThreadPoolTaskExecutor‌详解
  • 大语言模型的“思考”逻辑:从Token生成到上下文理解的内部流程
  • 我的创作纪念日——《惊变365天》
  • 裸签、Attach、Detach及其验签方式
  • Docker学习笔记(二):镜像与容器管理
  • 基于STM32的智能家居环境监控系统设计
  • 如何看懂GPU架构?万云智算一分钟带你了解GPU参数指标
  • Matter安全实现
  • Deathnote: 1靶场渗透
  • RTC实时时钟RX8025SA国产替代FRTC8025S
  • 2025打磨机器人品牌及自动化打磨抛光设备技术新版分析
  • 为何三折叠手机只有华为可以?看华为Mate XTs非凡大师就知道
  • 【CouponHub项目开发】EasyExcel解析Excel并使用线程池异步执行和延时队列兜底
  • Java GcExcel V8.2 新版本:效率升级与功能突破
  • 5.7 点云公开数据集——3D形状分类/部件分割
  • 企业发完年终奖后,是员工跳槽的高峰期?
  • 《嵌入式硬件(二):中断》
  • 数据可视化大屏精选开源项目
  • 【SuperSocket 】SuperSocket 中自定义 Session
  • [光学原理与应用-402]:设计 - 深紫外皮秒脉冲激光器 - 元件 - AOM零级光与一级光:深紫外皮秒激光器中的核心光学特性与系统应用
  • 决策树算法详解:从原理到实战