embeddingModel操作milvus数据库集合

案例:

不是"创建集合的那一瞬间",而是"第一次使用时"

java 复制代码
// ========== 应用启动时(MilvusConfig执行) ==========

// 步骤1: 创建milvusClient
@Bean
public MilvusServiceClient milvusClient() {
    return new MilvusServiceClient(...);  // ✓ 只是连接数据库
}

// 步骤2: 创建embeddingModel
@Bean
public EmbeddingModel embeddingModel() {
    return new OpenAiEmbeddingModel(...);  // ✓ 只是创建工具对象
}

// 步骤3: 创建vectorStore
@Bean
public VectorStore zyVectorStore(
        MilvusServiceClient milvusClient,
        EmbeddingModel embeddingModel) {
    
    MilvusVectorStore vectorStore = MilvusVectorStore.builder(
            milvusClient,
            embeddingModel)
        .collectionName("zhi_yan")
        .initializeSchema(true)  // ← 注意!这里只是设置参数
        .build();
    
    // ⚠️ 到这里为止,集合还没有创建!
    // 只是创建了vectorStore对象,保存了配置
    
    return vectorStore;
}

// ========== 启动完成,集合仍然不存在 ==========

集合真正创建的时机

第一次调用vectorStore.add()

java 复制代码
// ========== 用户上传文件后 ==========

DocumentServiceImpl.importMarkdownContent() {
    
    // 1. 切片
    List<Document> chunks = textSplitter.apply(List.of(doc));
    
    // 2. 调用vectorStore.add() ← 这里才真正创建集合!
    vectorStore.add(chunks);
}

// ========== vectorStore.add()内部执行流程 ==========

class MilvusVectorStore {
    
    public void add(List<Document> documents) {
        
        // 步骤1: 检查集合是否存在
        boolean exists = checkCollectionExists("zhi_yan");
        
        if (!exists && initializeSchema) {
            // 步骤2: 集合不存在,需要创建
            createCollection();  // ← 这里才真正创建!
        }
        
        // 步骤3: 插入数据
        insertDocuments(documents);
    }
    
    private void createCollection() {
        // ========== 这里才使用embeddingModel! ==========
        
        // 1. 生成一个测试向量,获取维度
        log.info("正在获取向量维度...");
        List<Double> testVector = embeddingModel.embed("test");
        int dimension = testVector.size();  // ← 得到1024
        
        log.info("检测到向量维度: {}", dimension);
        
        // 2. 创建Schema
        List<FieldType> fields = new ArrayList<>();
        
        // 主键字段
        fields.add(FieldType.newBuilder()
            .withName("id")
            .withDataType(DataType.VarChar)
            .withMaxLength(36)
            .withPrimaryKey(true)
            .build());
        
        // 向量字段 ← 使用检测到的维度
        fields.add(FieldType.newBuilder()
            .withName("embedding")
            .withDataType(DataType.FloatVector)
            .withDimension(dimension)  // ← 1024
            .build());
        
        // 其他字段...
        
        // 3. 创建集合
        CollectionSchemaParam schema = CollectionSchemaParam.newBuilder()
            .withFieldTypes(fields)
            .build();
        
        CreateCollectionParam param = CreateCollectionParam.newBuilder()
            .withCollectionName("zhi_yan")
            .withSchema(schema)
            .build();
        
        milvusClient.createCollection(param);
        
        log.info("集合创建成功! embedding字段维度: {}", dimension);
    }
}

完整时间线

复制代码
时间点1: 应用启动
    ├─ 创建milvusClient ✓
    ├─ 创建embeddingModel ✓ (配置为1024维)
    ├─ 创建vectorStore ✓ (保存配置)
    └─ 集合状态: ❌ 不存在

时间点2: 应用启动完成
    └─ 集合状态: ❌ 仍然不存在

时间点3: 用户上传第一个文件
    ├─ DocumentController接收文件
    ├─ DocumentServiceImpl.importMarkdownContent()
    ├─ textSplitter.apply() 切片
    └─ vectorStore.add(chunks) ← 触发!
        ↓
        
时间点4: vectorStore.add()内部
    ├─ 检查集合是否存在 → 不存在
    ├─ 调用embeddingModel.embed("test") → 得到1024维向量
    ├─ 创建集合,embedding字段设为1024维 ✓
    └─ 集合状态: ✓ 创建成功,1024维

时间点5: 后续上传文件
    ├─ vectorStore.add(chunks)
    ├─ 检查集合是否存在 → 已存在
    ├─ 跳过创建步骤
    └─ 直接插入数据

验证:查看Spring AI源码逻辑

java 复制代码
// Spring AI的MilvusVectorStore实际实现(简化版)

public class MilvusVectorStore implements VectorStore {
    
    private final MilvusServiceClient milvusClient;
    private final EmbeddingModel embeddingModel;
    private final String collectionName;
    private final boolean initializeSchema;
    
    @Override
    public void add(List<Document> documents) {
        
        // 1. 确保集合存在
        if (initializeSchema) {
            createCollectionIfNotExists();  // ← 关键方法
        }
        
        // 2. 向量化并插入
        for (Document doc : documents) {
            List<Double> vector = embeddingModel.embed(doc.getContent());
            insert(doc.getId(), vector, doc.getContent(), doc.getMetadata());
        }
    }
    
