java实战-Milvus 2.5.x版本向量库-通过集合字段变更示例学习相关api demo

文章目录

  • 前言
    • java实战-Milvus 2.5.x版本向量库-通过集合字段变更示例学习相关api demo
      • 1. Milvus版本
      • 2. 示例逻辑分析
      • 3. 集合字段变更示例demo
      • 4. 测试

前言

  如果您觉得有用的话,记得给博主点个赞,评论,收藏一键三连啊,写作不易啊^ _ ^。
  而且听说点赞的人每天的运气都不会太差,实在白嫖的话,那欢迎常来啊!!!


java实战-Milvus 2.5.x版本向量库-通过集合字段变更示例学习相关api demo

注意:
关于demo中的Milvus 连接池与key的管理参考下面这篇文章。
java-Milvus 向量库(2.5.x版本)-连接池(多key)与自定义端点监听设计

1. Milvus版本

在这里插入图片描述

2. 示例逻辑分析

Milvus 不支持直接修改集合 schema(比如新增字段),所以你只能:

  1. 创建一个新集合(含你想新增的字段);
  2. 把旧集合的数据迁移过去;
  3. 继续在新集合中做后续操作。

注意的是数据迁移建议用 queryIteratorV2,而不是 searchIteratorV2.

功能queryIteratorV2searchIteratorV2
用途查询结构化数据(按条件筛选、返回字段)向量搜索,查找相似向量
是否依赖向量字段❌ 不依赖✅ 必须提供向量(FloatVector)
用途场景数据导出、分页查看、迁移、统计等向量相似度匹配(推荐、检索)
是否支持 filter✅ 支持 expr / filter✅ 支持 filter,但只能配合向量使用
返回内容任意字段(非向量也可以)topK 相似度结果(带 score)

3. 集合字段变更示例demo

