Milvus快速入门及用Java操作Milvus的全过程

 更新时间:2025年09月30日 09:30:58   作者:勇往直前plus  
Milvus是面向向量的数据库,通过相似性搜索处理非结构化数据特征,本文给大家介绍Milvus快速入门以及用Java操作Milvus的方法,感兴趣的朋友一起看看吧

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

下面这个流程图是Milvus 的核心工作流程图,很清晰地展示了 Milvus 如何通过向量查找内容的工作过程

用 Java 操作 Milvus

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

引入依赖

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

springBoot中注入Milvus客户端bean

@Configuration
public class MilvusConfig {
    @Value("${milvus_uri}")
    private String milvus_uri;
    @Bean
    public MilvusClientV2  milvusServiceClient() {
        ConnectConfig connectConfig = ConnectConfig.builder()
                .uri(milvus_uri)
                .build();
        return new MilvusClientV2(connectConfig);
    }
}

创建集合

  • 一般三个字段,主键字段,embedding字段,元数据(原始数据)字段
import io.milvus.v2.client.MilvusClientV2;
import io.milvus.v2.client.ConnectConfig;
import io.milvus.v2.service.collection.request.CreateCollectionReq;
import io.milvus.v2.service.collection.request.AddFieldReq;
import io.milvus.v2.common.DataType;
public class MilvusCollectionCreator {
    public static void main(String[] args) {
        // 1. 配置并创建 Milvus 客户端
        ConnectConfig connectConfig = ConnectConfig.builder()
                .uri("http://localhost:19530") // Milvus 服务器地址
                .token("username:password")     // 若启用认证,请提供;否则可省略
                .build();
        MilvusClientV2 client = new MilvusClientV2(connectConfig);
        // 2. 定义集合名称
        String collectionName = "my_first_collection"; // 替换为你想要的集合名
        // 3. 构建集合 Schema (字段定义)
        CreateCollectionReq.CollectionSchema schema = client.createSchema(); // 创建空Schema
        // 3.1 添加主键字段 (通常是INT64或VarChar)
        schema.addField(AddFieldReq.builder()
                .fieldName("id")
                .dataType(DataType.Int64)
                .isPrimaryKey(true) // 设为主键
                .autoID(false)       // 设置为false表示插入数据时需自行提供ID
                .build());
        // 3.2 添加标量字段 (例如存储文本名称)
        schema.addField(AddFieldReq.builder()
                .fieldName("name")
                .dataType(DataType.VarChar)
                .maxLength(255)      // VarChar类型必须指定最大长度
                .build());
        // 3.3 添加向量字段 (核心部分)
        int vectorDimension = 768; // 必须与你后续要插入的向量维度一致!
        schema.addField(AddFieldReq.builder()
                .fieldName("vector_embedding") // 字段名
                .dataType(DataType.FloatVector) // 数据类型为浮点向量
                .dimension(vectorDimension)     // 必须指定向量维度
                .build());
        // 4. 构建创建集合的请求
        CreateCollectionReq createCollectionReq = CreateCollectionReq.builder()
                .collectionName(collectionName)
                .collectionSchema(schema) // 设置定义好的Schema
                // .shardsNum(1)        // (可选) 设置分片数,默认为1
                // .enableDynamicField(true) // (可选) 是否启用动态字段以存储未定义的字段
                .build();
        // 5. 执行创建操作
         client.createCollection(createCollectionReq);
         System.out.println("集合 '" + collectionName + "' 创建成功!");
    }
}

插入数据

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

    /**
     * 插入单条数据到Milvus集合
     * @param id 记录的唯一ID
     * @param text 原始文本或其他标量数据
     * @param vector 文本对应的向量(Float列表)
     * @return 插入结果信息
     */
    public String insertSingleData(Long id, String text, List<Float> vector) {
        try {
            // 1. 构建一个 JsonObject 代表一条记录
            JsonObject entity = new JsonObject();
            entity.addProperty("id", id); // 主键字段 (需与集合Schema定义匹配)
            entity.addProperty("content", text); // 标量字段 (例如存储原始文本)
            // 将向量列表转换为JsonArray并添加到实体中
            entity.add("vector", gson.toJsonTree(vector)); // 向量字段 (字段名需与Schema匹配)
            // 2. 将单条数据放入列表
            List<JsonObject> dataList = Collections.singletonList(entity);
            // 3. 构建插入请求
            InsertReq insertReq = InsertReq.builder()
                    .collectionName(COLLECTION_NAME)
                    .data(dataList)
                    .build();
            // 4. 执行插入
            InsertResp insertResp = milvusClientV2.insert(insertReq);
            return "成功插入 " + insertResp.getInsertCnt() + " 条数据。";
        } catch (Exception e) {
            throw new RuntimeException("插入数据失败: " + e.getMessage(), e);
        }
    }