    private void createCollectionIfNotExists() {
        // 检查集合是否存在
        R<Boolean> response = milvusClient.hasCollection(
            HasCollectionParam.newBuilder()
                .withCollectionName(collectionName)
                .build()
        );
        
        if (!response.getData()) {
            // 集合不存在,创建它
            log.info("集合 {} 不存在,正在创建...", collectionName);
            
            // ========== 这里使用embeddingModel获取维度 ==========
            List<Double> dimensionVector = embeddingModel.embed("dimension test");
            int dimension = dimensionVector.size();
            
            log.info("从EmbeddingModel检测到向量维度: {}", dimension);
            
            // 创建Schema并创建集合
            createCollectionWithDimension(dimension);
        } else {
            log.info("集合 {} 已存在,跳过创建", collectionName);
        }
    }
}

为什么这样设计?

1. 延迟初始化(Lazy Initialization)

复制代码
好处:
✓ 启动更快 - 不需要在启动时创建集合
✓ 灵活性 - 可以先启动应用,后配置Milvus
✓ 自动适配 - 自动从embeddingModel获取维度,不需要手动配置

2. 自动维度检测

java 复制代码
// 你不需要这样写:
MilvusVectorStore.builder(...)
    .dimension(1024)  // ❌ 不需要手动指定
    .build();

// 而是自动检测:
MilvusVectorStore.builder(...)
    .initializeSchema(true)  // ✓ 自动从embeddingModel获取
    .build();

// 内部会:
int dimension = embeddingModel.embed("test").size();  // 自动得到1024

实际操作演示

场景1: 首次启动,集合不存在

bash 复制代码
# 1. 启动应用
mvn spring-boot:run

# 控制台输出:
# [INFO] 正在连接Milvus服务器: 10.0.0.15:19530
# [INFO] Milvus客户端连接成功
# [INFO] 正在创建OpenAI EmbeddingModel...
# [INFO] OpenAI EmbeddingModel创建成功
# [INFO] 正在创建Milvus VectorStore,集合名称: zhi_yan
# [INFO] Milvus VectorStore创建成功
# [INFO] 应用启动完成!

# ⚠️ 注意:这里没有"创建集合"的日志!

# 2. 上传第一个文件
curl -X POST http://localhost:8084/api/documents/import \
  -F "file=@test.md"

# 控制台输出:
# [INFO] 正在导入Markdown文件: test.md
# [INFO] 开始导入Markdown内容,文件名: test.md
# [INFO] 文档已分割成 3 个块
# [INFO] 集合 zhi_yan 不存在,正在创建...  ← 这里才创建!
# [INFO] 正在获取向量维度...
# [INFO] 从EmbeddingModel检测到向量维度: 1024
# [INFO] 创建集合Schema: embedding字段维度=1024
# [INFO] 集合创建成功!
# [INFO] 成功导入 3 个文档块到Milvus

场景2: 集合已存在

bash 复制代码
# 上传第二个文件
curl -X POST http://localhost:8084/api/documents/import \
  -F "file=@test2.md"

# 控制台输出:
# [INFO] 正在导入Markdown文件: test2.md
# [INFO] 开始导入Markdown内容,文件名: test2.md
# [INFO] 文档已分割成 4 个块
# [INFO] 集合 zhi_yan 已存在,跳过创建  ← 跳过创建步骤
# [INFO] 成功导入 4 个文档块到Milvus

总结

集合什么时候创建?

不是启动时,而是第一次调用vectorStore.add()时!

embeddingModel什么时候参与?

复制代码
启动时: 只是创建embeddingModel对象,不调用
    ↓
第一次add()时: 
    ├─ 调用embeddingModel.embed("test")
    ├─ 获取向量维度(1024)
    └─ 创建集合,设置embedding字段为1024维

为什么是1024?

复制代码
因为你配置了:
.dimensions(1024)
    ↓
embeddingModel.embed("test") 返回1024维向量
    ↓
vectorStore检测到1024维
    ↓
创建集合时设置embedding字段为1024维

关键代码

java 复制代码
// initializeSchema(true) 的作用:
// 在第一次add()时,自动创建集合,并从embeddingModel获取维度
MilvusVectorStore.builder(...)
    .initializeSchema(true)  // ← 这个参数很关键!
    .build();

集合是在第一次使用时才创建的,不是启动时! 🎯

相关推荐
x***J3481 小时前
VueWebSocket案例
分布式·milvus·appcompat
e***71673 小时前
Spring Boot项目接收前端参数的11种方式
前端·spring boot·后端
程序猿小蒜3 小时前
基于springboot的的学生干部管理系统开发与设计
java·前端·spring boot·后端·spring
努力发光的程序员5 小时前
互联网大厂Java面试:从Spring Boot到微服务架构
spring boot·缓存·微服务·消息队列·rabbitmq·spring security·安全框架
TechTrek5 小时前
Spring Boot 4.0正式发布了
java·spring boot·后端·spring boot 4.0
飞梦工作室5 小时前
企业级 Spring Boot 邮件系统开发指南:从基础到高可用架构设计
java·spring boot·后端
haiyu柠檬5 小时前
在Spring Boot中实现Azure的SSO+VUE3前端配置
java·spring boot·后端
q***72195 小时前
springBoot 和springCloud 版本对应关系
spring boot·后端·spring cloud
百***81276 小时前
【SpringBoot】SpringBoot中分页插件(PageHelper)的使用
java·spring boot·后端