检索向量

最近更新时间:2026-04-01 15:41:32

我的收藏

简介

本文档介绍如何使用对象存储 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
查询向量时的预过滤条件。支持基于元数据字段的条件过滤,语法详见下方 过滤条件(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
向量数据(仅当请求中 ReturnDatatrue 时返回)。
*VectorData
Metadata
向量元数据(仅当请求中 ReturnMetadatatrue 时返回)。
map[string]interface{}
Distance
结果向量与查询向量的距离值(仅当请求中 ReturnDistancetrue 时返回)。值越小表示越相似。
float64
其他返回值说明:
返回值
描述
类型
resp
响应头信息,包含 HTTP 响应的详细对象等。
*cos.Response
err
错误信息。如果请求成功,返回 nil
error
如果请求失败,将返回非 nilerror。向量检索相关的业务错误(如资源不存在等)会封装为 *cos.VectorErrorResponse 结构,您可以通过 cos.IsVectorError() 辅助函数判断并获取详细错误信息。详细的错误处理方式、VectorErrorResponse 结构体说明及服务端错误码列表请参见 异常处理 文档。

使用案例

案例一:基础相似度搜索(不带过滤条件)

package main

import (
"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 main

import (
"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 := true
returnMetadata := 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 main

import (
"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 := true
returnMetadata := true
returnDistance := 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
}