Springboot整合Milvus向量库

1. Milvus的Maven依赖, 配置如下

        <dependency><groupId>io.milvus</groupId><artifactId>milvus-sdk-java</artifactId><version>2.3.4</version><exclusions><exclusion><artifactId>log4j-slf4j-impl</artifactId><groupId>org.apache.logging.log4j</groupId></exclusion></exclusions></dependency>

PS: 请注意!引入的版本要看你部署的milvus服务的版本是多少,然后milvus官网上会有milvus服务对应的java sdk版本的版本号,版本号一定要对应的上  这样相应的版本api文档接口才可以用

milvus官方文档:Milvus v2.3.x documentation

然后2.3.4版本的java sdk的milvus还需要引用google 的protobuf包,不然会报错提示找不到此包

此包也要注意对应milvus的版本  这里官网没说明,我自行尝试可用的是3.24.1版本对应milvus的2.3.4版本的, 配置如下:

        <dependency><groupId>com.google.protobuf</groupId><artifactId>protobuf-java</artifactId><version>3.24.1</version></dependency>

2. 向量库的配置类 获取向量库服务地址 登录用户密码等

import io.milvus.client.MilvusServiceClient;
import io.milvus.param.ConnectParam;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class MilvusConfig {@Value("${milvus.host}")private String host;@Value("${milvus.port}")private Integer port;@Value("${milvus.username}")private String username;@Value("${milvus.password}")private String password;@Beanpublic MilvusServiceClient milvusServiceClient() {return new MilvusServiceClient(ConnectParam.newBuilder().withHost(host).withPort(port).withAuthorization(username, password).build());}
}

application.yml配置文件里配置相应的数据信息

3. 根据milvus 2.3.5 java SDK提供的API接口  调测相关使用的接口 

如:创建集合,创建索引,加载集合到内存,插入向量数据,查询向量数据并返回结果 删除集合

import java.util.List;/*** milvus向量数据库相关业务接口** @author Jx* @version 2024-3-18*/
public interface IMilvusService {Boolean hasCollect(String collectionName);void create(String collectionName, String desc);Boolean insert(String name, List<Long> textIds, List<List<Float>> vectorList);List<Long> search(String name, int topK, List<List<Float>> vectorList);void dropCollect(String name);void createIndex(String name);void dropVectors(String name, List<Long> indexIds);
}

实现类

