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;

    @Bean
    public 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 {

    @Autowired
    private MilvusServiceClient milvusServiceClient;


    final IndexType INDEX_TYPE = IndexType.IVF_FLAT;   // IndexType
    final 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;



    /**
     * 创建集合  指定集合名称
     */
    @Override
    public 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 status
        GetLoadStateParam 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
     */
    @Override
    public 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;
    }



    /**
     * 向量库中插入数据
     */
    @Override
    public 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数据list
        fieldsInsert.add(new InsertParam.Field(VECTOR, vectorList));  // 转换后的向量数据list
        fieldsInsert.add(new InsertParam.Field(TAG, tagList));  // 标签占位符  给个0
        InsertParam 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
     */
    @Override
    public void dropCollect(String collectionName){
        milvusServiceClient.dropCollection(
                DropCollectionParam.newBuilder()
                        .withCollectionName(collectionName)
                        .build()
        );
    }


    /**
     * 根据ids删除向量
     * @param collectionName
     * @param indexIds
     */
    @Override
    public 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
     */
    @Override
    public 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向量数据库操作!

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

JAVAEE之JavaScript

1.JavaScript JavaScript (简称 JS) 是世界上最流行的编程语言之一 是一个脚本语言, 通过解释器运行 主要在客户端(浏览器)上运行, 现在也可以基于 node.js 在服务器端运行. 脚本是什么&#xff1f; 脚本&#xff08;script&#xff09;是使用一种特定的描述性语言&#x…

【教程】Kotlin语言学习笔记(六)——泛型

写在前面&#xff1a; 如果文章对你有帮助&#xff0c;记得点赞关注加收藏一波&#xff0c;利于以后需要的时候复习&#xff0c;多谢支持&#xff01; 【Kotlin语言学习】系列文章 第一章 《认识Kotlin》 第二章 《数据类型》 第三章 《数据容器》 第四章 《方法》 第五章 《L…

[Rust开发]用可视化案例讲Rust编程6.动态分发与最终封装

全系列合集 [Rust开发]用可视化案例讲Rust编程1.用Rust画个百度地图 [Rust开发]用可视化案例讲Rust编程2. 编码的核心组成&#xff1a;函数 [Rust开发]用可视化案例讲Rust编程3.函数分解与参数传递 [Rust开发]用可视化案例讲Rust编程4.用泛型和特性实现自适配shapefile的读取 […

git可视化工具

Gitkraken GitKraken 是一款专门用于管理和协作Git仓库的图形化界面工具。它拥有友好直观的界面&#xff0c;使得Git的操作变得更加简单易用&#xff0c;尤其适合那些不熟悉Git命令行的开发者。GitKraken提供了丰富的功能&#xff0c;如代码审查、分支管理、仓库克隆、提交、推…

rabbitmq死信交换机,死信队列使用

背景 对于核心业务需要保证消息必须正常消费&#xff0c;就必须考虑消费失败的场景&#xff0c;rabbitmq提供了以下三种消费失败处理机制 直接reject&#xff0c;丢弃消息&#xff08;默认&#xff09;返回nack&#xff0c;消息重新入队列将失败消息投递到指定的交换机 对于核…

ubuntu-server部署hive-part4-部署hive

参照 https://blog.csdn.net/qq_41946216/article/details/134345137 操作系统版本&#xff1a;ubuntu-server-22.04.3 虚拟机&#xff1a;virtualbox7.0 部署hive 下载上传 下载地址 http://archive.apache.org/dist/hive/ apache-hive-3.1.3-bin.tar.gz 以root用户上传至…

财务数字化转型如何找到打通业财融合的关键点

敏捷应对外部复杂情况保持竞争力、加强内部协同联动实现降本增效、赋能流程再造推动企业在变化中进化……多重战略价值下&#xff0c;企业数字化变革已经从“可选项”变成了“必选项”。 财务数字化转型正在成为推动“高韧性”企业高增长的核心驱动力。现在&#xff0c;以财务助…

JavaScript基础代码练习之数列第n位

一、这段代码要求用户输入一个数字n&#xff0c;然后使用递归的方式计算斐波那契数列中第n位的值&#xff0c;并将结果以警告框的形式显示出来。斐波那契数列是一个经典的数学问题&#xff0c;其中每个数字是前两个数字的和&#xff0c;数列的前两个数字通常是1。因此&#xff…

【MATLAB源码-第28期】基于matlab的16QAM定时同步仿真,采用gardner算法,Costa锁相环。

