相关资源
对象存储的 Go SDK 源码下载地址:Go SDK。
演示示例 Demo 可以在源码的
example/vector 中找到,下载地址:Go SDK Demo。SDK 更新日志请参见 ChangeLog。
环境配置与准备
初始化向量桶服务
下面为您介绍如何使用 COS Go SDK 初始化向量桶客户端后完成一个基础操作,例如创建向量存储桶、查询向量存储桶列表、创建向量桶索引、查询向量桶索引列表、写入向量、查询向量等。
初始化 COS Vectors Client
注意:
建议用户使用子账号密钥 + 环境变量的方式调用 SDK,提高 SDK 使用的安全性。为子账号授权时,请遵循 最小权限指引原则,防止泄露目标存储桶或对象之外的资源。
一般而言,建议使用临时密钥访问向量桶服务,如果您一定要使用永久密钥,建议遵循对永久密钥的权限范围进行限制。
下面介绍 Go SDK Client 的初始化方式。与普通 COS 存储桶不同,向量桶服务需要通过专用的辅助函数生成向量专属的 URL,并传递给 Client 初始化。
说明:
正常情况下,全局只需要生成一个 Cos Client 实例,然后循环进行桶、索引、向量等操作,不建议每次访问都生成新的实例,以复用底层的连接池。
说明:
目前提供了三种 URL 生成方式:
1. NewVectorURL:通过地域名生成公网 URL(例如:https://vectors.ap-guangzhou.coslake.com)
2. NewVectorInternalURL:通过地域名生成内网 URL(例如:https://vectors.ap-guangzhou.internal.tencentcos.com)
3. NewVectorEndpointURL:直接通过自定义的完整 Endpoint 生成 URL
package mainimport ("net/http""os"cos "github.com/tencentyun/cos-go-sdk-v5")func main() {// 方式一:通过地域名生成公网 URL (推荐)// 第二个参数控制是否使用 HTTPS,建议为 truevectorURL, _ := cos.NewVectorURL("ap-guangzhou", true)// 方式二:通过地域名生成内网 URL (适用于同地域云服务器内网访问)// vectorURL, _ := cos.NewVectorInternalURL("ap-guangzhou", true)// 方式三:直接使用自定义的 Endpoint// vectorURL, _ := cos.NewVectorEndpointURL("https://vectors.ap-guangzhou.coslake.com")// 用户的 SecretId 和 SecretKey,建议使用子账号密钥,授权遵循最小权限指引。secretID := os.Getenv("COS_VECTORS_SECRET_ID")secretKey := os.Getenv("COS_VECTORS_SECRET_KEY")// 初始化 Client,设置 VectorURL 及鉴权_ = cos.NewClient(&cos.BaseURL{VectorURL: vectorURL}, &http.Client{Transport: &cos.AuthorizationTransport{SecretID: secretID,SecretKey: secretKey,},})// 后续所有向量相关的操作均通过 client.Vector 进行访问}
说明:
package mainimport ("net/http""os"cos "github.com/tencentyun/cos-go-sdk-v5")func main() {vectorURL, _ := cos.NewVectorURL("ap-guangzhou", true)// 临时密钥生成和使用指引参见 https://cloud.tencent.com/document/product/436/14048secretID := os.Getenv("COS_VECTORS_TMP_SECRET_ID")secretKey := os.Getenv("COS_VECTORS_TMP_SECRET_KEY")sessionToken := os.Getenv("COS_VECTORS_SESSION_TOKEN")_ = cos.NewClient(&cos.BaseURL{VectorURL: vectorURL}, &http.Client{Transport: &cos.AuthorizationTransport{SecretID: secretID,SecretKey: secretKey,SessionToken: sessionToken, // 必须设置 SessionToken 以使用临时凭证},})// 后续所有向量相关的操作均通过 client.Vector 进行访问}
访问向量桶服务
package mainimport ("context""fmt""net/http""os""time"cos "github.com/tencentyun/cos-go-sdk-v5")func main() {vectorURL, _ := cos.NewVectorURL("ap-guangzhou", true)client := cos.NewClient(&cos.BaseURL{VectorURL: vectorURL}, &http.Client{Transport: &cos.AuthorizationTransport{SecretID: os.Getenv("COS_VECTORS_SECRET_ID"),SecretKey: os.Getenv("COS_VECTORS_SECRET_KEY"),},})bucketName := "examplebucket-1250000000" // 替换为您的向量桶名称// ==================== 列出向量桶 ====================fmt.Println("==================== 列出向量桶 ====================")listRes, _, err := client.Vector.ListVectorBuckets(context.Background(), &cos.ListVectorBucketsOptions{})if err != nil {if vecErr, ok := cos.IsVectorError(err); ok {fmt.Printf("向量服务错误 [%s]: %s (RequestID: %s)\\n", vecErr.Code, vecErr.Message, vecErr.RequestID)} else {fmt.Printf("请求失败: %v\\n", err)}return}fmt.Printf("向量桶总数: %d\\n", len(listRes.VectorBuckets))if listRes.NextToken != "" {fmt.Printf("下一页标记: %s\\n", listRes.NextToken)}for i, b := range listRes.VectorBuckets {fmt.Printf(" [%d] 桶名称: %s\\n", i+1, b.VectorBucketName)fmt.Printf(" 资源QCS: %s\\n", b.VectorBucketQcs)fmt.Printf(" 创建时间: %s\\n", time.Unix(b.CreationTime, 0).Format("2006-01-02 15:04:05"))}// ==================== 创建向量桶 ====================fmt.Println("\\n==================== 创建向量桶 ====================")createOpt := &cos.CreateVectorBucketOptions{VectorBucketName: bucketName,}createRes, _, err := client.Vector.CreateVectorBucket(context.Background(), createOpt)if err != nil {if vecErr, ok := cos.IsVectorError(err); ok {fmt.Printf("向量服务错误 [%s]: %s (RequestID: %s)\\n", vecErr.Code, vecErr.Message, vecErr.RequestID)} else {fmt.Printf("请求失败: %v\\n", err)}return}fmt.Printf("创建成功!\\n")fmt.Printf(" 资源QCS: %s\\n", createRes.VectorBucketQcs)// ==================== 获取向量桶 ====================fmt.Println("\\n==================== 获取向量桶详情 ====================")getOpt := &cos.GetVectorBucketOptions{VectorBucketName: bucketName,}getRes, _, err := client.Vector.GetVectorBucket(context.Background(), getOpt)if err != nil {if vecErr, ok := cos.IsVectorError(err); ok {fmt.Printf("向量服务错误 [%s]: %s (RequestID: %s)\\n", vecErr.Code, vecErr.Message, vecErr.RequestID)} else {fmt.Printf("请求失败: %v\\n", err)}return}if getRes.VectorBucket != nil {vb := getRes.VectorBucketfmt.Printf(" 桶名称: %s\\n", vb.VectorBucketName)fmt.Printf(" 资源QCS: %s\\n", vb.VectorBucketQcs)fmt.Printf(" 创建时间: %s\\n", time.Unix(vb.CreationTime, 0).Format("2006-01-02 15:04:05"))if vb.EncryptionConfiguration != nil {fmt.Printf(" 加密类型: %s\\n", vb.EncryptionConfiguration.SseType)}}// ==================== 删除向量桶 ====================fmt.Println("\\n==================== 删除向量桶 ====================")delOpt := &cos.DeleteVectorBucketOptions{VectorBucketName: bucketName,}_, err = client.Vector.DeleteVectorBucket(context.Background(), delOpt)if err != nil {if vecErr, ok := cos.IsVectorError(err); ok {fmt.Printf("向量服务错误 [%s]: %s (RequestID: %s)\\n", vecErr.Code, vecErr.Message, vecErr.RequestID)} else {fmt.Printf("请求失败: %v\\n", err)}return}fmt.Printf("向量桶 %s 删除成功!\\n", bucketName)}
package mainimport ("context""fmt""net/http""os""strings""time"cos "github.com/tencentyun/cos-go-sdk-v5")func main() {vectorURL, _ := cos.NewVectorURL("ap-guangzhou", true)client := cos.NewClient(&cos.BaseURL{VectorURL: vectorURL}, &http.Client{Transport: &cos.AuthorizationTransport{SecretID: os.Getenv("COS_VECTORS_SECRET_ID"),SecretKey: os.Getenv("COS_VECTORS_SECRET_KEY"),},})bucketName := "examplebucket-1250000000"indexName := "idx-dim3"// ==================== 列出向量索引 ====================fmt.Println("==================== 列出向量索引 ====================")listIdxOpt := &cos.ListIndexesOptions{VectorBucketName: bucketName,}listIdxRes, _, err := client.Vector.ListIndexes(context.Background(), listIdxOpt)if err != nil {if vecErr, ok := cos.IsVectorError(err); ok {fmt.Printf("向量服务错误 [%s]: %s (RequestID: %s)\\n", vecErr.Code, vecErr.Message, vecErr.RequestID)} else {fmt.Printf("请求失败: %v\\n", err)}return}fmt.Printf("索引总数: %d\\n", len(listIdxRes.Indexes))if listIdxRes.NextToken != "" {fmt.Printf("下一页标记: %s\\n", listIdxRes.NextToken)}for i, idx := range listIdxRes.Indexes {fmt.Printf(" [%d] 索引名称: %s\\n", i+1, idx.IndexName)fmt.Printf(" 所属桶: %s\\n", idx.VectorBucketName)fmt.Printf(" 资源QCS: %s\\n", idx.IndexQcs)fmt.Printf(" 创建时间: %s\\n", time.Unix(idx.CreationTime, 0).Format("2006-01-02 15:04:05"))}// ==================== 创建向量索引 ====================fmt.Println("\\n==================== 创建向量索引 ====================")createIdxOpt := &cos.CreateIndexOptions{VectorBucketName: bucketName,IndexName: indexName,DataType: "float32",Dimension: 3,DistanceMetric: "euclidean",}createIdxRes, _, err := client.Vector.CreateIndex(context.Background(), createIdxOpt)if err != nil {if vecErr, ok := cos.IsVectorError(err); ok {fmt.Printf("向量服务错误 [%s]: %s (RequestID: %s)\\n", vecErr.Code, vecErr.Message, vecErr.RequestID)} else {fmt.Printf("请求失败: %v\\n", err)}return}fmt.Printf("索引创建成功!\\n")fmt.Printf(" 资源QCS: %s\\n", createIdxRes.IndexQcs)// ==================== 获取向量索引详情 ====================fmt.Println("\\n==================== 获取向量索引详情 ====================")getIdxOpt := &cos.GetIndexOptions{VectorBucketName: bucketName,IndexName: indexName,}getIdxRes, _, err := client.Vector.GetIndex(context.Background(), getIdxOpt)if err != nil {if vecErr, ok := cos.IsVectorError(err); ok {fmt.Printf("向量服务错误 [%s]: %s (RequestID: %s)\\n", vecErr.Code, vecErr.Message, vecErr.RequestID)} else {fmt.Printf("请求失败: %v\\n", err)}return}if getIdxRes.Index != nil {idx := getIdxRes.Indexfmt.Printf(" 索引名称: %s\\n", idx.IndexName)fmt.Printf(" 所属桶: %s\\n", idx.VectorBucketName)fmt.Printf(" 资源QCS: %s\\n", idx.IndexQcs)fmt.Printf(" 数据类型: %s\\n", idx.DataType)fmt.Printf(" 向量维度: %d\\n", idx.Dimension)fmt.Printf(" 距离度量: %s\\n", idx.DistanceMetric)fmt.Printf(" 创建时间: %s\\n", time.Unix(idx.CreationTime, 0).Format("2006-01-02 15:04:05"))if idx.MetadataConfiguration != nil && len(idx.MetadataConfiguration.NonFilterableMetadataKeys) > 0 {fmt.Printf(" 不可过滤键: %s\\n", strings.Join(idx.MetadataConfiguration.NonFilterableMetadataKeys, ", "))}}// ==================== 删除向量索引 ====================fmt.Println("\\n==================== 删除向量索引 ====================")delIdxOpt := &cos.DeleteIndexOptions{VectorBucketName: bucketName,IndexName: indexName,}_, err = client.Vector.DeleteIndex(context.Background(), delIdxOpt)if err != nil {if vecErr, ok := cos.IsVectorError(err); ok {fmt.Printf("向量服务错误 [%s]: %s (RequestID: %s)\\n", vecErr.Code, vecErr.Message, vecErr.RequestID)} else {fmt.Printf("请求失败: %v\\n", err)}return}fmt.Printf("索引 %s 删除成功!\\n", indexName)}
package mainimport ("context""fmt""net/http""os"cos "github.com/tencentyun/cos-go-sdk-v5")func main() {vectorURL, _ := cos.NewVectorURL("ap-guangzhou", true)client := cos.NewClient(&cos.BaseURL{VectorURL: vectorURL}, &http.Client{Transport: &cos.AuthorizationTransport{SecretID: os.Getenv("COS_VECTORS_SECRET_ID"),SecretKey: os.Getenv("COS_VECTORS_SECRET_KEY"),},})bucketName := "examplebucket-1250000000"indexName := "idx-dim3"// 存储桶中已创建 Index 向量索引// ==================== 插入向量 ====================fmt.Println("==================== 插入向量 ====================")putVecOpt := &cos.PutVectorsOptions{VectorBucketName: bucketName,IndexName: indexName,}vectors := []cos.InputVector{{Key: "vector1",Data: &cos.VectorData{Float32: []float32{0.1, 0.2, 0.3},},Metadata: map[string]interface{}{"key1": "value1","key2": "value2",},},{Key: "vector2",Data: &cos.VectorData{Float32: []float32{0.4, 0.5, 0.6},},Metadata: map[string]interface{}{"key1": "value1","key2": "value2",},},}_, err := client.Vector.PutVectors(context.Background(), putVecOpt, vectors)if err != nil {if vecErr, ok := cos.IsVectorError(err); ok {fmt.Printf("向量服务错误 [%s]: %s (RequestID: %s)\\n", vecErr.Code, vecErr.Message, vecErr.RequestID)} else {fmt.Printf("请求失败: %v\\n", err)}return}fmt.Printf("成功插入 %d 条向量数据\\n", len(vectors))// ==================== 获取向量 ====================fmt.Println("\\n==================== 获取向量 ====================")getVecOpt := &cos.GetVectorsOptions{VectorBucketName: bucketName,IndexName: indexName,ReturnData: cos.Bool(true),ReturnMetadata: cos.Bool(true),}keys := []string{"vector1", "vector2"}getVecRes, _, err := client.Vector.GetVectors(context.Background(), getVecOpt, keys)if err != nil {if vecErr, ok := cos.IsVectorError(err); ok {fmt.Printf("向量服务错误 [%s]: %s (RequestID: %s)\\n", vecErr.Code, vecErr.Message, vecErr.RequestID)} else {fmt.Printf("请求失败: %v\\n", err)}return}fmt.Printf("获取到 %d 条向量:\\n", len(getVecRes.Vectors))for i, v := range getVecRes.Vectors {fmt.Printf(" [%d] 主键: %s\\n", i+1, v.Key)if v.Data != nil && len(v.Data.Float32) > 0 {fmt.Printf(" 向量数据: %v\\n", v.Data.Float32)}if len(v.Metadata) > 0 {fmt.Printf(" 元数据:\\n")for mk, mv := range v.Metadata {fmt.Printf(" %s = %v\\n", mk, mv)}}}// ==================== 相似度搜索 ====================fmt.Println("\\n==================== 相似度搜索 ====================")queryOpt := &cos.QueryVectorsOptions{VectorBucketName: bucketName,IndexName: indexName,ReturnData: cos.Bool(true),ReturnMetadata: cos.Bool(true),}queryVec := &cos.VectorData{Float32: []float32{0.1, 0.2, 0.3},}topK := 10queryRes, _, err := client.Vector.QueryVectors(context.Background(), queryOpt, queryVec, topK)if err != nil {if vecErr, ok := cos.IsVectorError(err); ok {fmt.Printf("向量服务错误 [%s]: %s (RequestID: %s)\\n", vecErr.Code, vecErr.Message, vecErr.RequestID)} else {fmt.Printf("请求失败: %v\\n", err)}return}fmt.Printf("搜索到 %d 条相似向量 (TopK=%d):\\n", len(queryRes.Vectors), topK)for i, v := range queryRes.Vectors {fmt.Printf(" [%d] 主键: %s, 距离: %f\\n", i+1, v.Key, v.Distance)if v.Data != nil && len(v.Data.Float32) > 0 {fmt.Printf(" 向量数据: %v\\n", v.Data.Float32)}if len(v.Metadata) > 0 {fmt.Printf(" 元数据:\\n")for mk, mv := range v.Metadata {fmt.Printf(" %s = %v\\n", mk, mv)}}}// ==================== 列出向量 ====================fmt.Println("\\n==================== 列出向量 ====================")listVecOpt := &cos.ListVectorsOptions{VectorBucketName: bucketName,IndexName: indexName,MaxResults: 10,}listVecRes, _, err := client.Vector.ListVectors(context.Background(), listVecOpt)if err != nil {if vecErr, ok := cos.IsVectorError(err); ok {fmt.Printf("向量服务错误 [%s]: %s (RequestID: %s)\\n", vecErr.Code, vecErr.Message, vecErr.RequestID)} else {fmt.Printf("请求失败: %v\\n", err)}return}fmt.Printf("列出 %d 条向量:\\n", len(listVecRes.Vectors))if listVecRes.NextToken != "" {fmt.Printf("下一页标记: %s\\n", listVecRes.NextToken)}for i, v := range listVecRes.Vectors {fmt.Printf(" [%d] 主键: %s\\n", i+1, v.Key)}// ==================== 删除向量 ====================fmt.Println("\\n==================== 删除向量 ====================")delVecOpt := &cos.DeleteVectorsOptions{VectorBucketName: bucketName,IndexName: indexName,}_, err = client.Vector.DeleteVectors(context.Background(), delVecOpt, keys)if err != nil {if vecErr, ok := cos.IsVectorError(err); ok {fmt.Printf("向量服务错误 [%s]: %s (RequestID: %s)\\n", vecErr.Code, vecErr.Message, vecErr.RequestID)} else {fmt.Printf("请求失败: %v\\n", err)}return}fmt.Printf("成功删除 %d 条向量\\n", len(keys))}
package mainimport ("bytes""context""encoding/json""fmt""net/http""os"cos "github.com/tencentyun/cos-go-sdk-v5")func main() {vectorURL, _ := cos.NewVectorURL("ap-guangzhou", true)client := cos.NewClient(&cos.BaseURL{VectorURL: vectorURL}, &http.Client{Transport: &cos.AuthorizationTransport{SecretID: os.Getenv("COS_VECTORS_SECRET_ID"),SecretKey: os.Getenv("COS_VECTORS_SECRET_KEY"),},})bucketName := "examplebucket-1250000000"// ==================== 配置向量桶策略 ====================fmt.Println("==================== 配置向量桶策略 ====================")// 构造策略 JSON 字符串,各字段含义:// - Version: 策略版本,固定为 "2.0"// - Effect: 授权效果,"Allow" 表示允许// - Principal: 被授权的主体,格式为 qcs::cam::uin/<主账号UIN>:uin/<子账号UIN>// - Action: 允许的操作列表,此处授予查看向量桶和列出向量的权限// - Resource: 授权的资源范围,格式为 qcs::cosvector:<region>:uid/<APPID>:bucket/<桶名>/*policy := `{"Version": "2.0","Statement": [{"Effect": "Allow","Principal": {"qcs": ["qcs::cam::uin/700000000000:uin/700001234567"]},"Action": ["name/cos:GetVectorBucket","name/cos:ListVectors"],"Resource": ["qcs::cosvector:ap-guangzhou:uid/1250000000:bucket/examplebucket-1250000000/*"]}]}`putPolOpt := &cos.PutVectorBucketPolicyOptions{VectorBucketName: bucketName,Policy: policy,}_, err := client.Vector.PutVectorBucketPolicy(context.Background(), putPolOpt)if err != nil {if vecErr, ok := cos.IsVectorError(err); ok {fmt.Printf("向量服务错误 [%s]: %s (RequestID: %s)\\n", vecErr.Code, vecErr.Message, vecErr.RequestID)} else {fmt.Printf("请求失败: %v\\n", err)}return}fmt.Printf("策略配置成功! 目标桶: %s\\n", bucketName)// ==================== 查看向量桶策略 ====================fmt.Println("\\n==================== 查看向量桶策略 ====================")getPolOpt := &cos.GetVectorBucketPolicyOptions{VectorBucketName: bucketName,}getPolRes, _, err := client.Vector.GetVectorBucketPolicy(context.Background(), getPolOpt)if err != nil {if vecErr, ok := cos.IsVectorError(err); ok {fmt.Printf("向量服务错误 [%s]: %s (RequestID: %s)\\n", vecErr.Code, vecErr.Message, vecErr.RequestID)} else {fmt.Printf("请求失败: %v\\n", err)}return}// 将策略 JSON 字符串格式化输出var prettyJSON bytes.Bufferif err := json.Indent(&prettyJSON, []byte(getPolRes.Policy), " ", " "); err == nil {fmt.Printf(" 当前策略:\\n %s\\n", prettyJSON.String())} else {fmt.Printf(" 当前策略: %s\\n", getPolRes.Policy)}// ==================== 删除向量桶策略 ====================fmt.Println("\\n==================== 删除向量桶策略 ====================")delPolOpt := &cos.DeleteVectorBucketPolicyOptions{VectorBucketName: bucketName,}_, err = client.Vector.DeleteVectorBucketPolicy(context.Background(), delPolOpt)if err != nil {if vecErr, ok := cos.IsVectorError(err); ok {fmt.Printf("向量服务错误 [%s]: %s (RequestID: %s)\\n", vecErr.Code, vecErr.Message, vecErr.RequestID)} else {fmt.Printf("请求失败: %v\\n", err)}return}fmt.Printf("桶 %s 的策略删除成功!\\n", bucketName)}