import com.beust.jcommander.internal.Lists;
import com.geb.config.FaceArchive;
import com.geb.service.IMilvusService;
import io.milvus.client.MilvusServiceClient;
import io.milvus.common.clientenum.ConsistencyLevelEnum;
import io.milvus.grpc.DataType;
import io.milvus.grpc.GetLoadStateResponse;
import io.milvus.grpc.MutationResult;
import io.milvus.grpc.SearchResults;
import io.milvus.param.IndexType;
import io.milvus.param.MetricType;
import io.milvus.param.R;
import io.milvus.param.RpcStatus;
import io.milvus.param.collection.*;
import io.milvus.param.dml.DeleteParam;
import io.milvus.param.dml.InsertParam;
import io.milvus.param.dml.SearchParam;
import io.milvus.param.highlevel.collection.ListCollectionsParam;
import io.milvus.param.highlevel.collection.response.ListCollectionsResponse;
import io.milvus.param.highlevel.dml.DeleteIdsParam;
import io.milvus.param.highlevel.dml.response.DeleteResponse;
import io.milvus.param.index.CreateIndexParam;
import io.milvus.response.SearchResultsWrapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;import java.util.ArrayList;
import java.util.List;
import java.util.Map;@Slf4j
@Service
public class MilvusServiceImpl implements IMilvusService {@Autowiredprivate MilvusServiceClient milvusServiceClient;final IndexType INDEX_TYPE = IndexType.IVF_FLAT;   // IndexTypefinal String INDEX_PARAM = "{\"nlist\":1024}";     // ExtraParam/*** 创建集合的字段* text_id  对应的文本id* vector  向量字段* tag  标签*/private final String TEXTID = "text_id";private final String VECTOR = "vector";private final String TAG = "tag";private final int dimension = 1024;/*** 创建集合  指定集合名称*/@Overridepublic void create(String collectionName, String desc){log.info("Miluvs create collectionName:{}, desc:{}", collectionName, desc);boolean has = hasCollect(collectionName);log.info("Miluvs hasCollect:{}", has);// 不存在此集合才进行创建集合if(!has){//  创建集合 设置索引 加载集合到内存中FieldType fieldType1 = FieldType.newBuilder().withName(TEXTID).withDataType(DataType.Int64).withPrimaryKey(true).withAutoID(false).build();FieldType fieldType2 = FieldType.newBuilder().withName(VECTOR)  // 设置向量名称.withDataType(DataType.FloatVector)  // 设置向量类型.withDimension(dimension) // 设置向量维度.build();FieldType fieldType3 = FieldType.newBuilder().withName(TAG).withDataType(DataType.Int64).build();CreateCollectionParam createCollectionReq = CreateCollectionParam.newBuilder().withCollectionName(collectionName).withDescription(desc).withShardsNum(2).addFieldType(fieldType1).addFieldType(fieldType2).addFieldType(fieldType3).withEnableDynamicField(true).withConsistencyLevel(ConsistencyLevelEnum.BOUNDED).build();R<RpcStatus> response = milvusServiceClient.createCollection(createCollectionReq);if (response.getStatus() != R.Status.Success.getCode()) {log.info("milvus create fail message:{}", response.getMessage());}else{// 创建集合索引并加载集合到内存  插入数据和搜索的前置操作!!createIndex(collectionName);}}}/*** 创建集合索引 -- 加在向量字段上* @param collectionName*/public void createIndex(String collectionName){milvusServiceClient.createIndex(CreateIndexParam.newBuilder().withCollectionName(collectionName).withFieldName(VECTOR).withIndexType(INDEX_TYPE).withMetricType(MetricType.L2).withExtraParam(INDEX_PARAM).withSyncMode(Boolean.FALSE).build());// 加载所创建的集合loadCollection(collectionName);}/*** 加载集合* @param collectionName*/public void loadCollection(String collectionName){milvusServiceClient.loadCollection(LoadCollectionParam.newBuilder().withCollectionName(collectionName).build());// You can check the loading statusGetLoadStateParam param = GetLoadStateParam.newBuilder().withCollectionName(collectionName).build();R<GetLoadStateResponse> stateResponse = milvusServiceClient.getLoadState(param);if (stateResponse.getStatus() != R.Status.Success.getCode()) {System.out.println(stateResponse.getMessage());}}/*** 集合是否存在* @return*/@Overridepublic Boolean hasCollect(String collectionName){R<Boolean> hasResult = milvusServiceClient.hasCollection(HasCollectionParam.newBuilder().withCollectionName(collectionName).build());if (hasResult.getStatus() == R.Status.Success.getCode()) {return hasResult.getData();}return false;}/*** 向量库中插入数据*/@Overridepublic Boolean insert(String name, List<Long> textIds, List<List<Float>> vectorList){log.info("milvus insert name:{}, textIds:{}, vectorList:{}", name, textIds, vectorList);List<Long> tagList = new ArrayList<>();for (Long textId : textIds) {tagList.add(0L);}List<InsertParam.Field> fieldsInsert = new ArrayList<>();fieldsInsert.add(new InsertParam.Field(TEXTID, textIds));  // 文本对应的ids数据listfieldsInsert.add(new InsertParam.Field(VECTOR, vectorList));  // 转换后的向量数据listfieldsInsert.add(new InsertParam.Field(TAG, tagList));  // 标签占位符  给个0InsertParam param = InsertParam.newBuilder().withCollectionName(name).withFields(fieldsInsert).build();R<MutationResult> response = milvusServiceClient.insert(param);if (response.getStatus() != R.Status.Success.getCode()) {log.info("milvus insert vector fail! message:{}", response.getMessage());return false;}else{return true;}}/*** 删除集合* @param collectionName*/@Overridepublic void dropCollect(String collectionName){milvusServiceClient.dropCollection(DropCollectionParam.newBuilder().withCollectionName(collectionName).build());}/*** 根据ids删除向量* @param collectionName* @param indexIds*/@Overridepublic void dropVectors(String collectionName, List<Long> indexIds){String expr =  TEXTID + " in " + indexIds;DeleteParam param = DeleteParam.newBuilder().withCollectionName(collectionName).withExpr(expr).build();R<MutationResult> response = milvusServiceClient.delete(param);if (response.getStatus() != R.Status.Success.getCode()) {System.out.println(response.getMessage());}}/*** 向量搜索 - 向量库中用具体向量搜索 - 返回indexIds*/@Overridepublic List<Long> search(String collectionName, int topK , List<List<Float>> vectorList){// 构建查询条件  进行向量字段查询   待测试1024维度向量SearchParam searchParam = io.milvus.param.dml.SearchParam.newBuilder().withCollectionName(collectionName).withVectorFieldName(VECTOR).withOutFields(Lists.newArrayList("*")).withVectors(vectorList).withTopK(topK).build();R<SearchResults> searchResults = milvusServiceClient.search(searchParam);if (searchResults.getStatus() != R.Status.Success.getCode()) {log.info(searchResults.getMessage());}List<Long> textIdList = new ArrayList<>() ;SearchResultsWrapper wrapper = new SearchResultsWrapper(searchResults.getData().getResults());for (int i = 0; i < vectorList.size(); ++i) {List<SearchResultsWrapper.IDScore> scores = wrapper.getIDScore(i);for (SearchResultsWrapper.IDScore score:scores) {Map<String, Object> filedsMap = score.getFieldValues();textIdList.add(Long.valueOf(String.valueOf(filedsMap.get(TEXTID))));}}return textIdList;}/*** 删除集合中的 id对应的向量*/public void deleteEmbedingById(){List<String> ids = Lists.newArrayList("441966745769900131","441966745769900133");DeleteIdsParam param = DeleteIdsParam.newBuilder().withCollectionName(FaceArchive.COLLECTION_NAME_MILVUS_TESTONE).withPrimaryIds(ids).build();R<DeleteResponse> response = milvusServiceClient.delete(param);if (response.getStatus() != R.Status.Success.getCode()) {System.out.println(response.getMessage());}for (Object deleteId : response.getData().getDeleteIds()) {System.out.println(deleteId);}}// 测试用的向量数据类型public List<List<Float>> getListVector(){List<Float> vectorData = new ArrayList<>();for (int i = 0; i < 1; i++) {vectorData.add((float) Math.random());}List<List<Float>> vectors = new ArrayList<>();vectors.add(vectorData);return vectors;}
}

