根据业务场景不同,可以选择两种映射策略:
- 一对一映射:一个文件对应一个向量,将文件路径直接作为 Vector Key。
- 一对多映射:一个文件产生多个向量(如长文档切片、OCR 多模态),通过 Metadata 记录来源。
检索流程
典型的向量语义检索流程如下:
- 调用
QueryVectors接口进行向量检索,返回最相似的 TopK 向量及其 Metadata。 - 从返回结果中获取 Vector Key 或 Metadata 中的来源字段(如
source_file)。 - 通过
GetObject从 OSS 通用 Bucket 下载对应的原始文件,返回给用户。
用户搜索请求 (QueryVectors) ↓ 向量检索 → 返回 TopK 向量 (Key + Metadata) ↓ 从 Metadata 获取来源信息 (source_file) ↓ 从 OSS 通用 Bucket 下载原始文件 (GetObject) ↓ 返回原始文件给用户
选择映射策略
映射策略 |
适用场景 |
实现方式 |
一对一映射 |
一个文件对应一个向量(如一张图片提取一个特征向量) |
将原始文件的 Object Key 直接作为 Vector Key |
一对多映射 |
一个文件产生多个向量(如长文档切片、OCR 多模态处理) |
在 Metadata 中记录 |
说明
使用 OSS Vectors Embed CLI工具写入向量时,会自动在 Metadata 中添加 OSSVECTORS-EMBED-SRC-LOCATION 字段记录原始文件路径,无需手动维护。
场景示例:OCR 处理流
以下示例展示了一个原始文件 invoice_001.jpg 产生两条向量(图像特征 + OCR 文本)的一对多映射场景:
原始文件 Key |
衍生数据内容 |
向量类型 |
映射策略 (Metadata) |
|
图像特征 |
Image Vector |
|
|
OCR 识别文本 |
Text Vector |
|
通过 CLI 构建映射
oss-vectors-embed CLI 工具在写入向量时会自动在 Metadata 中记录原始文件路径。安装方式请参见使用 OSS Vectors Embed CLI 工具写入和检索向量数据。
开始前,请确保满足以下条件:
- 已配置环境变量
OSS_ACCESS_KEY_ID、OSS_ACCESS_KEY_SECRET和DASHSCOPE_API_KEY。 - 已创建向量 Bucket 和向量索引,且索引维度与所用 Embedding 模型输出维度一致。
将以下示例中的占位符替换为实际值:
占位符 |
说明 |
|
阿里云账号 ID |
|
向量 Bucket 名称 |
|
向量索引名称 |
一对一映射:使用文件名作为 Vector Key
通过 --filename-as-key 参数,将原始文件名直接作为 Vector Key。检索时通过返回的 Vector Key 即可定位原始文件。
oss-vectors-embed \ --account-id "<your-account-id>" \ --vectors-region cn-hangzhou \ put \ --vector-bucket-name "<your-vector-bucket>" \ --index-name "<your-index>" \ --model-id text-embedding-v4 \ --text /path/to/document.txt \ --filename-as-key
命令返回示例:
{ "key": "document.txt", "bucket": "<your-vector-bucket>", "index": "<your-index>", "model": "text-embedding-v4", "contentType": "text", "embeddingDimensions": 1024, "metadata": { "OSSVECTORS-EMBED-SRC-LOCATION": "document.txt", "OSSVECTORS-EMBED-SRC-CONTENT-TYPE": "TEXT", "OSSVECTORS-EMBED-SRC-CONTENT": "文件内容..." } }
说明
CLI 自动在 Metadata 中添加 OSSVECTORS-EMBED-SRC-LOCATION 字段记录原始文件路径,无需手动维护映射。
一对多映射:通过自定义 Metadata 关联
当一个原始文件产生多个向量时(如长文档切片),通过 --metadata 参数附加来源信息,将多个向量关联回同一原始文件。
oss-vectors-embed \ --account-id "<your-account-id>" \ --vectors-region cn-hangzhou \ put \ --vector-bucket-name "<your-vector-bucket>" \ --index-name "<your-index>" \ --model-id text-embedding-v4 \ --text /path/to/chunk_3.txt \ --filename-as-key \ --metadata '{"source_file": "manuals/guide.pdf", "chunk_id": "3"}'
命令返回示例:
{ "key": "chunk_3.txt", "bucket": "<your-vector-bucket>", "index": "<your-index>", "model": "text-embedding-v4", "contentType": "text", "embeddingDimensions": 1024, "metadata": { "source_file": "manuals/guide.pdf", "chunk_id": "3", "OSSVECTORS-EMBED-SRC-LOCATION": "chunk_3.txt", "OSSVECTORS-EMBED-SRC-CONTENT-TYPE": "TEXT", "OSSVECTORS-EMBED-SRC-CONTENT": "文件内容..." } }
检索时通过返回的 Metadata 中的 source_file 字段定位原始文件。
通过 SDK 构建映射
调用 PutVectors 接口写入向量时,在每条向量的 metadata 字段中注入原始文件的映射信息。
说明
SDK 方式需要传入已生成的向量(如 float32 数组),而非原始文本。从文本出发检索的场景,建议先通过 Embedding 模型生成向量,或直接使用 CLI 方式。
Python SDK
开始前请安装 alibabacloud-oss-v2 SDK:
pip install alibabacloud-oss-v2
确保已配置环境变量 OSS_ACCESS_KEY_ID 和 OSS_ACCESS_KEY_SECRET。
一对一映射
将原始文件的 Object Key 直接作为向量 Key,检索时通过 Vector Key 即可定位原始文件。
import alibabacloud_oss_v2 as oss import alibabacloud_oss_v2.vectors as oss_vectors ACCOUNT_ID = "<your-account-id>" REGION = "cn-hangzhou" BUCKET = "<your-vector-bucket>" INDEX = "<your-index>" def create_vector_client(): """创建向量检索客户端""" credentials_provider = oss.credentials.EnvironmentVariableCredentialsProvider() cfg = oss.config.load_default() cfg.credentials_provider = credentials_provider cfg.region = REGION cfg.account_id = ACCOUNT_ID return oss_vectors.Client(cfg) client = create_vector_client() # 将原始文件路径直接作为向量 Key,实现 1:1 映射 result = client.put_vectors(oss_vectors.models.PutVectorsRequest( bucket=BUCKET, index_name=INDEX, vectors=[ { "key": "marketing/poster_01.png", # 直接使用原始文件路径 "data": {"float32": [0.12] * 128}, # 向量维度需与索引一致 "metadata": { "category": "promotion", } } ] )) print(f"写入结果: status_code={result.status_code}")
运行后输出:
写入结果: status_code=200
一对多映射
同一原始文件产生多条向量(如 OCR 场景),在 Metadata 中记录来源文件路径,检索时通过 Metadata 反查原始文件。
import alibabacloud_oss_v2 as oss import alibabacloud_oss_v2.vectors as oss_vectors ACCOUNT_ID = "<your-account-id>" REGION = "cn-hangzhou" BUCKET = "<your-vector-bucket>" INDEX = "<your-index>" def create_vector_client(): """创建向量检索客户端""" credentials_provider = oss.credentials.EnvironmentVariableCredentialsProvider() cfg = oss.config.load_default() cfg.credentials_provider = credentials_provider cfg.region = REGION cfg.account_id = ACCOUNT_ID return oss_vectors.Client(cfg) client = create_vector_client() # 同一原始文件 invoice_001.jpg 产生两条向量(图像特征 + OCR 文本) result = client.put_vectors(oss_vectors.models.PutVectorsRequest( bucket=BUCKET, index_name=INDEX, vectors=[ { "key": "vec_ocr_text_001", "data": {"float32": [0.05] * 128}, # 向量维度需与索引一致 "metadata": { "source_file": "invoice_001.jpg", "ocr_text_file": "invoice_001.txt", "type": "text", } }, { "key": "vec_ocr_image_001", "data": {"float32": [0.08] * 128}, # 向量维度需与索引一致 "metadata": { "source_file": "invoice_001.jpg", "type": "image", } } ] )) print(f"写入结果: status_code={result.status_code}") # 检索并通过 Metadata 反查原始文件 query_result = client.query_vectors(oss_vectors.models.QueryVectorsRequest( bucket=BUCKET, index_name=INDEX, query_vector={"float32": [0.05] * 128}, # 向量维度需与索引一致 return_metadata=True, return_distance=True, top_k=5, )) print(f"查询结果: status_code={query_result.status_code}") if query_result.vectors: for v in query_result.vectors: key = v.get("key") metadata = v.get("metadata", {}) source = metadata.get("source_file", key) # 优先从 metadata 获取来源 print(f" 向量 Key: {key}, 来源文件: {source}, 类型: {metadata.get('type', 'unknown')}")
运行后输出:
写入结果: status_code=200 查询结果: status_code=200 向量 Key: vec_ocr_text_001, 来源文件: invoice_001.jpg, 类型: text 向量 Key: vec_ocr_image_001, 来源文件: invoice_001.jpg, 类型: image ...
Go SDK
开始前请安装 alibabacloud-oss-go-sdk-v2 SDK:
go get github.com/aliyun/alibabacloud-oss-go-sdk-v2
确保已配置环境变量 OSS_ACCESS_KEY_ID 和 OSS_ACCESS_KEY_SECRET。
package main import ( "context" "fmt" "log" "github.com/aliyun/alibabacloud-oss-go-sdk-v2/oss" "github.com/aliyun/alibabacloud-oss-go-sdk-v2/oss/credentials" "github.com/aliyun/alibabacloud-oss-go-sdk-v2/oss/vectors" ) const ( region = "cn-hangzhou" bucketName = "<your-vector-bucket>" accountId = "<your-account-id>" indexName = "<your-index>" ) func main() { cfg := oss.LoadDefaultConfig(). WithCredentialsProvider(credentials.NewEnvironmentVariableCredentialsProvider()). WithRegion(region). WithAccountId(accountId) client := vectors.NewVectorsClient(cfg) // 写入向量,通过 metadata 关联原始文件 result, err := client.PutVectors(context.TODO(), &vectors.PutVectorsRequest{ Bucket: oss.Ptr(bucketName), IndexName: oss.Ptr(indexName), Vectors: [ ]map[string]any{ { "key": "marketing/poster_01.png", "data": map[string]any{"float32": [ ]float32{0.12, 0.05, 0.88}}, // 向量维度需与索引一致 "metadata": map[string]any{ "source_file": "marketing/poster_01.png", "category": "promotion", }, }, }, }) if err != nil { log.Fatalf("写入失败: %v", err) } fmt.Printf("写入结果: status_code=%d\n", result.StatusCode) // 查询并通过 metadata 获取来源文件 queryResult, err := client.QueryVectors(context.TODO(), &vectors.QueryVectorsRequest{ Bucket: oss.Ptr(bucketName), IndexName: oss.Ptr(indexName), QueryVector: map[string]any{"float32": [ ]float32{0.12, 0.05, 0.88}}, // 向量维度需与索引一致 ReturnMetadata: oss.Ptr(true), ReturnDistance: oss.Ptr(true), TopK: oss.Ptr(5), }) if err != nil { log.Fatalf("查询失败: %v", err) } fmt.Printf("查询结果: status_code=%d\n", queryResult.StatusCode) for _, v := range queryResult.Vectors { fmt.Printf(" 向量 Key: %v, metadata: %v\n", v["key"], v["metadata"]) } }
运行后输出:
写入结果: status_code=200 查询结果: status_code=200 向量 Key: marketing/poster_01.png, metadata: map[category:promotion source_file:marketing/poster_01.png] ...
最佳实践
- Vector Key 设计:若原始文件和向量为 1:1,首选将原始文件的 Object Key 作为 Vector Key。若为 1:N(如长文档切片),建议使用
{ObjectKey}#{ChunkID}格式,既能标识来源又能区分各切片。 - Metadata 设计:在 Metadata 中至少保留
source_file字段,方便从检索结果反查原始文件。 - 性能考量:避免在 Metadata 中存储过大的原始文本,仅存储 Key 或摘要。具体内容通过
GetObject回 OSS 查询。 - CLI 自动映射:使用
oss-vectors-embedCLI 写入时,会自动添加OSSVECTORS-EMBED-SRC-LOCATION字段记录来源,无需手动维护。 - Key 前缀管理:使用 CLI 的
--key-prefix参数为向量 Key 添加统一前缀,便于按业务维度批量管理和清理。