找回密码
 立即注册
首页 业界区 安全 Markdown文件导入Milvus向量数据库完整指南 ...

Markdown文件导入Milvus向量数据库完整指南

乙荒 2025-11-24 13:25:04
概述

本文档详细说明了如何将Markdown文件上传、切片并存储到Milvus向量数据库的完整流程,包括所有关键代码节点和配置说明。
系统架构
  1. 用户上传MD文件
  2.     ↓
  3. DocumentController (接收请求)
  4.     ↓
  5. DocumentService (业务处理)
  6.     ↓
  7. TokenTextSplitter (文档切片)
  8.     ↓
  9. EmbeddingModel (向量化) ← DashScope API
  10.     ↓
  11. MilvusVectorStore (存储)
  12.     ↓
  13. Milvus数据库
复制代码
技术栈

组件版本说明Spring Boot3.4.3应用框架Spring AI1.0.2AI集成框架Milvus2.4.8向量数据库DashScopetext-embedding-v3阿里云Embedding服务核心配置

1. application.yml
  1. spring:
  2.   ai:
  3.     openai:
  4.       # DashScope API密钥
  5.       api-key: ${OPENAI_API_KEY:sk-your-api-key}
  6.       # 基础URL(不含/v1,会自动添加)
  7.       base-url: ${OPENAI_API_BASE:https://dashscope.aliyuncs.com/compatible-mode}
  8.       embedding:
  9.         enabled: true
  10.         options:
  11.           model: text-embedding-v3  # 使用v3模型
  12. milvus:
  13.   enabled: true
  14.   host: 10.0.0.15
  15.   port: 19530
复制代码
关键点:

  • base-url末尾不要包含/v1,OpenAiApi会自动添加
  • 使用text-embedding-v3模型,支持1024维度
2. pom.xml依赖
  1. <dependency>
  2.     <groupId>org.springframework.ai</groupId>
  3.     spring-ai-openai</artifactId>
  4.     <version>1.0.2</version>
  5. </dependency>
  6. <dependency>
  7.     <groupId>org.springframework.ai</groupId>
  8.     spring-ai-milvus-store</artifactId>
  9.     <version>1.0.2</version>
  10. </dependency>
  11. <dependency>
  12.     <groupId>io.milvus</groupId>
  13.     milvus-sdk-java</artifactId>
  14.     <version>2.4.8</version>
  15. </dependency>
复制代码
MilvusConfig配置类详解

配置类的作用

MilvusConfig是一个配置工厂类,在Spring Boot启动时自动执行,负责创建和配置所有需要的工具对象。
执行时机:
  1. Spring Boot启动
  2.     ↓
  3. 扫描@Configuration类
  4.     ↓
  5. 发现MilvusConfig
  6.     ↓
  7. 检查条件: milvus.enabled=true?
  8.     ↓ (是)
  9. 按顺序执行@Bean方法,创建对象
  10.     ↓
  11. 将创建的对象放入Spring容器
  12.     ↓
  13. 其他类可以通过@Autowired使用这些对象
复制代码
四个核心Bean及其依赖关系
  1. MilvusConfig (配置类)
  2.     │
  3.     ├─ ① milvusClient (Milvus数据库连接)
  4.     │   └─ 连接到10.0.0.15:19530
  5.     │
  6.     ├─ ② embeddingModel (文本向量化工具)
  7.     │   └─ 调用DashScope API将文本转为1024维向量
  8.     │
  9.     ├─ ③ vectorStore (向量存储管理器)
  10.     │   ├─ 依赖: milvusClient (用于存储数据)
  11.     │   └─ 依赖: embeddingModel (用于生成向量)
  12.     │
  13.     └─ ④ textSplitter (文档切片工具)
  14.         └─ 将长文档切分成300 token的小块
  15. DocumentServiceImpl (使用者)
  16.     ├─ 注入 vectorStore ← 来自MilvusConfig
  17.     └─ 注入 textSplitter ← 来自MilvusConfig
复制代码
代码实现流程

节点1: 接收上传请求

文件: DocumentController.java
  1. @PostMapping("/import")
  2. public ResponseEntity<Map<String, Object>> importMarkdownFile(
  3.         @RequestParam("file") MultipartFile file) {
  4.     try {
  5.         // 1. 验证文件
  6.         if (file.isEmpty()) {
  7.             throw new IllegalArgumentException("上传的文件为空");
  8.         }
  9.         
  10.         String fileName = file.getOriginalFilename();
  11.         log.info("正在导入Markdown文件: {}", fileName);
  12.         
  13.         // 2. 验证文件类型
  14.         if (fileName != null && !fileName.toLowerCase().endsWith(".md")) {
  15.             throw new IllegalArgumentException("只支持.md格式的Markdown文件");
  16.         }
  17.         
  18.         // 3. 读取文件内容
  19.         String content = new String(file.getBytes(), StandardCharsets.UTF_8);
  20.         
  21.         // 4. 调用服务层处理: 切片 → 向量化 → 存储
  22.         int chunksImported = documentService.importMarkdownContent(content, fileName);
  23.         
  24.         // 5. 返回成功响应
  25.         Map<String, Object> response = new HashMap<>();
  26.         response.put("success", true);
  27.         response.put("message", "Markdown文件导入成功");
  28.         response.put("chunksImported", chunksImported);
  29.         response.put("fileName", fileName);
  30.         
  31.         return ResponseEntity.ok(response);
  32.         
  33.     } catch (Exception e) {
  34.         log.error("导入Markdown文件出错", e);
  35.         
  36.         Map<String, Object> response = new HashMap<>();
  37.         response.put("success", false);
  38.         response.put("message", "导入失败: " + e.getMessage());
  39.         
  40.         return ResponseEntity.badRequest().body(response);
  41.     }
  42. }
复制代码
作用:

  • 接收前端上传的Markdown文件
  • 验证文件格式和内容
  • 读取文件内容并转换为UTF-8字符串
  • 调用服务层处理
  • 返回导入结果(包含成功导入的块数量)
节点2: Bean① - 创建Milvus数据库连接

文件: MilvusConfig.java
  1. @Bean
  2. @ConditionalOnProperty(name = "milvus.enabled", havingValue = "true")
  3. public MilvusServiceClient milvusClient() {
  4.     log.info("正在连接Milvus服务器: {}:{}", milvusHost, milvusPort);
  5.    
  6.     MilvusServiceClient client = new MilvusServiceClient(
  7.         ConnectParam.newBuilder()
  8.             .withHost(milvusHost)   // 10.0.0.15
  9.             .withPort(milvusPort)   // 19530
  10.             .build()
  11.     );
  12.    
  13.     log.info("Milvus客户端连接成功");
  14.     return client;
  15. }
复制代码
作用:

  • 创建Milvus数据库的连接客户端
  • 类比: 就像JDBC连接MySQL数据库
  • 连接到10.0.0.15:19530
何时使用:

  • vectorStore内部使用这个客户端来操作Milvus数据库
  • 执行插入、查询等数据库操作
实际调用:
  1. // vectorStore内部会这样使用:
  2. milvusClient.insert("zhi_yan", vector, metadata);  // 插入向量数据
复制代码
节点3: Bean② - 创建文本向量化工具

文件: MilvusConfig.java
  1. @Bean
  2. @ConditionalOnProperty(name = "milvus.enabled", havingValue = "true")
  3. public EmbeddingModel embeddingModel() {
  4.     log.info("正在创建OpenAI EmbeddingModel,Base URL: {}, 模型: {}",
  5.              openaiBaseUrl, embeddingModelName);
  6.    
  7.     // 步骤1: 配置DashScope API连接
  8.     OpenAiApi openAiApi = OpenAiApi.builder()
  9.             .baseUrl(openaiBaseUrl)  // https://dashscope.aliyuncs.com/compatible-mode
  10.             .apiKey(openaiApiKey)    // sk-b7cbae5635ff49cba56c45a66ba9dafa
  11.             .build();
  12.    
  13.     // 步骤2: 配置Embedding参数
  14.     OpenAiEmbeddingOptions options = OpenAiEmbeddingOptions.builder()
  15.             .model(embeddingModelName)  // text-embedding-v3
  16.             .dimensions(1024)            // 生成1024维向量
  17.             .build();
  18.    
  19.     // 步骤3: 创建EmbeddingModel
  20.     OpenAiEmbeddingModel model = new OpenAiEmbeddingModel(
  21.         openAiApi,           // API连接
  22.         MetadataMode.EMBED,  // 模式
  23.         options              // 配置参数
  24.     );
  25.    
  26.     log.info("OpenAI EmbeddingModel创建成功");
  27.     return model;
  28. }
复制代码
作用:

  • 创建文本向量化工具
  • 功能: 将文本转换为1024维的数字向量
  • 通过DashScope API调用阿里云的embedding服务
何时使用:

  • vectorStore内部使用这个工具将文本转换为向量
实际调用示例:
  1. // vectorStore内部会这样使用:
  2. String text = "这是一段文本";
  3. float[] vector = embeddingModel.embed(text);
  4. // 结果: [0.123, 0.456, ..., 0.789] (1024个浮点数)
复制代码
重要说明:

  • baseUrl不含/v1,OpenAiApi会自动拼接成/v1/embeddings
  • dimensions(1024)必须设置,text-embedding-v3支持的维度范围: [64, 128, 256, 512, 768, 1024]
节点4: Bean③ - 创建向量存储管理器

文件: MilvusConfig.java
  1. @Bean(name = "zyVectorStore")
  2. @ConditionalOnProperty(name = "milvus.enabled", havingValue = "true")
  3. public VectorStore zyVectorStore(
  4.         MilvusServiceClient milvusClient,    // Spring自动传入Bean①
  5.         EmbeddingModel embeddingModel) {     // Spring自动传入Bean②
  6.    
  7.     log.info("正在创建Milvus VectorStore,集合名称: zhi_yan");
  8.    
  9.     // 整合milvusClient和embeddingModel
  10.     MilvusVectorStore vectorStore = MilvusVectorStore.builder(
  11.             milvusClient,      // 用于连接Milvus数据库
  12.             embeddingModel)    // 用于文本向量化
  13.         .collectionName("zhi_yan")   // 指定集合名称
  14.         .databaseName("default")      // 数据库名
  15.         .initializeSchema(true)       // 自动创建集合(如果不存在)
  16.         .build();
  17.    
  18.     log.info("Milvus VectorStore创建成功");
  19.     return vectorStore;
  20. }
复制代码
作用:

  • 创建向量存储管理器,整合Milvus连接和Embedding工具
  • 自动创建zhi_yan集合(如果不存在)
  • 集合的embedding字段维度自动从embeddingModel.dimensions()获取(1024)
何时使用:

  • DocumentServiceImpl通过@Autowired注入使用
  • 提供add()方法来存储文档向量
实际使用:
  1. // 在DocumentServiceImpl中
  2. vectorStore.add(chunks);  
  3. // vectorStore.add()内部执行流程:
  4. for (Document chunk : chunks) {
  5.     // 1. 调用embeddingModel生成向量
  6.     float[] vector = embeddingModel.embed(chunk.getContent());
  7.    
  8.     // 2. 调用milvusClient存储到数据库
  9.     milvusClient.insert("zhi_yan", vector, chunk.getMetadata());
  10. }
复制代码
集合Schema:
  1. zhi_yan集合结构:
  2. ├── id (VARCHAR, 主键, 36字符)
  3. ├── embedding (FLOAT_VECTOR, dim=1024)
  4. ├── metadata (JSON, 存储文件名、类型等)
  5. └── content (VARCHAR, 存储文档内容)
复制代码
节点5: Bean④ - 创建文档切片工具

文件: MilvusConfig.java
  1. @Bean
  2. @ConditionalOnProperty(name = "milvus.enabled", havingValue = "true")
  3. public DocumentTransformer textSplitter() {
  4.     return new TokenTextSplitter(
  5.         300,   // 每块大小(tokens)
  6.         200,   // 块之间重叠(tokens)
  7.         5,     // 最小块大小
  8.         10000, // 最大块大小
  9.         true   // 保持分隔符
  10.     );
  11. }
复制代码
作用:

  • 创建文档切片工具
  • 将长文档切分成多个小块
  • 每块约300个token,块之间重叠200个token
何时使用:

  • DocumentServiceImpl通过@Autowired注入使用
  • 在存储前先切片,避免单个文档过长
实际使用:
  1. // 在DocumentServiceImpl中
  2. String longText = "很长的文档内容...";
  3. Document doc = new Document(longText);
  4. List<Document> chunks = textSplitter.apply(List.of(doc));
  5. // 结果: [chunk1(300 tokens), chunk2(300 tokens), chunk3(300 tokens), ...]
复制代码
切片示例:
  1. 原文档(1000 tokens)
  2.     ↓
  3. 切片1: tokens 0-300
  4. 切片2: tokens 100-400  (与切片1重叠100 tokens)
  5. 切片3: tokens 200-500  (与切片2重叠100 tokens)
  6. 切片4: tokens 300-600
  7. ...
复制代码
为什么要重叠?

  • 确保上下文连贯性
  • 避免重要信息被切断
  • 提高检索准确度
节点6: 业务处理 - 导入文档

文件: DocumentServiceImpl.java
  1. @Override
  2. public int importMarkdownContent(String content, String fileName) {
  3.     if (vectorStore == null || textSplitter == null) {
  4.         log.warn("VectorStore或TextSplitter未配置,无法导入文档");
  5.         throw new UnsupportedOperationException("向量存储功能未启用,请配置Milvus");
  6.     }
  7.     try {
  8.         log.info("开始导入Markdown内容,文件名: {}", fileName);
  9.         // 1. 创建Document对象,添加元数据
  10.         Map<String, Object> metadata = new HashMap<>();
  11.         metadata.put("source", fileName);
  12.         metadata.put("type", "markdown");
  13.         metadata.put("imported_at", System.currentTimeMillis());
  14.         Document document = new Document(content, metadata);
  15.         // 2. 文档切片 (TokenTextSplitter)
  16.         List<Document> chunks = textSplitter.apply(List.of(document));
  17.         log.info("文档已分割成 {} 个块", chunks.size());
  18.         // 3. 向量化并存储到Milvus
  19.         // vectorStore.add()内部会:
  20.         //   - 调用embeddingModel.embed()生成向量
  21.         //   - 将向量存储到Milvus的zhi_yan集合
  22.         vectorStore.add(chunks);
  23.         log.info("成功导入 {} 个文档块到Milvus", chunks.size());
  24.         return chunks.size();
  25.     } catch (Exception e) {
  26.         log.error("导入Markdown内容出错,文件名: {}", fileName, e);
  27.         throw new RuntimeException("导入Markdown内容失败", e);
  28.     }
  29. }
复制代码
处理流程:

  • 创建Document对象

    • 包装原始内容
    • 添加元数据(文件名、来源、时间等)

  • 文档切片

    • 调用TokenTextSplitter切分文档
    • 返回多个Document块

  • 向量化与存储

    • vectorStore.add(chunks)触发以下操作:

      • 对每个chunk调用embeddingModel.embed()生成向量
      • 向量通过DashScope API生成(1024维)
      • 将向量和内容存储到Milvus


完整数据流与调用链路

用户上传文件后的完整执行流程
  1. // ========== 阶段1: 接收上传 ==========
  2. 用户上传文件: POST /api/documents/import
  3.     ↓
  4. DocumentController.importMarkdownFile(file)
  5.     ├─ 验证文件格式(.md)
  6.     ├─ 读取文件内容(UTF-8)
  7.     └─ 调用服务层
  8.         ↓
  9. // ========== 阶段2: 业务处理 ==========
  10. DocumentServiceImpl.importMarkdownContent(content, fileName)
  11.     │
  12.     ├─ 步骤1: 创建Document对象
  13.     │   Document doc = new Document(content, metadata);
  14.     │
  15.     ├─ 步骤2: 文档切片 (使用Bean④ textSplitter)
  16.     │   List<Document> chunks = textSplitter.apply(List.of(doc));
  17.     │   // 原文档 → [chunk1, chunk2, chunk3, ...]
  18.     │
  19.     └─ 步骤3: 向量化并存储 (使用Bean③ vectorStore)
  20.         vectorStore.add(chunks);
  21.             ↓
  22. // ========== 阶段3: 向量化 (vectorStore内部) ==========
  23. for (Document chunk : chunks) {
  24.    
  25.     // 3.1 调用Bean② embeddingModel生成向量
  26.     float[] vector = embeddingModel.embed(chunk.getContent());
  27.         ↓
  28.         // embeddingModel内部执行:
  29.         HTTP POST https://dashscope.aliyuncs.com/compatible-mode/v1/embeddings
  30.         {
  31.             "model": "text-embedding-v3",
  32.             "input": "文档块内容",
  33.             "dimensions": 1024
  34.         }
  35.         ↓
  36.         响应: {
  37.             "data": [{
  38.                 "embedding": [0.123, 0.456, ..., 0.789]  // 1024个浮点数
  39.             }]
  40.         }
  41.    
  42.     // 3.2 调用Bean① milvusClient存储到数据库
  43.     milvusClient.insert("zhi_yan", {
  44.         id: UUID.randomUUID(),
  45.         embedding: vector,           // [1024维向量]
  46.         metadata: {
  47.             source: fileName,
  48.             type: "markdown",
  49.             imported_at: timestamp
  50.         },
  51.         content: chunk.getContent()  // 文档块文本
  52.     });
  53. }
  54.     ↓
  55. // ========== 阶段4: 存储到Milvus ==========
  56. Milvus数据库 zhi_yan集合
  57. ├─ 记录1: {id, embedding[1024], metadata, content}
  58. ├─ 记录2: {id, embedding[1024], metadata, content}
  59. ├─ 记录3: {id, embedding[1024], metadata, content}
  60. └─ ...
  61.     ↓
  62. // ========== 阶段5: 返回结果 ==========
  63. 返回给用户: {
  64.     "success": true,
  65.     "message": "Markdown文件导入成功",
  66.     "chunksImported": 4,
  67.     "fileName": "example.md"
  68. }
复制代码
各个Bean在流程中的作用

执行阶段使用的Bean作用启动时Bean① milvusClient连接Milvus数据库启动时Bean② embeddingModel配置DashScope API启动时Bean③ vectorStore整合①②,提供统一接口启动时Bean④ textSplitter创建切片工具运行时textSplitter切分文档运行时vectorStore协调向量化和存储运行时embeddingModel生成向量(通过vectorStore调用)运行时milvusClient存储数据(通过vectorStore调用)对象依赖关系
  1. 启动时创建(MilvusConfig):
  2.     Bean① milvusClient ────┐
  3.                            ├──→ Bean③ vectorStore ──→ 注入到DocumentServiceImpl
  4.     Bean② embeddingModel ──┘
  5.    
  6.     Bean④ textSplitter ────────────────────→ 注入到DocumentServiceImpl
  7. 运行时使用(DocumentServiceImpl):
  8.     textSplitter.apply() → 切片
  9.     vectorStore.add() → 内部调用embeddingModel和milvusClient
复制代码
关键问题与解决方案

问题1: 404错误

原因:

  • base-url配置为https://dashscope.aliyuncs.com/compatible-mode/v1
  • OpenAiApi自动添加/v1,导致请求URL变成/v1/v1/embeddings
解决方案:
  1. # 错误配置
  2. base-url: https://dashscope.aliyuncs.com/compatible-mode/v1  ❌
  3. # 正确配置
  4. base-url: https://dashscope.aliyuncs.com/compatible-mode  ✅
复制代码
问题2: 维度不匹配

错误信息:
  1. Incorrect dimension for field 'embedding':
  2. the no.0 vector's dimension: 1024 is not equal to field's dimension: 1536
复制代码
原因:

  • text-embedding-v3默认生成1024维向量
  • Milvus集合配置为1536维(OpenAI标准)
解决方案:
  1. // 在EmbeddingModel配置中显式指定维度
  2. OpenAiEmbeddingOptions options = OpenAiEmbeddingOptions.builder()
  3.     .model("text-embedding-v3")
  4.     .dimensions(1024)  // 明确设置为1024
  5.     .build();
复制代码
问题3: ApiKey类型错误

错误信息:
  1. 'ApiKey' is abstract; cannot be instantiated
复制代码
原因:

  • ApiKey是抽象类,不能直接new ApiKey()
解决方案:
  1. // 使用builder方式,直接传String
  2. OpenAiApi openAiApi = OpenAiApi.builder()
  3.     .baseUrl(openaiBaseUrl)
  4.     .apiKey(openaiApiKey)  // 直接传String,不需要包装
  5.     .build();
复制代码
验证与测试

1. 启动应用

查看日志确认配置成功:
  1. 正在连接Milvus服务器: 10.0.0.15:19530
  2. Milvus客户端连接成功
  3. 正在创建OpenAI EmbeddingModel,Base URL: https://dashscope.aliyuncs.com/compatible-mode, 模型: text-embedding-v3
  4. OpenAI EmbeddingModel创建成功
  5. 正在创建Milvus VectorStore,集合名称: zhi_yan
  6. Milvus VectorStore创建成功
复制代码
2. 测试导入

使用Postman或curl测试:
  1. curl -X POST http://localhost:8084/api/documents/import \
  2.   -F "file=@test.md"
复制代码
成功日志:
  1. 正在导入Markdown文件: test.md
  2. 开始导入Markdown内容,文件名: test.md
  3. 文档已分割成 4 个块
  4. 成功导入 4 个文档块到向量数据库
复制代码
3. 验证Milvus
  1. from pymilvus import connections, Collection
  2. connections.connect(host="10.0.0.15", port=19530)
  3. collection = Collection("zhi_yan")
  4. # 查看集合信息
  5. print(f"集合数量: {collection.num_entities}")
  6. print(f"Schema: {collection.schema}")
复制代码
性能优化建议

1. 批量处理
  1. // 批量添加,减少网络开销
  2. List<Document> allChunks = new ArrayList<>();
  3. for (String file : files) {
  4.     allChunks.addAll(processFile(file));
  5. }
  6. vectorStore.add(allChunks);  // 一次性添加
复制代码
2. 异步处理
  1. @Async
  2. public CompletableFuture<Void> importMarkdownContentAsync(
  3.         String fileName, String content) {
  4.     importMarkdownContent(fileName, content);
  5.     return CompletableFuture.completedFuture(null);
  6. }
复制代码
3. 缓存Embedding

对于重复内容,可以缓存embedding结果避免重复调用API。
故障排查

日志级别配置
  1. logging:
  2.   level:
  3.     com.example.assistant: DEBUG
  4.     org.springframework.ai: DEBUG
  5.     io.milvus: DEBUG
复制代码
常见错误

错误原因解决方案404 Not Foundbase-url包含/v1移除base-url末尾的/v1维度不匹配embedding维度与集合不符设置dimensions(1024)连接超时Milvus服务不可达检查网络和Milvus状态API Key无效DashScope密钥错误验证API Key有效性总结

核心要点


  • 配置正确的base-url: 不含/v1后缀
  • 明确指定维度: dimensions(1024)
  • 自动创建集合: initializeSchema(true)
  • 合理的切片策略: 300 tokens/块,200 tokens重叠
数据流向
  1. MD文件 → 切片 → 向量化(DashScope) → 存储(Milvus)
复制代码
关键代码节点


  • DocumentController: 接收上传
  • MilvusConfig.embeddingModel(): 配置向量化模型
  • MilvusConfig.zyVectorStore(): 配置向量存储
  • MilvusConfig.textSplitter(): 配置文档切片
  • DocumentServiceImpl.importMarkdownContent(): 业务处理
附录

text-embedding-v3模型说明

属性值支持维度64, 128, 256, 512, 768, 1024默认维度1024最大输入8192 tokens输出类型float32向量Milvus索引配置
  1. index_params = {
  2.     "metric_type": "COSINE",    # 余弦相似度
  3.     "index_type": "IVF_FLAT",   # 索引类型
  4.     "params": {"nlist": 128}    # 聚类中心数
  5. }
复制代码
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

相关推荐

您需要登录后才可以回帖 登录 | 立即注册