以上,跟业务进行结合  直接调用操作向量库的API接口即可~

PS:milvus  集成在springboot项目中踩的坑:

#首先就是milvus和protobuf的版本要对应上  可以查下官网api提供的服务端的milvus版本对应的java sdk milvus版本    然后根据milvus sdk版本再找到对应的protobuf版本

#其次  根据官网文档api创建完集合后是无法自动加载集合的  需要手动为集合创建一个索引  比如IVF类型的索引  再进行集合加载到内存  然后才可以对该集合查询插入数据等操作

插入过程中: 所有字段值都不能为空 且 所有字段值条数都需一样  也就是统一字段条数  一致!!

#还有就是,创建集合时候  确定好向量字段的维度,

后面插入向量数据以及查询向量数据的数据维度要与创建向量字段的维度相同!!

注意! milvus向量库只负责向量的操作存储及查询这些,并不负责文本or视频音频转为向量数据的过程,此过程需要专门模型转换进行数据处理为向量数据才可用milvus向量数据库操作!

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

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

相关文章

组合总和-java

题目描述: 给你一个 无重复元素 的整数数组 candidates 和一个目标整数 target &#xff0c;找出 candidates 中可以使数字和为目标数 target 的 所有 不同组合 &#xff0c;并以列表形式返回。你可以按 任意顺序 返回这些组合。 candidates 中的 同一个 数字可以 无限制重复被…

