Skip to content

wxwsir/MilvusVectorStoreV2

Repository files navigation

MilvusVectorStoreV2

1. 概述

MilvusVectorStoreV2 是基于 MilvusClientV2 的对 VectorStore 的实现,其提供了基于 Milvus 的向量存储实现,支持密集向量、稀疏向量和多向量混合检索(多路召回+RFF),适用于大语言模型应用中的语义搜索、知识检索等场景。主要包含向量存储、集合管理、RAG检索增强等核心功能。

2. 相关依赖

        <dependency>
            <groupId>org.springframework.ai</groupId>
            <artifactId>spring-ai-starter-model-openai</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.ai</groupId>
            <artifactId>spring-ai-tika-document-reader</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.ai</groupId>
            <artifactId>spring-ai-pdf-document-reader</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.ai</groupId>
            <artifactId>spring-ai-milvus-store</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.ai</groupId>
            <artifactId>spring-ai-vector-store</artifactId>
        </dependency>

3. 核心组件详解

3.1 MilvusVectorStoreV2

MilvusVectorStoreV2 是基于 MilvusClientV2 实现的向量存储组件,实现了 Spring AI 的 VectorStore 接口,支持文档的增删改查和多种检索方式。

主要功能:

  • 文档向量化存储
  • 文档删除(支持 ID 和过滤条件删除)
  • 密集向量的相似度搜索(similaritySearch 方法)
  • 全文检索(fullTextSearch 方法)
  • 多路召回检索(multiChannelRecallSearch 方法)

核心字段:

  • dense_collectionName:密集向量集合名称
  • sparse_collectionName:稀疏向量集合名称
  • multi_collectionName:多向量集合名称
  • vectorFieldName:密集向量字段名称
  • sparseVectorFieldName:稀疏向量字段名称
  • partitionName:分区名称

3.2 CollectionManager

CollectionManager 负责 Milvus 集合和索引的创建与管理,支持三种类型的集合:

集合类型:

  • 向量集合(VECTOR):存储密集向量,用于语义相似度检索
  • 文本集合(TEXT):支持中文分词和 BM25 检索,适用于全文搜索
  • 多向量集合(MULTI_VECTOR):同时支持密集向量和稀疏向量检索

索引配置:

  • 向量索引:使用 HNSW 算法,余弦相似度度量
  • 文本索引:使用 AUTOINDEX,BM25 相似度度量
  • 多向量索引:同时配置密集向量和稀疏向量索引

3.3 RagAnswerMilvusAdvisor

RagAnswerMilvusAdvisor 实现了 Spring AI 的 BaseAdvisor 接口,用于为聊天客户端提供 RAG(检索增强生成)能力。

工作流程:

  1. before 阶段:根据用户问题从 Milvus 检索相关文档,将文档内容作为上下文附加到用户问题中
  2. after 阶段:将检索到的文档信息添加到响应的元数据中,便于溯源

3.4 MilvusConfig

MilvusConfig 负责 Milvus 客户端和向量存储的配置与初始化,主要包括:

  • Milvus 客户端连接池配置
  • MilvusVectorStoreV2 Bean 定义
  • 注入 OpenAI 嵌入模型和批处理策略

4. 配置说明

4.1 应用配置(application.yml)

# Milvus 配置milvus:
  url: http://host:port             # Milvus 服务地址
  token: root:Milvus                # 认证 token
  config:
    maxIdlePerKey: 10               # 每个 key 的最大空闲客户端数
    maxTotalPerKey: 20              # 每个 key 的最大客户端总数
    maxTotal: 100                   # 所有 key 的最大客户端总数
    maxBlockWaitDuration: 5         # 获取客户端的最大等待时间(秒)
    minEvictableIdleDuration: 10    # 最小可驱逐空闲时间(秒)

4.2 组件配置

MilvusVectorStoreV2 支持以下配置参数:

参数名 类型 默认值 说明
dense_collectionName String text_dense_collection 密集向量集合名称
sparse_collectionName String text_sparse_collection 稀疏向量集合名称
multi_collectionName String multi_collection_01 多向量集合名称
vectorFieldName String text_dense 密集向量字段名
sparseVectorFieldName String text_sparse 稀疏向量字段名
partitionName String _default 分区名称

5. 使用示例

5.1 创建向量存储实例

@Autowired
private MilvusVectorStoreV2 milvusVectorStoreV2;

5.2 添加文档

        // 解析文档
        TextReader textReader = new TextReader(txtResource);
        textReader.getCustomMetadata().put("title", "test.txt");
        List<Document> documentList = textReader.get();

        // 分块
        TokenTextSplitter splitter = new TokenTextSplitter(
                50, // defaultChunkSize 目标Token数,即每个块的Token数
                20,  // minChunkSizeChars 最小字符数,当某块因分隔符导致不足chunkSize时,会至少保留minChunkSize的内容
                1, // minChunkLengthToEmbed 最小有效分块长度,避免过滤短句
                100, // maxNumChunks 最大分块数
                false // keepSeparator 是否保留分隔符(如换行符)在文本块中,中文无需保留
        );
        List<Document> documents = splitter.split(documentList);
        String ragTag = "milvus";
        documents.forEach(document -> document.getMetadata().put("knowledge", ragTag));

        log.info("分块后文档数: {}", documents.size());
        milvusVectorStoreV2.setDense_collectionName("text_dense_collection");
        // 添加文档到向量数据库
        milvusVectorStoreV2.accept(documents);
        log.info("insert doc");