操作环境&#xff1a; MATLAB 2022a 1、算法描述 正交幅度调制&#xff08;QAM&#xff0c;Quadrature Amplitude Modulation&#xff09;是一种在两个正交载波上进行幅度调制的调制方式。这两个载波通常是相位差为90度&#xff08;π/2&#xff09;的正弦波&#xff0c;因此…

DevOps与CI/CD简介

DevOps 是一种软件开发和运维的文化、实践和方法论&#xff0c;旨在通过加强开发团队和运维团队之间的合作和沟通&#xff0c;实现快速、高效、可靠的软件交付和运维。DevOps 是由 Development&#xff08;开发&#xff09;和 Operations&#xff08;运维&#xff09;两个单词组…

基于深度学习的常见车型识别系统(网页版+YOLOv8/v7/v6/v5代码+训练数据集)

摘要&#xff1a;在本博客中介绍了基于YOLOv8/v7/v6/v5的常见车型识别系统。核心技术采用YOLOv8&#xff0c;并融合了YOLOv7、YOLOv6、YOLOv5的算法优势&#xff0c;进行了细致的性能指标对比。详细介绍了国内外在常见车型识别方面的研究现状、数据集处理方法、算法原理、模型构…

Linux(centos) 安装GraalVM

文章目录 版权声明GraalVM 版权声明 本博客的内容基于我个人学习黑马程序员课程的学习笔记整理而成。我特此声明&#xff0c;所有版权属于黑马程序员或相关权利人所有。本博客的目的仅为个人学习和交流之用&#xff0c;并非商业用途。我在整理学习笔记的过程中尽力确保准确性&…

力扣-python-丑数

解答&#xff1a; class Solution:def isUgly(self, n: int) -> bool:if n < 0:return False# 将 n 依次除以 2、3、5&#xff0c;直到 n 不能再被这些因子整除while n % 2 0:n // 2while n % 3 0:n // 3while n % 5 0:n // 5return n 1class Solution:def isUgly(s…

手写简易操作系统(二十一)--硬盘驱动

前情提要 上面一节我们实现了 malloc 和 free 的系统调用&#xff0c;这一节我们来实现硬盘驱动。 一、硬盘分区 我们的文件系统安装在一块全新的硬盘中&#xff0c;我们先创建它&#xff0c;然后在给他分区。 1.1、创建硬盘 首先是创建&#xff0c;这个之前我们已经干过一…

《Git版本控制管理》笔记

第三章 git --version查看版本号git --help查看帮助文档裸双破折号分离参数 git diff -w master origin – tools/Makefile将当前目录或任何目录转化为Git版本库 git init 初始化之后项目目录中&#xff0c;有名为.git的文件git status 查看git状态git commit 提供日志消息和作…

Docker、Kubernetes之间的区别

比较容器化工具&#xff1a;了解 Docker、Kubernetes 在应用程序部署和管理方面的差异。 基本概述 Docker 是一个流行的容器化平台&#xff0c;允许开发人员在容器中创建、部署和运行应用程序。 Docker 提供了一组工具和 API&#xff0c;使开发人员能够构建和管理容器化应用程…

【星海随笔】Ubuntu22.04忘记密码

服务器篇&#xff1a; 有问题可留言。 第一步 远程console界面进入该设备 并重启该设备 如果看到这个界面情况 则点击右上角按钮 【发送 CtrlAltDelete】 调出grub启动菜单 NOTE&#xff1a;启动的后半段去点击这个按钮&#xff0c;前半段一直点会一直重启 如果是直连服务器&a…

AI智能客服机器人是什么?对企业重要吗?

在数字化时代&#xff0c;客户服务是企业与客户建立牢不可破关系的重要桥梁。AI智能客服机器人&#xff0c;顾名思义&#xff0c;就是利用人工智能技术提升客户服务体验的自动化工具。今天&#xff0c;就让我们来揭开AI智能客服机器人的神秘面纱&#xff0c;并讨论它对企业的重…

增强Java技能:使用OkHttp下载www.dianping.com信息

在这篇技术文章中&#xff0c;我们将探讨如何使用Java和OkHttp库来下载并解析www.dianping.com上的商家信息。我们的目标是获取商家名称、价格、评分和评论&#xff0c;并将这些数据存储到CSV文件中。此外&#xff0c;我们将使用爬虫代理来绕过任何潜在的IP限制&#xff0c;并实…

Ollama教程——入门:开启本地大型语言模型开发之旅

Ollama教程——入门&#xff1a;开启本地大型语言模型开发之旅 引言安装ollamamacOSWindows预览版LinuxDocker ollama的库和工具ollama-pythonollama-js 快速开始运行模型访问模型库 自定义模型从GGUF导入模型自定义提示 CLI参考创建模型拉取模型删除模型复制模型多行输入多模态…