创建索引

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!");

检索并获取原始数据

    public Map<String, String> query(List<Float> embedding) {
        // key:原始文本,value:drug_code
        Map<String, String> res = new HashMap<>();
        //设置查询参数
        Map<String, Object> searchParamsMap = new HashMap<>();
        searchParamsMap.put("nprobe", 10); // 设置搜索的桶数量,影响精度和性能
        // 设置返回的field
        List<String> returnFields = Arrays.asList("original_text", "drug_code");
        FloatVec floatVec = new FloatVec(embedding);
        SearchReq searchReq = SearchReq.builder()
                .collectionName(DRUG_WES_COLLECTION_NAME)
                .data(Collections.singletonList(floatVec))
                .topK(TOK_K)
                .outputFields(returnFields)
                .searchParams(searchParamsMap)
                .build();
        SearchResp searchResp = milvusServiceClient.search(searchReq);
        //获取查询向量检索出的数据
        List<SearchResp.SearchResult> searchResult = searchResp.getSearchResults().get(0);
        for (SearchResp.SearchResult sr : searchResult) {
            Map<String, Object> entity = sr.getEntity();
            String originalText = (String) entity.get("original_text");
            String drugCode = (String) entity.get("drug_code");
            res.put(originalText,drugCode);
        }
        return res;
    }

工程建议

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

到此这篇关于Milvus快速入门及用Java操作Milvus的全过程的文章就介绍到这了,更多相关java milvus操作内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 详解Spring如何避免被JVM 垃圾回收

    详解Spring如何避免被JVM 垃圾回收

    如果Spring 被回收掉,Spring管理的bean全部会被回收,那我们的Java应用不就被一锅端了吗?所以本文小编将和大家一起聊聊Spring如何避免被JVM垃圾回收,需要的朋友可以参考下
    2023-11-11
  • springMVC在restful风格的性能优化方案

    springMVC在restful风格的性能优化方案

    这篇文章主要介绍了springMVC在restful风格的性能优化方案,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-08-08
  • Java基于分治算法实现的棋盘覆盖问题示例

    Java基于分治算法实现的棋盘覆盖问题示例

    这篇文章主要介绍了Java基于分治算法实现的棋盘覆盖问题,简单描述了棋盘覆盖问题,并结合具体实例形式分析了java基于分治算法实现棋盘覆盖问题的相关操作技巧,需要的朋友可以参考下
    2017-11-11
  • Java之打印String对象的地址

    Java之打印String对象的地址

    这篇文章主要介绍了Java之打印String对象的地址,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-09-09
  • 使用Criteria进行分组求和、排序、模糊查询的实例

    使用Criteria进行分组求和、排序、模糊查询的实例

    这篇文章主要介绍了使用Criteria进行分组求和、排序、模糊查询的实例,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-03-03
  • Java编程通过list接口实现数据的增删改查代码示例

    Java编程通过list接口实现数据的增删改查代码示例

    这篇文章是介绍Java编程基础方面的内容,涉及list接口的操作,通过list接口实现对数据的增删改查的相关代码,具有一定参考价值,需要的朋友可以了解下。
    2017-10-10
  • SpringBoot特点之依赖管理和自动装配(实例代码)

    SpringBoot特点之依赖管理和自动装配(实例代码)

    在使用SpringBoot的时候,会自动将Bean装配到IoC容器中,操作也很简单,今天小编给大家介绍下SpringBoot特点之依赖管理和自动装配的知识,感兴趣的朋友一起看看吧
    2022-03-03
  • SpringBoot+Tess4j实现牛的OCR识别工具的示例代码

    SpringBoot+Tess4j实现牛的OCR识别工具的示例代码

    这篇文章主要介绍了SpringBoot+Tess4j实现牛的OCR识别工具的示例代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-01-01
  • java生成申请单序列号的实现方法

    java生成申请单序列号的实现方法

    申请单序列号一般要求根据一定的规则生成后几位连续的字符串,下面是我项目中使用的生成序列号的代码,其中用到了锁机制,有需要的朋友可以参考一下
    2014-01-01
  • 关于maven打包出错的解决方案

    关于maven打包出错的解决方案

    这篇文章主要介绍了关于maven打包出错的解决方案,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-04-04

最新评论