java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > java milvus操作

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

作者:勇往直前plus

Milvus是面向向量的数据库,通过相似性搜索处理非结构化数据特征,本文给大家介绍Milvus快速入门以及用Java操作Milvus的方法,感兴趣的朋友一起看看吧

Milvus 核心概念

向量数据库

核心概念

​​索引类型说明
FLAT暴力搜索,精度100%但速度慢,适合小数据集或验证结果
​​IVF_FLAT​​先通过聚类将数据分桶(nlist 参数决定桶数),搜索时只查询最近的几个桶(nprobe 参数控制),大大提升速度
​​HNSW​​基于图论的索引,适合高精度、低延迟的搜索场景,但内存消耗较高
​​度量类型说明
​​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);
    }
}

创建集合

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操作内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文