package org.example.controller;import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.example.annotation.CommonLog;
import org.example.exception.model.ResponseResult;
import org.example.service.MilvusService;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;import javax.annotation.Resource;/**
* @author 杨镇宇
* @date 2025/7/8 08:46
* @version 1.0
*/
@Api(value = " milvus 练习", tags = {" milvus 练习"})
@Slf4j
@RestController
@RequestMapping(value="api/milvus")
public class MilvusController {@Resourceprivate MilvusService milvusService;@ApiOperation(value = "集合字段变更(数据迁移)测试", notes = "集合字段变更(数据迁移)测试")@CrossOrigin(origins = "*")@CommonLog(methodName = "集合字段变更(数据迁移)测试",className = "MilvusController#updateMigrateData",url = "api/milvus/updateMigrateData")@RequestMapping(value = "/updateMigrateData", method = RequestMethod.POST)public ResponseResult updateMigrateData(){milvusService.updateMigrateData();return ResponseResult.ok("测试完成");}}
package org.example.service.impl;import com.google.gson.Gson;
import com.google.gson.JsonObject;
import io.milvus.orm.iterator.QueryIterator;
import io.milvus.orm.iterator.SearchIteratorV2;
import io.milvus.response.QueryResultsWrapper;
import io.milvus.v2.client.MilvusClientV2;
import io.milvus.v2.common.ConsistencyLevel;
import io.milvus.v2.common.DataType;
import io.milvus.v2.common.IndexParam;
import io.milvus.v2.service.collection.request.*;
import io.milvus.v2.service.collection.response.DescribeCollectionResp;
import io.milvus.v2.service.vector.request.InsertReq;
import io.milvus.v2.service.vector.request.QueryIteratorReq;
import io.milvus.v2.service.vector.request.SearchIteratorReqV2;
import io.milvus.v2.service.vector.request.data.FloatVec;
import io.milvus.v2.service.vector.response.SearchResp;
import lombok.extern.slf4j.Slf4j;
import org.example.milvus.config.OldMilvusServiceClient;
import org.example.milvus.model.MilvusAdminClient;
import org.example.milvus.model.MilvusInsertClient;
import org.example.milvus.model.MilvusSearchClient;
import org.example.service.MilvusService;
import org.springframework.stereotype.Service;import javax.annotation.Resource;
import java.util.*;/**
* @author 杨镇宇
* @date 2025/7/8 09:02
* @version 1.0
*/
@Slf4j
@Service
public class MilvusServiceImpl implements MilvusService {/*** key:search-module*/@Resourceprivate MilvusSearchClient searchClient;/*** key:insert-module*/@Resourceprivate MilvusInsertClient insertClient;/*** key:admin-module*/@Resourceprivate MilvusAdminClient adminClient;/*** milvusServiceClient旧客户端*/@Resourceprivate OldMilvusServiceClient oldMilvusServiceClient;// 归一化函数(单位向量)public  List<Float> normalizeVector(List<Float> vector) {double norm = 0.0;for (Float v : vector) {norm += v * v;}norm = Math.sqrt(norm);List<Float> normalized = new ArrayList<>();for (Float v : vector) {normalized.add((float) (v / norm));}return normalized;}/*** java实战-Milvus 向量库 集合字段变更*/@Overridepublic void updateMigrateData() {MilvusClientV2 client = adminClient.getClient();int dim = 4;// 维度String collectionName = "java_test";String description = "测试表";CreateCollectionReq.CollectionSchema collectionSchema = client.createSchema();collectionSchema.addField(AddFieldReq.builder().fieldName("id").dataType(DataType.Int64).isPrimaryKey(Boolean.TRUE).autoID(Boolean.FALSE).description("id").build());collectionSchema.addField(AddFieldReq.builder().fieldName("vector").dataType(DataType.FloatVector).dimension(dim).description("向量字段").build());collectionSchema.addField(AddFieldReq.builder().fieldName("user").dataType(DataType.VarChar).maxLength(100).description("用户").build());collectionSchema.addField(AddFieldReq.builder().fieldName("timestamp").dataType(DataType.Int64).description("时间").build());log.info("=============创建测试表提供测试===================");createTable(dim,collectionSchema,client,collectionName,description);log.info("--------------插入1200条数据用作测试--------------");MilvusClientV2 insert = insertClient.getClient();batchInsert(insert,collectionName);log.info("--------------查询前10条数据验证--------------");List<Float> queryVector = Arrays.asList(1.0f, 2.0f, 3.0f, 4.0f); // 示例向量query(client,queryVector,collectionName);// 新增字段AddFieldReq addBuild = AddFieldReq.builder().fieldName("age").dataType(DataType.VarChar).maxLength(100).description("年龄").isNullable(true)   // ✅ 允许为空.build();collectionSchema.addField(addBuild);log.info("=============创建新表,进行数据迁移===================");String newCollection = migrateData(client, collectionName, collectionSchema, dim, description);log.info("--------------查询前10条数据验证--------------");query(client,queryVector,newCollection);log.info("删除旧表");DropCollectionReq dropCollectionReq = DropCollectionReq.builder().collectionName(collectionName).build();client.dropCollection(dropCollectionReq);}public void query(MilvusClientV2 client,List<Float> queryVector,String collectionName){queryVector = normalizeVector(queryVector); // ✨ 添加归一化SearchIteratorReqV2 searchReq = SearchIteratorReqV2.builder().collectionName(collectionName)              // 替换为你的集合名.outputFields(Arrays.asList("id", "user", "timestamp","vector")) // 可加你想验证的字段.batchSize(10L).vectorFieldName("vector").vectors(Collections.singletonList(new FloatVec(queryVector))).filter("id > 0")  // 可选条件,确保有返回.topK(10)          // 查询前 10 个最相似的.metricType(IndexParam.MetricType.COSINE).consistencyLevel(ConsistencyLevel.BOUNDED).build();SearchIteratorV2 searchIterator = client.searchIteratorV2(searchReq);log.info("🔍 表【{}】:前 10 条查询结果:",collectionName);while (true) {List<SearchResp.SearchResult> res = searchIterator.next();if (res.isEmpty()) {log.info("🔍 查询结束");searchIterator.close();break;}for (SearchResp.SearchResult record : res) {Map<String, Object> entity = record.getEntity();log.info("🔍 >>>>> id:{},user:{},timestamp:{},vector:{}",entity.get("id"),entity.get("user"),entity.get("timestamp"),entity.get("vector"));}}}/*** 插入1200条数据* @param client*/public void batchInsert(MilvusClientV2 client,String collectionName){Gson gson = new Gson();List<JsonObject> dataList = new ArrayList<>();for (long i = 1; i <= 1200; i++) {JsonObject row = new JsonObject();// 构造向量:这里用随机值或自定义值填充List<Float> vector = Arrays.asList(1.0f * i, 2.0f * i, 3.0f * i, 4.0f * i);  // dim = 4row.add("vector", gson.toJsonTree(normalizeVector(vector)));row.addProperty("id", i);                    // 手动指定主键row.addProperty("user", "user_" + i);        // 示例字段row.addProperty("timestamp", System.currentTimeMillis());     // 注意 Int16 用 shortdataList.add(row);// 每 200 条插入一次,避免过大 payloadif (dataList.size() == 200 || i == 1200) {InsertReq insertReq = InsertReq.builder().collectionName(collectionName)  // 替换为你的集合名.data(dataList).build();client.insert(insertReq);log.info("✅ 已插入 {} 条数据", i);dataList.clear();}}}/*** 新增字段,数据迁移*/public String migrateData(MilvusClientV2 client, String collectionName,CreateCollectionReq.CollectionSchema collectionSchema,int dim,String description){String newCollection = collectionName + "_new";// 获取旧集合结构信息DescribeCollectionResp oldSchemaResp = client.describeCollection(DescribeCollectionReq.builder().collectionName(collectionName).build());List<String> oldFieldNames = oldSchemaResp.getFieldNames();// 创建新集合createTable(dim,collectionSchema,client,newCollection,description);// 获取新集合结构信息DescribeCollectionResp newSchemaResp = client.describeCollection(DescribeCollectionReq.builder().collectionName(newCollection).build());List<String> newFieldNames = newSchemaResp.getFieldNames();Set<String> oldFieldSet = new HashSet<>(oldFieldNames);Gson gson = new Gson();  // 如果没有引入 gson,请确保引入:com.google.code.gson:gsonlong offset = 0;long limit = 200;while (true) {QueryIteratorReq queryReq = QueryIteratorReq.builder().collectionName(collectionName).expr("id > 0").outputFields(oldFieldNames).batchSize(limit).offset(offset).limit(limit).consistencyLevel(ConsistencyLevel.BOUNDED).build();QueryIterator queryIterator = client.queryIterator(queryReq);List<QueryResultsWrapper.RowRecord> rows = queryIterator.next();queryIterator.close();if (rows.isEmpty()) {log.info("✅ 数据迁移完成,总记录数: {}", offset);break;}List<JsonObject> insertRows = new ArrayList<>();for (QueryResultsWrapper.RowRecord row : rows) {JsonObject json = new JsonObject();for (String field : newFieldNames) {if (oldFieldSet.contains(field)) {Object value = row.get(field);if (value instanceof Number) {json.addProperty(field, (Number) value);} else if (value instanceof String) {json.addProperty(field, (String) value);} else if (value instanceof List<?>) {json.add(field, gson.toJsonTree(value));} else {log.warn("⚠ 未处理的字段类型: {} -> {}", field, value);}} else {// 🔧 新增字段统一设置为 null 或默认值json.addProperty(field, "");}}insertRows.add(json);}InsertReq insertReq = InsertReq.builder().collectionName(newCollection).data(insertRows).build();client.insert(insertReq);log.info("✅ 插入第 {} ~ {} 条数据", offset + 1, offset + rows.size());offset += rows.size();}log.info("✅ 集合 `{}` 迁移完成", newCollection);return newCollection;}/*** 创建集合 + 为所有向量字段建索引*/public static void createTable(int dim,CreateCollectionReq.CollectionSchema collectionSchema,MilvusClientV2 client, String collectionName,  String description) {// 先判断是否存在,存在先删除HasCollectionReq name = HasCollectionReq.builder().collectionName(collectionName).build();if (client.hasCollection(name)) {log.info("Collection `{}` 已存在,准备删除", collectionName);client.dropCollection(DropCollectionReq.builder().collectionName(collectionName)// 集合名称.timeout(60000L)//进程的超时时长。指定时长到期后,进程将终止, 默认为60000L.build());log.info("Collection `{}` 删除成功", collectionName);}IndexParam indexParam = IndexParam.builder().fieldName("vector").metricType(IndexParam.MetricType.COSINE) // 检索时计算向量之间的相似度方式使用 COSINE(余弦相似度),COSINE 适用于归一化向量的相似度匹配,等价于夹角越小越相似。.build();// 创建 CollectionSchema 和 CollectionCreateCollectionReq createCollectionReq = CreateCollectionReq.builder().collectionSchema(collectionSchema) // 留空表示此集合将使用默认设置创建。要设置具有自定义架构的集合,您需要创建一个CollectionSchema对象并在此处引用它。.autoID(false)// 当数据插入到该集合时,主字段是否自动递增 ,TRUE自动递增.collectionName(collectionName)//表名.description(description)//描述.dimension(dim) // 保存向量嵌入的集合字段的维数.metricType("COSINE")//此集合使用的算法用于测量向量嵌入之间的相似性。   该值默认为IP。可能的值为L2、IP和COSINE。有关这些指标类型的详细信息.indexParams(Collections.singletonList(indexParam)).build();// 创建集合client.createCollection(createCollectionReq);log.info("Collection `{}` 创建完成", collectionName);DescribeCollectionResp resp = client.describeCollection(DescribeCollectionReq.builder().collectionName(collectionName).build());List<CreateCollectionReq.FieldSchema> fieldSchemaList = resp.getCollectionSchema().getFieldSchemaList();log.info("-------------------------【{}】集合结构-----------------------",collectionName);for (CreateCollectionReq.FieldSchema fieldSchema:fieldSchemaList){String field = fieldSchema.getName();String fieldDescription = fieldSchema.getDescription();DataType dataType = fieldSchema.getDataType();log.info("字段名:{},类型:{},备注:{}",field,dataType,fieldDescription);}}}

4. 测试

测试执行:
在这里插入图片描述
效果:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/pingmian/88193.shtml
繁体地址,请注明出处:http://hk.pswp.cn/pingmian/88193.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

HashMap的get与put流程源码深度解析

目录 一、HashMap基础结构 二、put操作流程分析 put操作关键步骤总结 三、get操作流程分析 get操作关键步骤总结 四、延伸 1.hash()方法 2. 扩容 resize()方法的主要逻辑&#xff1a; Java 8中对扩容的优化&#xff1a; 3. 转向红黑树的条件 HashMap作为Java集合框架…

初识Neo4j之图数据库(二)

目录 一、图数据库如何工作 二、为什么使用图数据库 Neo4j 图数据库以节点、关系和属性的形式存储数据&#xff0c;而不是用表或文档进行数据存储。这意味着用户可以像在白板上画草图那样来组织数据。而且&#xff0c;由于图数据库不受限于预先定义的数据模型&#xff0c;因此…

Python 中 ffmpeg-python 库的详细使用

文章目录 一、ffmpeg-python库概述1.1 ffmpeg-python库介绍1.2 安装1.3 优势1.4 常用场景二、基本使用2.1 视频信息获取2.2 视频转码三、视频处理3.1 视频裁剪3.2 视频缩放3.3 视频旋转四、音频处理4.1 提取音频4.2 音频混合五、高级使用5.1 添加水印5.2 视频滤镜5.3 视频合成5…

JAVA策略模式demo【设计模式系列】

策略模式用在统一的入口&#xff0c;但需要根据某个类型判断后续执行逻辑&#xff0c;例如我最近遇到的场景&#xff1a;我需要对接一个设备&#xff0c;前端请求我这边&#xff0c;我再去和设备交互&#xff0c;但设备种类很多&#xff0c;各自有自己的接入规则&#xff01;传…

mysql索引:索引应该选择哪种数据结构 B+树 MySQL中的页 页主体 页目录 索引分类

索引是什么?为什么要使用索引? 以前学数据结构时学了ArrayList,我们可以往里面存放数据 但是有问题,也就是说当程序重启或是电脑关机之后,数据就没有了,为什么? 因为他的数据是保存在内存中的 数据库把数据保存在磁盘中,就可以完成对数据的持久化内存与外存的区别 内存&…

SpringBoot静态资源与缓存配置全解析

springboot中静态资源classpath就是resource文件夹下欢迎页规则项目启动默认去找静态资源下的index.html页面 默认访问该页面favicon原则在静态资源目录下寻找favicon.ico缓存实验在请求中使用Cache-Control 时&#xff0c;它可选的值有&#xff1a;在响应中使用Cache-Control …

基于 Python Django 和 Spark 的电力能耗数据分析系统设计与实现7000字论文实现

摘要随着能源问题日益突出&#xff0c;电力能耗数据分析对于提高能源利用效率、降低能源消耗具有重要意义。本文设计并实现了一个基于 Python Django 和 Spark 的电力能耗数据分析系统。系统采用前后端分离架构&#xff0c;前端使用 Django 框架实现用户界面&#xff0c;后端使…

elementUI vue2 前端表格table数据导出(二)

为啥前端导出不在赘述了&#xff0c;不然读者也难看到这篇文章。第一步&#xff1a;安装依赖npm install vue-json-excel第二步&#xff1a;引用依赖配置// 导出Excel文件组件 import JsonExcel from vue-json-excel; Vue.component(downloadExcel, JsonExcel)第三步&#xff1…

RabbitMQ 4.1.1-Local random exchange体验

Local Random Exchange 一种 RabbitMQ 4.0 引入的新型交换机&#xff0c;主要是为 request-reply&#xff08;RPC&#xff09;场景 设计的。 使用这种交换机时&#xff0c;消息只会被路由到本地节点上的队列&#xff0c;可以确保极低的消息发布延迟。如果有多个本地队列绑定到该…

中山排气歧管批量自动化智能化3D尺寸测量及cav检测分析

当前制造业快速发展&#xff0c;传统测量方法正面临严峻挑战。生产规模的持续扩张使得现有测量手段逐渐暴露出效率不足的问题&#xff0c;这种技术滞后性正在直接影响企业的整体生产效率。具体表现为测量速度跟不上生产节拍&#xff0c;精度要求难以达标&#xff0c;最终导致生…

Debian 11 Bullseye 在线安装docker

首先移除所有错误的 Docker 软件源&#xff1a;sudo rm -f /etc/apt/sources.list.d/docker*安装必要依赖sudo apt update sudo apt install -y ca-certificates curl gnupg添加 Docker 官方 GPG 密钥&#xff08;使用国内镜像&#xff09;&#xff1a;curl -fsSL https://mirr…

Spring Boot 项目中多数据源配置使用场景

在 Spring Boot 中配置多数据源是一个非常常见的需求&#xff0c;主要用于以下场景&#xff1a; 读写分离&#xff1a;一个主数据库&#xff08;Master&#xff09;负责写操作&#xff0c;一个或多个从数据库&#xff08;Slave&#xff09;负责读操作&#xff0c;以提高性能和可…

FAAC 在海思平台使用得到aac实时音频流

FAAC 在海思平台使用得到aac实时音频流 使用 FAAC将音频 pcm转为 aac 主要参见这篇博客 FAAC 在君正平台使用得到aac实时音频流_君正 x2600 音频-CSDN博客

javascript函数参数类似python函数参数星号*解耦数组

序言通常情况下&#xff0c;我们很可能不清楚参数有多少&#xff0c;这个时候用的都是数组。但是使用数组和单个元素&#xff0c;从内心情感来说&#xff0c;它们是两种维度&#xff0c;为了让参数成为一个数组&#xff0c;把单个输入的参数强加一个数组的外壳&#xff0c;并不…

C语言基础(1)

1.编译器的选择 我们的c语言是一门&#xff0c;我们写的c语言代码是文本文件(存放在.c为后缀的文件中)&#xff0c;文本文件本身无法被执行&#xff0c;必须通过编译器的编译和链接器的链接&#xff0c;生成可执行的二进制文件&#xff0c;才能够被执行注意&#xff1a; 每个源…

Rust赋能美团云原生DevOps实践

Rust 云原生 DevOps 实践 在云原生环境中,Rust 的高性能与安全性使其成为构建微服务和基础设施工具的理想选择。Docker 作为容器化标准工具,结合 Rust 的跨平台特性,可高效实现持续集成与部署(CI/CD)。 构建优化的 Rust Docker 镜像 多阶段构建是 Rust 项目容器化的关键…

计算机网络实验——配置ACL

ACL基础一、实验目的1. 配置H3C路由器基本ACL。二、实验要求1. 熟练掌握网络配置能力。2. 熟练掌握ACL基本配置。三、实验步骤&#xff08;1&#xff09;使用reset saved-configuration命令和reboot命令&#xff0c;重置路由器原有配置&#xff0c;如图1所示。图 1&#xff08;…

在本地部署mcp服务器实现自然语言操作mysql数据库,轻松实现数据表的增~ 删~ 改~ 查~

1.将写好的mcp_server代码放在本地任意盘&#xff01; import asyncio import logging import os import sys from mysql.connector import connect, Error from mcp.server import Server from mcp.types import Resource, Tool, TextContent from pydantic import AnyUrl# Co…

2025快手创作者中心发布视频python实现

难度还行&#xff0c;只有一个__NS_sig3加密&#xff0c;流程麻烦点cookies_list cookie.split("; ")cookie_dict {}# 遍历每个 Cookie&#xff0c;根据等号将键值对拆分并添加到字典中for cookie in cookies_list:key_value cookie.split("")if len(ke…

Android 组件内核

文章目录什么是binder1. 什么是Binder&#xff1f;2. Binder架构组成3. 工作原理与通信流程1&#xff09;服务注册2&#xff09;服务查询3&#xff09;通信过程4&#xff09;核心数据结构4. 关键技术点5. 常见面试考点1&#xff09;Binder与传统IPC&#xff08;Socket、管道、共…