SpringBoot整合Milvus的实现

 更新时间:2023年07月04日 10:40:38   作者:杨慕晚  
本文主要介绍了SpringBoot整合Milvus的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

什么是Milvus?

Milvus,一个开源的高性能向量数据库,它在各种应用场景中展现出强大的性能和灵活性。
在许多现代应用中,处理和分析大规模向量数据变得越来越重要。例如,在图像和视频搜索、推荐系统、自然语言处理和生物信息学等领域,向量数据被广泛应用。

项目背景

在公司推荐系统中,我们需要根据用户的历史行为和兴趣,为其推荐相关的内容。于是将用户和内容表示为向量,并使用 Milvus 进行相似度匹配。通过将用户向量和内容向量存储在 Milvus 中,并利用其高效的相似度查询功能,我们可以快速找到与用户兴趣最匹配的内容,并进行个性化推荐。

向量的生成由spark任务生成数据并写入,本文只写SpringBoot集成Milvus实现数据查询部分,面向C端,性能已测

Maven依赖引入

开始使用的是1.x版本,后来由于2.x新增了过滤筛选功能,升级了版本为2.2.3,1版本和2版本查询还是有一些区别,建议采用2版本

<dependency>
    <groupId>io.milvus</groupId>
    <artifactId>milvus-sdk-java</artifactId>
    <version>2.2.3</version>
</dependency>

自动配置

@Configuration
public class MilvusConfiguration {
    /**
     *  milvus ip addr
     */
    @Value("${milvus.config.ipAddr}")
    private String ipAddr;
    /**
     * milvus   port
     */
    @Value("${milvus.config.port}")
    private Integer  port;
    @Bean
    @Scope("singleton")
    public MilvusServiceClient getMilvusClient() {
        return getMilvusFactory().getMilvusClient();
    }
    @Bean(initMethod = "init", destroyMethod = "close")
    public MilvusRestClientFactory getMilvusFactory() {
        return  MilvusRestClientFactory.build(ipAddr, port);
    }
}

milvus Rest client 封装

