使用Milvus时存储源数据方案

674 阅读4分钟

使用Milvus时存储源数据方案

1. 直接使用 MinIO 存储原始内容的推荐场景

如果满足以下条件,推荐直接使用 MinIO

  • 原始内容为大型文件:如图片、视频、PDF 文档等非结构化数据。
  • 无需复杂元数据查询:仅需通过简单路径或 URL 访问文件。
  • 已有 MinIO 运维经验:熟悉其 API 和权限管理。
  • 高扩展性需求:预计数据量会快速增长,需分布式存储支持。
操作示例
// 插入数据到 Milvus 时关联 MinIO 路径
InsertParam insertParam = InsertParam.newBuilder()
    .withCollectionName("images")
    .withFieldsData(Arrays.asList(
        FieldData.newBuilder().withName("id").withIntData(1001).build(),
        FieldData.newBuilder().withName("vector").withFloatVectorData(vector).build(),
        FieldData.newBuilder().withName("minio_path").withStringData("mybucket/images/1001.jpg").build()
    ))
    .build();
milvusClient.insert(insertParam);
优点
  • 无缝集成:MinIO 已与 Milvus 部署在同一环境,无需额外服务。
  • 成本低:直接复用现有对象存储,节省资源。
  • 高性能:对象存储专为大文件优化,适合高吞吐场景。
缺点
  • 元数据管理弱:需自行维护 minio_path 与向量 ID 的映射关系。
  • 复杂查询困难:如需要根据文件属性(如上传时间、标签)筛选内容,需额外开发逻辑。

2. 更优方案推荐(不直接使用 MinIO 的场景)

如果遇到以下需求,建议采用其他方案:

场景 1:需要复杂元数据查询
  • 需求:根据文件属性(如标签、作者、时间范围)联合查询。

  • 方案MinIO + 关系型数据库(如 PostgreSQL)

    • 分工

      • MinIO:仅存储原始文件。
      • 关系型数据库:存储文件的元数据和 MinIO 路径。
      • Milvus:存储向量和关联的元数据 ID。
    • 操作流程

      1. 上传文件到 MinIO,生成唯一路径。

      2. 将元数据(如标签、描述、路径)写入 PostgreSQL:

        INSERT INTO images (id, minio_path, tags, upload_time)
        VALUES (1001, 'mybucket/images/1001.jpg', '风景,夏季', NOW());
        
      3. 插入向量到 Milvus,关联元数据 ID:

        InsertParam insertParam = InsertParam.newBuilder()
            .withCollectionName("images")
            .withFieldsData(Arrays.asList(
                FieldData.newBuilder().withName("metadata_id").withIntData(1001).build(),
                FieldData.newBuilder().withName("vector").withFloatVectorData(vector).build()
            ))
            .build();
        
    • 查询示例

      -- 联合查询:先通过 Milvus 搜索向量,再通过 ID 关联元数据
      SELECT * FROM images 
      WHERE id IN (SELECT metadata_id FROM milvus_results) 
      AND tags LIKE '%风景%';
      
    • 优点

      • 支持复杂 SQL 查询(如 JOIN、聚合)。
      • 事务支持,保证数据一致性。
    • 缺点

      • 需维护两个系统(Milvus + PostgreSQL)。

场景 2:多模态数据(文本 + 向量 + 文件)
  • 需求:同时管理结构化数据、非结构化文件和向量。

  • 方案MongoDB(多模型数据库)

    • 设计

      • MongoDB:存储原始内容(如 JSON 文档)、文件路径或 Base64 编码的小文件。
      • Milvus:存储向量,通过文档 ID 关联。
    • 插入示例

      // MongoDB 插入文档
      Document doc = new Document()
          .append("_id", 1001)
          .append("description", "夏季风景照片")
          .append("minio_path", "mybucket/images/1001.jpg");
      
      mongoCollection.insertOne(doc);
      
      // Milvus 插入向量
      InsertParam insertParam = InsertParam.newBuilder()
          .withCollectionName("images")
          .withFieldsData(Arrays.asList(
              FieldData.newBuilder().withName("doc_id").withIntData(1001).build(),
              FieldData.newBuilder().withName("vector").withFloatVectorData(vector).build()
          ))
          .build();
      
    • 查询示例

      // 先通过 Milvus 搜索向量,获取关联的 doc_id
      List<Long> docIds = milvusSearchResults.getIDs();
      
      // 从 MongoDB 查询完整数据
      Bson filter = Filters.in("_id", docIds);
      FindIterable<Document> results = mongoCollection.find(filter);
      
    • 优点

      • 灵活存储多模态数据(JSON、文件路径、二进制)。
      • 内置索引支持快速查询。
    • 缺点

      • 大文件仍需依赖 MinIO 或 GridFS(MongoDB 的分布式文件存储)。

场景 3:极致简化架构
  • 需求:最小化运维成本,接受轻度性能损失。

  • 方案Milvus 标量字段存储小文件元数据

    • 设计

      • 小文件(如小于 1MB 的文本、缩略图)直接 Base64 编码后存入 Milvus 标量字段。
      • 大文件:仍用 MinIO 存储路径。
    • 示例

      // 将小图片转换为 Base64 字符串
      String imageBase64 = Base64.getEncoder().encodeToString(imageBytes);
      
      // 插入到 Milvus
      InsertParam insertParam = InsertParam.newBuilder()
          .withCollectionName("images")
          .withFieldsData(Arrays.asList(
              FieldData.newBuilder().withName("id").withIntData(1001).build(),
              FieldData.newBuilder().withName("vector").withFloatVectorData(vector).build(),
              FieldData.newBuilder().withName("thumbnail").withStringData(imageBase64).build()
          ))
          .build();
      
    • 优点

      • 无需外部存储,架构简单。
    • 缺点

      • 性能下降(Base64 编解码开销)。
      • 仅适合极小文件(Milvus 单条记录大小有限制)。

3. 决策树:如何选择存储方案?

原始内容类型?
├── 大文件(图片、视频) → MinIO + 元数据管理(PostgreSQL/MongoDB)
├── 小文本/简单元数据 → Milvus 标量字段
└── 混合多模态数据 → MongoDB + MinIO

总结

  • 推荐直接使用 MinIO:如果系统以大规模非结构化文件为主,且无需复杂元数据查询。
  • 推荐结合关系型数据库:如果需要事务支持和复杂查询。
  • 推荐多模型数据库:如果处理多模态数据且希望简化架构。

最终选择应基于以下优先级:

  1. 数据类型和大小:大文件选 MinIO,小文本选 Milvus 标量字段。
  2. 查询复杂度:复杂查询需引入关系型数据库。
  3. 运维成本:MinIO 方案最简单,但功能有限;多系统方案功能强大,但维护复杂。

可以根据实际场景混合使用这些方案,例如:

  • 核心图片存储在 MinIO。
  • 元数据和频繁查询的标签存在 PostgreSQL。
  • 向量存在 Milvus。