HTML常用的图片标签和超链接标签

目录 一.常用的图片标签和超链接标签&#xff1a; 1.超链接标签&#xff1a; 前言: 超链接的使用&#xff1a; target属性: 1)鼠标样式&#xff1a; 2)颜色及下划线: 总结: 2.图片标签&#xff1a; 前言: img的使用: 设置图片&#xff1a; 1.设置宽度和高度: 2.HTM…

C++心决之内联函数+auto关键字+指针空值

目录 7.内联函数 7.1 概念 7.2 特性 8. auto关键字(C11) 8.1 类型别名思考 8.2 auto简介 8.3 auto的使用细则 8.4 auto不能推导的场景 9. 基于范围的for循环(C11) 9.1 范围for的语法 9.2 范围for的使用条件 10. 指针空值nullptr(C11) 10.1 C98中的指针空值 7.内联…

R语言颜色细分

1.如何对R语言中两种颜色之间进行细分 2.代码&#xff1a; x <- colorRampPalette(c("#FC8D62","#FDEAE6"))(12) #打印向量值 # 按字典顺序排序颜色值 x_sorted <- sort(x,decreasing TRUE)# 打印排序后的颜色值 print(x_sorted)#展示颜色 scales:…

18.web 应用测试

每年必考&#xff1b; 考几个关键点&#xff1a; 1、计算通信量&#xff1b;给定并发多少、每个并发事务请求的量是多少、单位时间并发有多少个请求&#xff1b;计算吞吐量&#xff1b; 解&#xff1a;记公式&#xff1b;课上不讲&#xff0c;真题里有公式&#xff1b;比较容易…

解决Flutter应用在苹果商店上架中常见的问题与挑战

引言 Flutter是一款由Google推出的跨平台移动应用开发框架&#xff0c;其强大的性能和流畅的用户体验使其备受开发者青睐。然而&#xff0c;开发一款应用只是第一步&#xff0c;将其成功上架到苹果商店才是实现商业目标的关键一步。本文将详细介绍如何使用Flutter将应用程序上…

第十四章 MySQL

一、MySQL 1.1 MySql 体系结构 MySQL 架构总共四层&#xff0c;在上图中以虚线作为划分。 1. 最上层的服务并不是 MySQL 独有的&#xff0c;大多数给予网络的客户端/服务器的工具或者服务都有类似的架构。比如&#xff1a;连接处理、授权认证、安全等。 2. 第二层的架构包括…

JWFD流程图转换为矩阵数据库的过程说明

在最开始设计流程图的时候&#xff0c;请务必先把开始节点和结束节点画到流程图上面&#xff0c;就是设计器面板的最开始两个按钮&#xff0c;先画开始点和结束点&#xff0c;再画中间的流程&#xff0c;然后保存&#xff0c;这样提交到矩阵数据库就不会出任何问题&#xff0c;…

MQ消息队列详解以及MQ重复消费问题

MQ消息队列详解以及MQ重复消费问题 1、解耦2、异步调用3、流量削峰4、MQ重复消费问题&#xff0c;以及怎么解决&#xff1f;4.1、重复消费产生4.2、解决方法&#xff1a; https://blog.csdn.net/qq_44240587/article/details/104630567 核心的就是&#xff1a;解耦、异步、削锋…

C#/WPF 使用开源Wav2Lip做自己的数字人(无需安装环境)

实现效果 Speaker Wav2Lip概述 2020年&#xff0c;来自印度海德拉巴大学和英国巴斯大学的团队&#xff0c;在ACM MM2020发表了的一篇论文《A Lip Sync Expert Is All You Need for Speech to Lip Generation In The Wild 》&#xff0c;在文章中&#xff0c;他们提出一个叫做Wa…

【R】Error in library(foreach) : 不存在叫‘foreach’这个名字的程辑包