public class MilvusRestClientFactory {
    private static String  IP_ADDR;
    private static Integer PORT ;
    private MilvusServiceClient milvusServiceClient;
    private ConnectParam.Builder  connectParamBuilder;
    private static MilvusRestClientFactory milvusRestClientFactory = new MilvusRestClientFactory();
    private MilvusRestClientFactory(){
    }
    public static MilvusRestClientFactory build(String ipAddr, Integer  port) {
        IP_ADDR = ipAddr;
        PORT = port;
        return milvusRestClientFactory;
    }
    private ConnectParam.Builder connectParamBuilder(String host, int port) {
        return  ConnectParam.newBuilder().withHost(host).withPort(port);
    }
    public void init() {
        connectParamBuilder =  connectParamBuilder(IP_ADDR,PORT);
        ConnectParam connectParam = connectParamBuilder.build();
        milvusServiceClient =new MilvusServiceClient(connectParam);
    }
    public MilvusServiceClient getMilvusClient() {
        return milvusServiceClient;
    }
    public void close() {
        if (milvusServiceClient != null) {
            try {
                milvusServiceClient.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}

查询

写入数据不同,获取结果不同,我这里最后获取的是Long类型的数据集合,仅供参考

同步搜索milvus

/**
 * 同步搜索milvus
 * @param collectionName 表名
 * @param vectors 查询向量
 * @param topK 最相似的向量个数
 * @return
 */
public List<Long> search(String collectionName, List<List<Float>> vectors, Integer topK) {
    Assert.notNull(collectionName, "collectionName  is null");
    Assert.notNull(vectors, "vectors is null");
    Assert.notEmpty(vectors, "vectors is empty");
    Assert.notNull(topK, "topK is null");
    int nprobeVectorSize = vectors.get(0).size();
    String paramsInJson = "{"nprobe": " + nprobeVectorSize + "}";
    SearchParam searchParam =
            SearchParam.newBuilder().withCollectionName(collectionName)
                    .withParams(paramsInJson)
                    .withMetricType(MetricType.IP)
                    .withVectors(vectors)
                    .withVectorFieldName("embedding")
                    .withTopK(topK)
                    .build();
    R<SearchResults> searchResultsR = milvusServiceClient.search(searchParam);
    SearchResults searchResultsRData = searchResultsR.getData();
    List<Long> topksList = searchResultsRData.getResults().getIds().getIntId().getDataList();
    return topksList;
}

同步搜索milvus,增加过滤条件搜索

/**
 * 同步搜索milvus,增加过滤条件搜索
 *
 * @param collectionName 表名
 * @param vectors 查询向量
 * @param topK 最相似的向量个数
 * @param exp 过滤条件:status=1
 * @return
 */
public List<Long> search(String collectionName, List<List<Float>> vectors, Integer topK, String exp) {
    Assert.notNull(collectionName, "collectionName  is null");
    Assert.notNull(vectors, "vectors is null");
    Assert.notEmpty(vectors, "vectors is empty");
    Assert.notNull(topK, "topK is null");
    Assert.notNull(exp, "exp is null");
    int nprobeVectorSize = vectors.get(0).size();
    String paramsInJson = "{"nprobe": " + nprobeVectorSize + "}";
    SearchParam searchParam =
            SearchParam.newBuilder().withCollectionName(collectionName)
                    .withParams(paramsInJson)
                    .withMetricType(MetricType.IP)
                    .withVectors(vectors)
                    .withExpr(exp)
                    .withVectorFieldName("embedding")
                    .withTopK(topK)
                    .build();
    R<SearchResults> searchResultsR = milvusServiceClient.search(searchParam);
    SearchResults searchResultsRData = searchResultsR.getData();
    List<Long> topksList = searchResultsRData.getResults().getIds().getIntId().getDataList();
    return topksList;
}

异步搜索milvus:针对实时结果要求不高的场景

/**
 * 异步搜索milvus
 *
 * @param collectionName 表名
 * @param vectors 查询向量
 * @param partitionList 最相似的向量个数
 * @param topK
 * @return
 */
public List<Long> searchAsync(String collectionName, List<List<Float>> vectors,
                              List<String> partitionList, Integer topK) throws ExecutionException, InterruptedException {
    Assert.notNull(collectionName, "collectionName  is null");
    Assert.notNull(vectors, "vectors is null");
    Assert.notEmpty(vectors, "vectors is empty");
    Assert.notNull(partitionList, "partitionList is null");
    Assert.notEmpty(partitionList, "partitionList is empty");
    Assert.notNull(topK, "topK is null");
    int nprobeVectorSize = vectors.get(0).size();
    String paramsInJson = "{"nprobe": " + nprobeVectorSize + "}";
    SearchParam searchParam =
            SearchParam.newBuilder().withCollectionName(collectionName)
                    .withParams(paramsInJson)
                    .withVectors(vectors)
                    .withTopK(topK)
                    .withPartitionNames(partitionList)
                    .build();
    ListenableFuture<R<SearchResults>> listenableFuture = milvusServiceClient.searchAsync(searchParam);
    List<Long> resultIdsList = listenableFuture.get().getData().getResults().getTopksList();
    return resultIdsList;
}

获取分区集合

/**
 * 获取分区集合
 * @param collectionName 表名
 * @return
 */
public List<String> getPartitionsList(String collectionName) {
    Assert.notNull(collectionName, "collectionName  is null");
    ShowPartitionsParam searchParam = ShowPartitionsParam.newBuilder().withCollectionName(collectionName).build();
    List<ByteString> byteStrings = milvusServiceClient.showPartitions(searchParam).getData().getPartitionNamesList().asByteStringList();
    List<String> partitionList = Lists.newLinkedList();
    byteStrings.forEach(s -> {
        partitionList.add(s.toStringUtf8());
    });
    return partitionList;
}

yml配置数据

milvus:
  config:
    ipAddr: xxx.xxx.xxx.xxx
    port: 19531

到此这篇关于SpringBoot整合Milvus的实现的文章就介绍到这了,更多相关SpringBoot整合Milvus内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • java获取两个List集合的交集代码示例

    java获取两个List集合的交集代码示例

    这篇文章主要给大家介绍了关于java获取两个List集合交集的相关资料,我们可以使用Stream操作来对集合进行一系列的操作,其中包括求交集,文中通过代码介绍的非常详细,需要的朋友可以参考下
    2023-11-11
  • 一文详解SpringBoot如何切换Redis的DB

    一文详解SpringBoot如何切换Redis的DB

    这篇文章主要为大家详细介绍了Spring Redis动态切换数据库的核心机制,并指出仅调用setDatabase()和resetConnection()无法真正切换数据库的根本原因,感兴趣的小伙伴可以了解下
    2025-12-12
  • springboot使用过滤器详解

    springboot使用过滤器详解

    本文主要介绍了过滤器的基本概念,过滤器的生命周期,以及如何通过注解方式和非注解方式实现过滤器,过滤器是客户端与服务器资源文件之间的一道过滤网,能够帮助我们过滤不符合要求的请求,通常用作Session校验
    2024-10-10
  • java模拟TCP通信实现客户端上传文件到服务器端

    java模拟TCP通信实现客户端上传文件到服务器端

    这篇文章主要为大家详细介绍了java模拟TCP通信实现客户端上传文件到服务器端,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2019-10-10
  • MyBatis使用CASE WHEN进行批量更新的高效写法

    MyBatis使用CASE WHEN进行批量更新的高效写法

    当我们使用mybatis的时候,可能经常会碰到一批数据的批量更新问题,因为如果一条数据一更新,那每一条数据就需要涉及到一次数据库的操作,包括网络IO以及磁盘IO,可想而知,这个效率是非常低下的,那么今天我们就来总结一下,如何使用mybatis做批量更新,需要的朋友可以参考下
    2025-10-10
  • Java使用ScriptEngine动态执行代码(附Java几种动态执行代码比较)

    Java使用ScriptEngine动态执行代码(附Java几种动态执行代码比较)

    这篇文章主要介绍了Java使用ScriptEngine动态执行代码,并且分享Java几种动态执行代码比较,需要的朋友可以参考下
    2021-04-04
  • Flink部署集群整体架构源码分析

    Flink部署集群整体架构源码分析

    这篇文章主要为大家介绍了Flink部署集群及整体架构示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-12-12
  • Javaweb动态开发最重要的Servlet详解

    Javaweb动态开发最重要的Servlet详解

    动态web的核心是Servlet,由tomcat解析并执行,本质是Java中的一个类(面向对象)这个类的功能十分强大几乎可以完成全部功能,在Java规范中只有Servlet实现类实例化的对象才能被浏览器访问,所以掌握Servlet具有重要意义
    2022-08-08
  • java二分查找插入法

    java二分查找插入法

    当你需要构建一个大的有序队列,用插入发太慢了,可以先用二分查找法,找到在队列要插入的位置,把数后移一下,然后放进去。比较效率,下面是java使用示例,需要的朋友可以参考下
    2014-03-03
  • 从零开始手写JDBC连接数据库的详细指南

    从零开始手写JDBC连接数据库的详细指南

    在 Java 开发中,数据库是存储和管理数据的核心组件,JDBC是 Java 程序与数据库交互的标准 API,本文将带大家手写一个完整的 JDBC 连接数据库的示例,希望对大家有所帮助
    2025-07-07

最新评论