Milvus 是一款开源的云原生向量数据库,专为海量高维向量的相似性搜索与分析设计。它的核心是解决“非结构化数据(如图片、音频、文本、视频)通过向量表征后的快速检索”问题,因此在推荐系统、图像检索、语义搜索、AIGC知识库等场景中被广泛应用。
核心特性
- 高性能:支持十亿级向量数据的毫秒级检索,提供IVF_FLAT、HNSW、DISKANN等多种索引类型。
- 云原生:基于微服务架构,支持Kubernetes部署,具备弹性扩缩容能力。
- 多模态兼容:能够适配TensorFlow、PyTorch等主流深度学习框架生成的向量。
- 灵活的数据管理:支持向量与标量字段混合存储,并提供了动态增删改查、分区和TTL等功能。
- 多语言SDK:提供了包括Python、Java、Go、Node.js、C++在内的多种编程语言客户端。
- 高可用:通过副本与分布式部署机制,保障数据安全与服务的连续性。
核心概念
| 概念 |
说明 |
| 向量(Vector) |
非结构化数据经过嵌入模型(Embedding)处理后得到的高维数值数组(例如768维)。 |
| 集合(Collection) |
类似于关系型数据库中的“表”,用于存储向量及相关的标量字段。 |
| 分区(Partition) |
集合的子划分,可根据时间、业务场景等维度隔离数据,以提升检索效率。 |
| 索引(Index) |
为向量字段建立的加速检索结构。若未建立索引,检索将退化为性能低下的暴力(brute-force)搜索。 |
| 别名(Alias) |
集合的别名,可用于在不中断业务的情况下平滑切换集合版本。 |
| 一致性级别 |
支持强一致性、会话一致性和最终一致性,以满足不同业务场景对数据一致性的要求。 |
安装部署
Milvus支持两种主流部署方式:Docker Compose(适用于单机或测试环境) 和 Kubernetes(适用于生产环境)。
前置条件
- Docker Compose部署:需要Docker 20.10.0+和Docker Compose 2.0+。
- Kubernetes部署:需要K8s 1.21+和Helm 3.0+。
- 硬件建议:推荐CPU 4核以上、内存16GB以上(大规模向量数据需要更高配置),磁盘建议使用SSD。
Docker Compose部署
这是最快速的单机启动方式,适合开发和测试。
步骤1:下载配置文件
下载官方main分支的独立部署模板:
wget https://raw.githubusercontent.com/milvus-io/milvus/master/deployments/docker/standalone/docker-compose.yml -O docker-compose.yml
注意:上述链接指向最新开发版。如需固定版本(例如v2.4.6),需手动编辑docker-compose.yml文件,将milvusdb/milvus:latest替换为milvusdb/milvus:v2.4.6。
步骤2:启动与验证
配置文件准备就绪后,执行以下命令启动所有服务:
# 在后台启动所有容器
docker compose up -d
# 查看所有容器的运行状态
docker compose ps
当所有容器(包括etcd、minio、standalone)的状态都显示为Up时,表示Milvus服务已成功启动。
Go SDK与版本兼容性
Milvus遵循主版本.次版本.补丁版本(例如v2.4.6)的语义化版本规则,Go SDK与服务端的兼容性至关重要。
| 版本类型 |
兼容性说明 |
示例 |
| 主版本(如 2.x) |
主版本不同则完全不兼容。 |
v1.1.x SDK 无法连接 v2.4.x 服务端。 |
| 次版本(如 2.4.x) |
向前兼容:高版本SDK可连接低版本服务端(但新功能可能不可用)。反向不保证:低版本SDK连接高版本服务端可能导致错误。 |
v2.4.x SDK 连接 v2.3.x 服务端基本可用。 |
| 补丁版本(如 2.4.6) |
完全兼容,仅包含Bug修复,无接口变更。 |
v2.4.6 SDK 与 v2.4.3 服务端可互通。 |
核心原则
- 生产环境:必须确保 SDK次版本 ≤ 服务端次版本,且补丁版本尽量接近(例如服务端为v2.4.6,SDK应使用v2.4.6或v2.4.5)。
- 绝对禁止:使用低版本SDK连接高版本服务端(如v2.3.x SDK连接v2.4.x服务端),极易引发“未定义字段”、“协议解析失败”等错误。
如何保证版本兼容?
- 确认服务端版本:
# 查看Docker部署的Milvus版本
docker inspect milvus-standalone | grep "IMAGE"
# 输出示例:... "milvusdb/milvus:v2.4.6" ...
也可以通过Go SDK的GetVersion方法动态获取。
- 安装对应版本的SDK:
# 在Go项目中,严格指定与服务端一致的版本
go get github.com/milvus-io/milvus-sdk-go/v2@v2.4.6
完整示例代码
以下是一个使用Go SDK操作Milvus的完整示例,涵盖了连接、集合管理、数据插入、索引创建、向量检索和标量查询等核心操作。
package main
import (
"context"
"fmt"
"log"
"math/rand"
"time"
"github.com/milvus-io/milvus-sdk-go/v2/client"
"github.com/milvus-io/milvus-sdk-go/v2/entity"
"github.com/milvus-io/milvus-sdk-go/v2/grpc/client/param"
)
// generateRandomVector 生成指定维度的随机向量(模拟Embedding模型输出)
func generateRandomVector(dim int) []float32 {
vec := make([]float32, dim)
for i := 0; i < dim; i++ {
vec[i] = rand.Float32() // 生成 0~1 之间的随机数
}
return vec
}
func main() {
// 1. 配置连接参数
ctx := context.Background()
addr := "localhost:19530" // Milvus单机版默认地址
clientParams := []param.ConnectParam{
param.WithAddress(addr),
param.WithConnectTimeout(5 * time.Second),
// 生产环境若开启认证,可添加: param.WithAuthorization("root:Milvus")
}
// 2. 建立连接
milvusClient, err := client.NewGrpcClient(ctx, clientParams...)
if err != nil {
log.Fatalf("连接 Milvus 失败: %v", err)
}
defer milvusClient.Close()
fmt.Println("✅ Milvus 连接成功")
// 3. 定义集合参数
collectionName := "go_demo_collection"
dim := 768 // 向量维度(适配常见BERT等模型)
indexType := entity.IndexTypeHNSW // 索引类型,HNSW适用于高性能检索
metricType := entity.MetricTypeL2 // 距离度量方式:L2欧氏距离
// 4. 清理旧集合(演示用)
exists, err := milvusClient.HasCollection(ctx, collectionName)
if err != nil {
log.Fatalf("检查集合失败: %v", err)
}
if exists {
err = milvusClient.DropCollection(ctx, collectionName)
if err != nil {
log.Fatalf("删除集合失败: %v", err)
}
fmt.Printf("🗑️ 已删除旧集合: %s\n", collectionName)
}
// 5. 创建集合(定义Schema)
fields := []*entity.Field{
// 主键字段 (INT64, 自增)
{
Name: "id",
DataType: entity.FieldTypeInt64,
PrimaryKey: true,
AutoID: true,
},
// 向量字段 (FLOAT_VECTOR, 768维)
{
Name: "image_vector",
DataType: entity.FieldTypeFloatVector,
TypeParams: map[string]string{
entity.TypeParamDim: fmt.Sprintf("%d", dim),
},
},
// 标量字段 (VARCHAR, 存储图片名)
{
Name: "image_name",
DataType: entity.FieldTypeVarChar,
TypeParams: map[string]string{entity.TypeParamMaxLength: "255"},
},
}
schema := &entity.Schema{
CollectionName: collectionName,
Fields: fields,
Description: "Go SDK 演示:图片向量集合",
}
err = milvusClient.CreateCollection(ctx, schema, 1) // 1个分片
if err != nil {
log.Fatalf("创建集合失败: %v", err)
}
fmt.Printf("✅ 创建集合成功: %s\n", collectionName)
// 6. 插入测试数据
rand.Seed(time.Now().UnixNano())
numRows := 10
vectors := make([][]float32, 0, numRows)
imageNames := make([]string, 0, numRows)
for i := 0; i < numRows; i++ {
vectors = append(vectors, generateRandomVector(dim))
imageNames = append(imageNames, fmt.Sprintf("image_%d.jpg", i+1))
}
insertData := entity.NewInsertParam(collectionName)
insertData.AddColumn("image_vector", vectors)
insertData.AddColumn("image_name", imageNames)
insertIDs, err := milvusClient.Insert(ctx, insertData)
if err != nil {
log.Fatalf("插入数据失败: %v", err)
}
fmt.Printf("✅ 插入 %d 条数据,生成的主键 ID: %v\n", numRows, insertIDs)
// 7. 创建索引(检索前必需步骤)
indexParam := &entity.IndexParam{
CollectionName: collectionName,
FieldName: "image_vector",
IndexType: indexType,
MetricType: metricType,
ExtraParams: map[string]string{
entity.IndexParamM: "8", // HNSW参数:每个节点的最大连接数
entity.IndexParamEfConstruction: "64", // 构建索引时的搜索范围
},
}
err = milvusClient.CreateIndex(ctx, indexParam)
if err != nil {
log.Fatalf("创建索引失败: %v", err)
}
fmt.Println("✅ 创建索引成功")
// 8. 加载集合到内存(检索前必需步骤)
err = milvusClient.LoadCollection(ctx, collectionName, false)
if err != nil {
log.Fatalf("加载集合失败: %v", err)
}
fmt.Println("✅ 集合已加载到内存")
// 9. 执行向量相似性检索 (TopK)
queryVector := generateRandomVector(dim)
searchParam := &entity.SearchParam{
CollectionName: collectionName,
FieldName: "image_vector",
MetricType: metricType,
TopK: 5, // 返回最相似的5个结果
ExtraParams: map[string]string{
entity.SearchParamEf: "64", // 检索时的搜索范围
},
OutputFields: []string{"image_name"},
}
searchParam.AddVectors(queryVector)
searchResults, err := milvusClient.Search(ctx, searchParam)
if err != nil {
log.Fatalf("检索失败: %v", err)
}
fmt.Println("\n🔍 向量检索 Top5 结果:")
for i, result := range searchResults {
fmt.Printf("第 %d 个查询向量的结果:\n", i+1)
for j, hit := range result {
fmt.Printf(" 排名 %d: ID=%d, 相似度得分=%.4f, 图片名称=%s\n",
j+1, hit.ID, hit.Score, hit.Fields["image_name"])
}
}
// 10. 执行标量条件查询
queryExpr := `image_name like "image_1%"`
queryParam := &entity.QueryParam{
CollectionName: collectionName,
Expr: queryExpr,
OutputFields: []string{"id", "image_name"},
}
queryResults, err := milvusClient.Query(ctx, queryParam)
if err != nil {
log.Fatalf("标量查询失败: %v", err)
}
fmt.Printf("\n📋 标量查询结果(%s):%+v\n", queryExpr, queryResults)
// 11. 删除数据(根据表达式)
if len(insertIDs) > 0 {
deleteExpr := fmt.Sprintf("id = %d", insertIDs[0])
err = milvusClient.Delete(ctx, collectionName, deleteExpr)
if err != nil {
log.Fatalf("删除数据失败: %v", err)
}
fmt.Printf("\n🗑️ 已删除 ID=%d 的数据\n", insertIDs[0])
}
// 12. 卸载集合释放资源
err = milvusClient.ReleaseCollection(ctx, collectionName)
if err != nil {
log.Fatalf("卸载集合失败: %v", err)
}
fmt.Println("\n✅ 集合已卸载,程序执行完成")
}
关键注意事项
- 版本兼容:务必确保Go SDK与Milvus服务端的版本严格匹配(特别是主版本和次版本)。可通过
go list -m github.com/milvus-io/milvus-sdk-go/v2查看当前SDK版本。
- 性能优化:
- 批量操作:尽量使用批量插入和检索,减少网络往返开销。
- 索引调优:根据数据规模和性能要求调整索引参数。例如,HNSW的
M参数影响精度和构建速度,efConstruction影响索引质量。
- 连接复用:在生产环境中,应创建客户端连接池并复用,避免频繁建立和关闭连接。
- 错误处理:示例中使用
log.Fatalf简化了错误处理。在实际生产代码中,应对网络超时、服务端异常等错误进行妥善捕获,并实现重试机制。
- 高可用配置:对于人工智能和搜索等关键业务场景,连接客户端时可配置
param.WithMaxRetries()实现自动重连。若为集群部署,应配置多个节点地址以实现负载均衡和故障转移。