5.3 执行相似度搜索

SearchRequest request = SearchRequest.builder()
     .query("馨可宁单针多少元")
     .topK(5)
     .filterExpression(filterExpression)  // 过滤条件
     .build();
milvusVectorStoreV2.setDense_collectionName("text_dense_collection");
milvusVectorStoreV2.similaritySearch(request);

5.4 执行全文检索

SearchRequest request = SearchRequest.builder()
     .query("2025年上半年工业生产总值是多少")
     .topK(5)
     .filterExpression(filterExpression)  // 过滤条件
     .build();
milvusVectorStoreV2.setSparse_collectionName("text_sparse_collection");
milvusVectorStoreV2.fullTextSearch(request);

5.5 执行多路召回检索

SearchRequest request = SearchRequest.builder()
     .query("《民法典》中第352页第一条讲述了什么内容")
     .topK(2)
     .filterExpression(filterExpression)  // 过滤条件
     .build();
String collectionName = "multi_collection_01";
milvusVectorStoreV2.setMulti_collectionName(collectionName);

5.6 使用 RAG 增强

OpenAiApi openAiApi = OpenAiApi.builder()
     .baseUrl("https://api.chatanywhere.tech")
     .apiKey("sk-PTovWzp1oSk8fbLjn4evx0ii1M0SM23xGEY4oLvlyADHGvPj")
     .completionsPath("v1/chat/completions")
     .embeddingsPath("v1/embeddings")
     .build();

chatModel = OpenAiChatModel.builder()
     .openAiApi(openAiApi)
     .defaultOptions(OpenAiChatOptions.builder()
          .model("gpt-4o")
          .build())
     .build();
chatClient = ChatClient.builder(chatModel)
     .defaultAdvisors(
          PromptChatMemoryAdvisor.builder(
               MessageWindowChatMemory.builder()
                    .maxMessages(100)
                    .build()
          ).build())
     .build();

// 用户输入
String message = "2025 年免疫类流感疫苗共有几款疫苗中标 ?";

// 指定文档搜索
SearchRequest request = SearchRequest.builder()
     .query(message)
     .topK(2)
     .build();

String collectionName = "multi_collection_01";

// 执行混合检索
milvusVectorStoreV2.setMulti_collectionName(collectionName);
List<Document> documents = milvusVectorStoreV2.multiChannelRecallSearch(
     request,
     message // 混合检索中的全文搜索会使用分析器将输入文本标记为可搜索的单个术语,即关键词
);

// 构造上下文
String documentCollectors = documents.stream().map(Document::getText).collect(Collectors.joining());
Message ragMessage = new SystemPromptTemplate(Constants.RAG_PROMPT).createMessage(Map.of("documents", documentCollectors));
List<Message> messages = new ArrayList<>();
messages.add(new UserMessage(message));
messages.add(ragMessage);

// 调用 LLM
String endContent = chatClient.prompt(new Prompt(
     messages,
     OpenAiChatOptions.builder()
          .model("gpt-4o")
          .build()
)).call().content();

log.info("RAG answer: {}", endContent);

6. 创建集合与索引

通过 CollectionManager 创建 Milvus 集合和索引:

@Autowired
private CollectionManager collectionManager;

// 创建密集向量 collection
String collectionType = Constants.COLLECTION_TYPE.VECTOR.getCode();
String collectionName = "text_dense_collection";
collectionManager.createCollection(collectionType, collectionName);

// 创建稀疏向量 collection
String collectionType = Constants.COLLECTION_TYPE.TEXT.getCode();
String collectionName = "text_sparse_collection";
collectionManager.createCollection(collectionType, collectionName);

// 创建多向量 collection
String collectionType = Constants.COLLECTION_TYPE.MULTI_VECTOR.getCode();
String collectionName = "multi_collection_01";
collectionManager.createCollection(collectionType, collectionName);

7. 注意事项

  1. 连接管理:项目使用 Milvus 客户端连接池,确保合理配置连接参数避免资源耗尽

  2. 索引优化:根据实际数据量和查询需求调整索引参数,如 HNSW 的 M 和 efConstruction 值

  3. 性能考虑:对于大规模数据,建议使用分区和过滤条件提高检索效率

  4. 向量维度:当前实现默认使用维度为 1024 的向量,如有需要请调整

About

MilvusVectorStoreV2, based on Milvus and VectorStore(Spring AI)

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages