Milvus高维数据库建立自己的ai知识库,语义检索功能

一、项目背景与技术选型

核心目标
通过Milvus向量数据库实现AI知识库的高维向量存储与语义检索,结合MinIO对象存储管理原始数据,构建可扩展的AI知识管理系统。

技术栈

  • Milvus:高维向量数据库,负责向量数据的存储、索引与检索
  • MinIO:分布式对象存储,托管非结构化数据(如文章原文)
  • Docker:容器化部署,确保环境一致性
  • Java SDK:实现业务系统与Milvus的交互

二、语义知识库检索工作流程

  1. 数据预处理
    • 读取文件如word内容将内容给ai模型转化为768维向量
    • 将向量存入Milvus,源文件存入minio,文件url存入Milvus对应的向量
  2. 检索流程
    • 用户提问 →ai模型转化→ 生成查询向量
    • Milvus执行近似最近邻(ANN)搜索
    • 根据返回的语义最相似的文章的url从MinIO获取原文
  3. AI整合回答
    • 将检索到的Top-K知识片段与原始问题拼接
    • 语义检索直接展示url的minio的文件,知识库提问提取文件知识和问题投给ai

1.前置环境省略补充:

1.Linux操作系统部署Centos7:Linux操作系统的下载与安装(保姆级教程)_linux系统下载-CSDN博客

2.docker安装部署可以直接拉最新的:docker安装(完整详细版)-CSDN博客

2.这里展示博主当前网上找到的可用的国内镜像:

1.这里知识cat展示,你们修改可以使用vi或vim编辑(应该都知道这个是干嘛用的吧)

 cat /etc/docker/daemon.json 

2.vim的操作: vim /etc/docker/daemon.json → i →鼠标中键粘贴→esc→:wq(保存退出)。

{
  "registry-mirrors": [
                    "https://docker.sunzishaokao.com",
                    "https://docker.xuanyuan.me",
                   "https://docker.1ms.run",
                   "https://docker.1panel.live",
                   "https://hub.rat.dev",
                    "https://docker.wanpeng.top",
                   "https://doublezonline.cloud",
                    "https://docker.mrxn.net",
                    "https://docker.anyhub.us.kg",
                    "https://dislabaiot.xyz",
                    "https://docker.fxxk.dedyn.io",
                   "https://docker-mirror.aigc2d.com",
                   "https://ypfjyq04.mirror.aliyuncs.com",
                   "https://docker.m.daocloud.io",
                   "https://docker.zhai.cm",
                   "https://a.ussh.net",
                   "https://aicarbon.xyz",
                   "https://docker.yomansunter.com",
                   "https://666860.xyz",
                   "https://1ms.run",
                   "https://docker.mybacc.com",
                   "https://dytt.online",
                   "https://lispy.org",
                   "http://docker.xiaogenban1993.com"
                 ]
}

3. Docker Compose 部署前置环境

根据官方文档使用Docker Compose快速部署安装Milvus,这里补充安装过程
(1)下载 Docker Compose v2.23.0(兼容 Docker 26.x)

sudo curl -L "https://github.com/docker/compose/releases/download/v2.23.0/docker-compose-linux-x86_64" -o /usr/local/bin/docker-compose

补充:如果拉不下来这里提供Git地址和csdn的博客绑定文件【如果安装不下来,可以手动安装后传到指定目录】

git clone https://gitee.com/TheListKnight/dy-milvus.git

(2) 赋予执行权限

sudo chmod +x /usr/local/bin/docker-compose

(3)最后异步校验验证安装

docker-compose --version

输出应类似:

                        Docker Compose version v2.23.0

4.安装部署Milvus使用2.3.5

博主遇到的问题:避坑2.3.3!

        刚开始我使用的是2.3.3,不知道谁说的稳定版,maven依赖也使用了java-sdk2.3.3的连接Milvus,但是2.3.3的版本有问题,容器总是会自动关闭,goroutine阻塞和gRPC连接问题等,所以这里建议使用2.3.5问题已经解决。

1.下载Milvus 的docker-compose.yml文件这里提供官网的下载指令

wget https://github.com/milvus-io/milvus/releases/download/v2.3.5/milvus-standalone-docker-compose.yml -O docker-compose.yml

补充:博主这边是拉下来了,如果拉不下来这里提供git地址和绑定文件最顶上

git clone https://gitee.com/TheListKnight/dy-milvus.git

2.生成容器(成功后查看容器会有三个,是Milvus的核心不要管)

sudo docker compose up -d

3.主要连接使用的是这个:确保启动状态

5.提供Milvus可视化的界面工具

1.使用 Attu(社区版 Web UI)安装方式(注意ip改你自己的

docker run -d -p 8000:3000 -e MILVUS_URL=你的虚拟机ip:19530 --name attu zilliz/attu:v2.3.4

2.浏览器访问:

http://你的虚拟机ip:8000/

6.java连接Milvus增删改查使用

已经将连接方法写成了工具类,先测试类展示工具类中的方法,最后展示工具类。

1.依赖导入

    <!-- Milvus Java SDK -->
        <dependency>
            <groupId>io.milvus</groupId>
            <artifactId>milvus-sdk-java</artifactId>
            <version>2.3.3</version>
        </dependency>

调用工具类初始化:

    MilvusUtils milvusUtils = new MilvusUtils("虚拟机的ip地址"
            ,19530
            ,128
            ,10);

2.创建集合

    @Test
    void 创建集合(){
        //连接初始化
        milvusUtils.initMilvusClient();
        连接后创建officePro集合
        milvusUtils.createCollection("officePro");
    }

3.创建分区

    @Test
    void 创建分区(){
        milvusUtils.initMilvusClient();
        milvusUtils.createPartition("officePro","text");
    }

4.创建索引

    @Test
    void 创建索引(){
        milvusUtils.initMilvusClient();
        milvusUtils.createIndex("officePro");
    }

5.插入向量数据(向量为空会报错,报错正常因为这里我写的空的)

    @Test
    void 插入向量数据(){
        milvusUtils.initMilvusClient();
        List<Float> queryVector = null;
        milvusUtils.insertData("officePro"
                ,"text",queryVector
                ,"baidu.com"
                ,"测试数据"
                ,"string");
    }

7.搜索相似向量(向量为空会报错,报错正常因为这里我写的空的)

    @Test
    void 向量检索(){
        milvusUtils.initMilvusClient();
        List<Float> queryVector = null;
        milvusUtils.searchSimilarVectors("officePro","text",queryVector);
    }

8.删除集合

    @Test
    void 删除集合(){
        milvusUtils.initMilvusClient();
        milvusUtils.dropCollection("officePro");
    }

写好的工具类:MilvusUtils

package com.example.util;

import io.milvus.client.MilvusServiceClient;
import io.milvus.param.ConnectParam;
import io.milvus.param.R;
import io.milvus.param.collection.CreateCollectionParam;
import io.milvus.param.collection.DropCollectionParam;
import io.milvus.param.collection.LoadCollectionParam;
import io.milvus.param.partition.CreatePartitionParam;
import io.milvus.param.index.CreateIndexParam;
import io.milvus.param.dml.InsertParam;
import io.milvus.param.dml.SearchParam;
import io.milvus.grpc.DataType;
import io.milvus.grpc.SearchResults;
import io.milvus.param.IndexType;
import io.milvus.param.MetricType;
import io.milvus.param.collection.FieldType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

public class MilvusUtils {
    private static final Logger logger = LoggerFactory.getLogger(MilvusUtils.class);
    
    private final String host;
    private final int port;
    private final int vectorDim;
    private final int topK;
    private MilvusServiceClient milvusClient;
    
    /**
     * 构造函数
     * @param host Milvus服务器地址
     * @param port Milvus服务器端口
     * @param vectorDim 向量维度
     * @param topK 搜索时返回的最相似结果数量
     */
    public MilvusUtils(String host, int port, int vectorDim, int topK) {
        this.host = host;
        this.port = port;
        this.vectorDim = vectorDim;
        this.topK = topK;
    }
    
    /**
     * 初始化Milvus客户端连接
     * @return 是否连接成功
     */
    public boolean initMilvusClient() {
        try {
            ConnectParam connectParam = ConnectParam.newBuilder()
                .withHost(host)
                .withPort(port)
                .build();
            milvusClient = new MilvusServiceClient(connectParam);
            logger.info("Milvus客户端初始化完成,连接地址: {}:{}", host, port);
            return true;
        } catch (Exception e) {
            logger.error("初始化Milvus客户端失败: {}", e.getMessage());
            return false;
        }
    }

    /**
     * 创建集合
     * @param collectionName 集合名称
     * @return 是否创建成功
     */
    public boolean createCollection(String collectionName) {
        try {
            FieldType idField = FieldType.newBuilder()
                    .withName("id")
                    .withDataType(DataType.Int64)
                    .withPrimaryKey(true)
                    .withAutoID(true)
                    .build();

            FieldType vectorField = FieldType.newBuilder()
                    .withName("vector_field")
                    .withDataType(DataType.FloatVector)
                    .withDimension(vectorDim)
                    .build();
            
            FieldType fileUrlField = FieldType.newBuilder()
                    .withName("file_url")
                    .withDataType(DataType.VarChar)
                    .withMaxLength(500)
                    .build();
                    
            FieldType fileNameField = FieldType.newBuilder()
                    .withName("file_name")
                    .withDataType(DataType.VarChar)
                    .withMaxLength(255)
                    .build();
                    
            FieldType fileTypeField = FieldType.newBuilder()
                    .withName("file_type")
                    .withDataType(DataType.VarChar)
                    .withMaxLength(50)
                    .build();

            CreateCollectionParam createCollectionReq = CreateCollectionParam.newBuilder()
                    .withCollectionName(collectionName)
                    .withDescription("文档向量存储集合")
                    .addFieldType(idField)
                    .addFieldType(vectorField)
                    .addFieldType(fileUrlField)
                    .addFieldType(fileNameField)
                    .addFieldType(fileTypeField)
                    .build();

            milvusClient.createCollection(createCollectionReq);
            logger.info("创建集合成功: {}", collectionName);
            return true;
        } catch (Exception e) {
            logger.error("创建集合失败: {}", e.getMessage());
            return false;
        }
    }

    /**
     * 创建分区
     * @param collectionName 集合名称
     * @param partitionName 分区名称
     * @return 是否创建成功
     */
    public boolean createPartition(String collectionName, String partitionName) {
        try {
            CreatePartitionParam createPartitionReq = CreatePartitionParam.newBuilder()
                    .withCollectionName(collectionName)
                    .withPartitionName(partitionName)
                    .build();

            milvusClient.createPartition(createPartitionReq);
            logger.info("创建分区成功: {}", partitionName);
            return true;
        } catch (Exception e) {
            logger.error("创建分区失败: {}", e.getMessage());
            return false;
        }
    }

    /**
     * 创建索引
     * @param collectionName 集合名称
     * @return 是否创建成功
     */
    public boolean createIndex(String collectionName) {
        try {
            CreateIndexParam createIndexReq = CreateIndexParam.newBuilder()
                    .withCollectionName(collectionName)
                    .withFieldName("vector_field")
                    .withIndexType(IndexType.IVF_FLAT)
                    .withMetricType(MetricType.L2)
                    .withExtraParam("{\"nlist\":1024}")
                    .withSyncMode(true)
                    .build();
            
            milvusClient.createIndex(createIndexReq);
            logger.info("创建索引成功");
            return true;
        } catch (Exception e) {
            logger.error("创建索引失败: {}", e.getMessage());
            return false;
        }
    }

    /**
     * 插入向量数据
     * @param collectionName 集合名称
     * @param partitionName 分区名称
     * @param vector 向量数据
     * @param fileUrl 文件URL
     * @param fileName 文件名
     * @param fileType 文件类型
     * @return 是否插入成功
     */
    public boolean insertData(String collectionName, String partitionName, 
                            List<Float> vector, String fileUrl, 
                            String fileName, String fileType) {
        try {
            List<InsertParam.Field> fields = new ArrayList<>();
            fields.add(new InsertParam.Field("vector_field", Collections.singletonList(vector)));
            fields.add(new InsertParam.Field("file_url", Collections.singletonList(fileUrl)));
            fields.add(new InsertParam.Field("file_name", Collections.singletonList(fileName)));
            fields.add(new InsertParam.Field("file_type", Collections.singletonList(fileType)));
            
            InsertParam insertParam = InsertParam.newBuilder()
                    .withCollectionName(collectionName)
                    .withPartitionName(partitionName)
                    .withFields(fields)
                    .build();
            
            milvusClient.insert(insertParam);
            logger.info("插入数据成功");
            return true;
        } catch (Exception e) {
            logger.error("插入数据失败: {}", e.getMessage());
            return false;
        }
    }

    /**
     * 搜索相似向量
     * @param collectionName 集合名称
     * @param partitionName 分区名称
     * @param queryVector 查询向量
     * @return 搜索结果
     */
    public SearchResults searchSimilarVectors(String collectionName, String partitionName, List<Float> queryVector) {
        try {
            // 先加载集合
            LoadCollectionParam loadCollectionParam = LoadCollectionParam.newBuilder()
                    .withCollectionName(collectionName)
                    .build();
            milvusClient.loadCollection(loadCollectionParam);
            
            List<List<Float>> queryVectors = Collections.singletonList(queryVector);
            
            SearchParam searchParam = SearchParam.newBuilder()
                    .withCollectionName(collectionName)
                    .withPartitionNames(Collections.singletonList(partitionName))
                    .withMetricType(MetricType.L2)
                    .withVectors(queryVectors)
                    .withVectorFieldName("vector_field")
                    .withTopK(topK)
                    .withOutFields(Arrays.asList("file_url", "file_name", "file_type"))
                    .build();
            
            R<SearchResults> searchResultsResponse = milvusClient.search(searchParam);
            if (searchResultsResponse != null && searchResultsResponse.getData() != null) {
                logger.info("搜索成功完成");
                return searchResultsResponse.getData();
            }
        } catch (Exception e) {
            logger.error("搜索数据失败: {}", e.getMessage());
        }
        return null;
    }

    /**
     * 删除集合
     * @param collectionName 集合名称
     * @return 是否删除成功
     */
    public boolean dropCollection(String collectionName) {
        try {
            DropCollectionParam dropCollectionParam = DropCollectionParam.newBuilder()
                    .withCollectionName(collectionName)
                    .build();
            
            milvusClient.dropCollection(dropCollectionParam);
            logger.info("删除集合成功: {}", collectionName);
            return true;
        } catch (Exception e) {
            logger.error("删除集合失败: {}", e.getMessage());
            return false;
        }
    }
}

有任何问题可以评论

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值