简介
本文档介绍如何使用对象存储 COS 的 Go SDK 在向量索引中进行相似度搜索,检索与查询向量最相似的 Top K 个向量。
功能说明
QueryVectors 方法用于在指定向量索引中,输入一个查询向量,基于距离度量方式(创建索引时指定的欧氏距离或余弦距离)检索最相似的向量。支持通过过滤条件(Filter)对元数据进行预过滤,缩小搜索范围。您还可以选择性地控制是否返回向量数据、元数据和距离值。方法原型
func (s *VectorService) QueryVectors(ctx context.Context, opt *QueryVectorsOptions, queryVector *VectorData, topK int) (*QueryVectorsResult, *Response, error)
请求参数说明
QueryVectorsOptions 结构体字段说明:参数 | 描述 | 类型 | 是否必填 |
VectorBucketName | 向量桶名称,格式为 <BucketName-APPID>,例如 examplebucket-1250000000。支持小写字母、数字和 -,长度限制为3-63个字符。 | string | 是 |
IndexName | 向量索引名称。 | string | 是 |
Filter | interface{} | 否 | |
ReturnData | 是否返回向量数据。默认为 false。 | *bool | 否 |
ReturnMetadata | 是否返回向量元数据。默认为 false。 | *bool | 否 |
ReturnDistance | 是否返回结果向量和查询向量的相似度距离值。默认为 false。 | *bool | 否 |
queryVector 参数说明:参数 | 描述 | 类型 | 是否必填 |
queryVector | 查询向量。输入向量的维度和数据类型必须与创建索引时指定的相匹配。 | *VectorData | 是 |
topK 参数说明:参数 | 描述 | 类型 | 是否必填 |
topK | 返回最相似的 K 个结果,取值范围为1-30。 | int | 是 |
过滤条件(Filter)说明
Filter 使用 JSON 对象表示,支持以下运算符:
比较运算符:
运算符 | 描述 | 示例 |
$eq | 等于 | {"genre": {"$eq": "drama"}} |
$ne | 不等于 | {"genre": {"$ne": "comedy"}} |
$gt | 大于 | {"year": {"$gt": 2020}} |
$gte | 大于等于 | {"year": {"$gte": 2020}} |
$lt | 小于 | {"year": {"$lt": 2025}} |
$lte | 小于等于 | {"year": {"$lte": 2025}} |
$in | 在数组中 | {"genre": {"$in": ["drama", "comedy"]}} |
$nin | 不在数组中 | {"genre": {"$nin": ["horror"]}} |
$exists | 字段存在性判断( true 存在,false 不存在) | {"summary": {"$exists": true}} |
逻辑运算符:
运算符 | 描述 | 示例 |
$and | 且 | {"$and": [条件1, 条件2]} |
$or | 或 | {"$or": [条件1, 条件2]} |
返回结果说明
调用成功后,将返回
(*QueryVectorsResult, *Response, error) 三个值。QueryVectorsResult 结构体字段说明:参数 | 描述 | 类型 |
Vectors | 结果向量列表,按相似度由高到低排序。 | []QueryOutputVector |
QueryOutputVector 结构体字段说明:参数 | 描述 | 类型 |
Key | 向量主键。 | string |
Data | 向量数据(仅当请求中 ReturnData 为 true 时返回)。 | *VectorData |
Metadata | 向量元数据(仅当请求中 ReturnMetadata 为 true 时返回)。 | map[string]interface{} |
Distance | 结果向量与查询向量的距离值(仅当请求中 ReturnDistance 为 true 时返回)。值越小表示越相似。 | float64 |
其他返回值说明:
返回值 | 描述 | 类型 |
resp | 响应头信息,包含 HTTP 响应的详细对象等。 | *cos.Response |
err | 错误信息。如果请求成功,返回 nil。 | error |
如果请求失败,将返回非
nil 的 error。向量检索相关的业务错误(如资源不存在等)会封装为 *cos.VectorErrorResponse 结构,您可以通过 cos.IsVectorError() 辅助函数判断并获取详细错误信息。详细的错误处理方式、VectorErrorResponse 结构体说明及服务端错误码列表请参见 异常处理 文档。使用案例
案例一:基础相似度搜索(不带过滤条件)
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 := "my-index"opt := &cos.QueryVectorsOptions{VectorBucketName: bucketName,IndexName: indexName,}// 查询向量(维度需与索引创建时一致)queryVector := &cos.VectorData{Float32: []float32{0.1, 0.2, 0.3},}// 返回最相似的 Top 10 结果res, _, err := client.Vector.QueryVectors(context.Background(), opt, queryVector, 10)if err != nil {if vecErr, ok := cos.IsVectorError(err); ok {fmt.Printf("向量服务错误,错误码: %s, 错误信息: %s, 请求ID: %s\\n",vecErr.Code, vecErr.Message, vecErr.RequestID)} else {fmt.Printf("请求失败: %v\\n", err)}return}fmt.Printf("检索到 %d 个最相似的向量\\n", len(res.Vectors))for i, v := range res.Vectors {fmt.Printf(" #%d Key: %s\\n", i+1, v.Key)}}
案例二:带过滤条件的相似度搜索(返回距离和元数据)
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 := "my-index"returnDistance := truereturnMetadata := true// 使用过滤条件:仅搜索 genre 为 drama、year >= 2020,且 summary 字段存在的向量opt := &cos.QueryVectorsOptions{VectorBucketName: bucketName,IndexName: indexName,Filter: map[string]interface{}{"$and": []map[string]interface{}{{"genre": map[string]interface{}{"$eq": "drama"}},{"year": map[string]interface{}{"$gte": 2020}},{"summary": map[string]interface{}{"$exists": true}},},},ReturnDistance: &returnDistance,ReturnMetadata: &returnMetadata,}queryVector := &cos.VectorData{Float32: []float32{0.1, 0.2, 0.3},}res, _, err := client.Vector.QueryVectors(context.Background(), opt, queryVector, 5)if err != nil {if vecErr, ok := cos.IsVectorError(err); ok {fmt.Printf("向量服务错误,错误码: %s, 错误信息: %s, 请求ID: %s\\n",vecErr.Code, vecErr.Message, vecErr.RequestID)} else {fmt.Printf("请求失败: %v\\n", err)}return}fmt.Printf("检索到 %d 个最相似的向量(已过滤)\\n", len(res.Vectors))for i, v := range res.Vectors {fmt.Printf(" #%d Key: %s, 距离: %.6f\\n", i+1, v.Key, v.Distance)if v.Metadata != nil {fmt.Printf(" 元数据: %v\\n", v.Metadata)}}}
案例三:返回完整信息的相似度搜索(向量数据 + 元数据 + 距离)
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 := "my-index"returnData := truereturnMetadata := truereturnDistance := true// 使用 $or 过滤条件:搜索 genre 为 drama 或 comedy 的向量opt := &cos.QueryVectorsOptions{VectorBucketName: bucketName,IndexName: indexName,Filter: map[string]interface{}{"$or": []map[string]interface{}{{"genre": map[string]interface{}{"$eq": "drama"}},{"genre": map[string]interface{}{"$eq": "comedy"}},},},ReturnData: &returnData,ReturnMetadata: &returnMetadata,ReturnDistance: &returnDistance,}queryVector := &cos.VectorData{Float32: []float32{0.15, 0.25, 0.35},}// 返回 Top 3 最相似结果res, _, err := client.Vector.QueryVectors(context.Background(), opt, queryVector, 3)if err != nil {if vecErr, ok := cos.IsVectorError(err); ok {fmt.Printf("向量服务错误,错误码: %s, 错误信息: %s, 请求ID: %s\\n",vecErr.Code, vecErr.Message, vecErr.RequestID)} else {fmt.Printf("请求失败: %v\\n", err)}return}fmt.Printf("检索到 %d 个最相似的向量\\n", len(res.Vectors))for i, v := range res.Vectors {fmt.Printf(" #%d Key: %s\\n", i+1, v.Key)fmt.Printf(" 距离: %.6f\\n", v.Distance)if v.Data != nil {fmt.Printf(" 向量数据 (前3维): %v\\n", v.Data.Float32[:min(3, len(v.Data.Float32))])}if v.Metadata != nil {fmt.Printf(" 元数据: %v\\n", v.Metadata)}}}func min(a, b int) int {if a < b {return a}return b}