Error in library(foreach) : 不存在叫‘foreach’这个名字的程辑包 此外: Warning message: package ‘parallel’ is a base package, and should not be updated 解决方法 缺少名为 foreach 的包&#xff0c;使用install.packages("foreach")将名为foreach 的包…

人脸、指纹、刷卡、密码、远程,一文速懂不同功能门禁系统怎么选?

门禁系统顾名思义就是对出入口通道进行管制的系统&#xff0c;它是在传统的门锁基础上发展而来。常见的门禁系统包括&#xff1a;密码识别门禁系统、刷卡识别门禁系统、生物识别门禁系统以及线上远程开门系统等。 在选择门禁系统时&#xff0c;需要根据不同的场景和需求&#x…

游戏引擎中的物理系统

一、物理对象与形状 1.1 对象 Actor 一般来说&#xff0c;游戏中的对象&#xff08;Actor&#xff09;分为以下四类&#xff1a; 静态对象 Static Actor动态对象 Dynamic Actor ---- 可能受到力/扭矩/冲量的影响检测器 TriggerKinematic Actor 运动学对象 ---- 忽略物理法则…

WordPress外贸建站Astra免费版教程指南(2024)

在WordPress的外贸建站主题中&#xff0c;有许多备受欢迎的主题&#xff0c;如Avada、Astra、Hello、Kadence等最佳WordPress外贸主题&#xff0c;它们都能满足建站需求并在市场上广受认可。然而&#xff0c;今天我要介绍的是一个不断颠覆建站人员思维的黑马——Astra主题。 原…

正则表达式(1)

文章目录 专栏导读1、match2、匹配目标3、通用匹配4、常用匹配规则表格 专栏导读 ✍ 作者简介&#xff1a;i阿极&#xff0c;CSDN 数据分析领域优质创作者&#xff0c;专注于分享python数据分析领域知识。 ✍ 本文录入于《python网络爬虫实战教学》&#xff0c;本专栏针对大学生…

朱啕虎对中美AIGC差距的观点总结

根据访谈内容,我总结了以下5个主题,每个主题包含相关的观点: 中美在大模型和应用创新方面的差距 美国在大模型和应用创新方面更为领先中国在数据和应用场景方面优势明显美国的创新更多集中在"顶层"- 追求更高端的应用,如生成视频、电影等,但实现难度较大中国的AIGC…

Jamba: A Hybrid Transformer-Mamba Language Model

Jamba: A Hybrid Transformer-Mamba Language Model 相关链接&#xff1a;arXiv 关键字&#xff1a;hybrid architecture、Transformer、Mamba、mixture-of-experts (MoE)、language model 摘要 我们介绍了Jamba&#xff0c;一种新的基于新颖混合Transformer-Mamba混合专家&am…

Redis缓存穿透、击穿与雪崩及对应的解决办法

文章目录 Redis缓存穿透、击穿和雪崩一. 缓存穿透二. 缓存击穿三. 缓存雪崩 Redis缓存穿透、击穿和雪崩 图中的上半部分可理解为缓存雪崩&#xff0c;下半部分可理解为缓存穿透&#xff0c;接下来一起学习 一. 缓存穿透 概念 简而言之&#xff1a;数据查不到 用户想要查询一个…

如何优化TCP?TCP的可靠传输机制是什么?

在网络世界中&#xff0c;传输层协议扮演着至关重要的角色&#xff0c;特别是TCP协议&#xff0c;以其可靠的数据传输特性而广受青睐。然而&#xff0c;随着网络的发展和数据量的激增&#xff0c;传统的TCP协议在效率方面遭遇了挑战。小编将深入分析TCP的可靠性传输机制&#x…

“由于找不到opencv_world3413.dll,无法继续执行代码”的解决方法

问题 在Windows系统中&#xff0c;编译完涉及到opencv的项目后&#xff0c;提示&#xff0c; 由于找不到opencv_world3413.dll&#xff0c;无法继续执行代码 解决方法 在编译好的opencv的bin文件内&#xff08;如&#xff1a;D:\code\vs2017\opencv\build\x64\vc15\bin&…