構建向量與原始檔案的映射關係

更新時間:
Copy as MD

OSS Vectors 的檢索結果返回的是向量 Key 和 Metadata,而非原始檔案本身。要將檢索結果關聯回原始檔案(如圖片、文檔、視頻),需要在寫入向量時構建映射關係。

根據業務情境不同,可以選擇兩種映射策略:

  • 一對一映射:一個檔案對應一個向量,將檔案路徑直接作為 Vector Key。

  • 一對多映射:一個檔案產生多個向量(如長文檔切片、OCR 多模態),通過 Metadata 記錄來源。

檢索流程

典型的向量語義檢索流程如下:

  1. 調用 QueryVectors 介面進行向量檢索,返回最相似的 TopK 向量及其 Metadata。

  2. 從返回結果中擷取 Vector Key 或 Metadata 中的來源欄位(如 source_file)。

  3. 通過 GetObject 從 OSS 通用 Bucket 下載對應的原始檔案,返回給使用者。

  使用者搜尋請求 (QueryVectors)
        ↓
     向量檢索 → 返回 TopK 向量 (Key + Metadata)
        ↓
  從 Metadata 擷取來源資訊 (source_file)
        ↓
  從 OSS 通用 Bucket 下載原始檔案 (GetObject)
        ↓
  返回原始檔案給使用者

選擇映射策略

映射策略

適用情境

實現方式

一對一映射

一個檔案對應一個向量(如一張圖片提取一個特徵向量)

將原始檔案的 Object Key 直接作為 Vector Key

一對多映射

一個檔案產生多個向量(如長文檔切片、OCR 多模態處理)

在 Metadata 中記錄 source_file 等來源資訊

說明

使用 OSS Vectors Embed CLI工具寫入向量時,會自動在 Metadata 中添加 OSSVECTORS-EMBED-SRC-LOCATION 欄位記錄原始檔案路徑,無需手動維護。

情境樣本:OCR 處理流

以下樣本展示了一個原始檔案 invoice_001.jpg 產生兩條向量(映像特徵 + OCR 文本)的一對多映射情境:

原始檔案 Key

衍生資料內容

向量類型

映射策略 (Metadata)

invoice_001.jpg

映像特徵

Image Vector

source_file: invoice_001.jpg, type: image

invoice_001.jpg

OCR 識別文本

Text Vector

source_file: invoice_001.jpg, ocr_text_file: invoice_001.txt, type: text

通過 CLI 構建映射

oss-vectors-embed CLI 工具在寫入向量時會自動在 Metadata 中記錄原始檔案路徑。安裝方式請參見使用 OSS Vectors Embed CLI 工具寫入和檢索向量資料

開始前,請確保滿足以下條件:

  • 已配置環境變數 OSS_ACCESS_KEY_IDOSS_ACCESS_KEY_SECRETDASHSCOPE_API_KEY

  • 已建立向量 Bucket 和向量索引,且索引維度與所用 Embedding 模型輸出維度一致。

將以下樣本中的預留位置替換為實際值:

預留位置

說明

<your-account-id>

阿里雲帳號 ID

<your-vector-bucket>

向量 Bucket 名稱

<your-index>

向量索引名稱

一對一映射:使用檔案名稱作為 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_IDOSS_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
    cfg.use_internal_endpoint = True  # 如需通過公網訪問,請將此處設定為False或刪除此行
    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
    cfg.use_internal_endpoint = True  # 如需通過公網訪問,請將此處設定為False或刪除此行
    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_IDOSS_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).
		// 如需通過公網訪問,請將此處設定為false或刪除此行
		WithUseInternalEndpoint(true)

	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-embed CLI 寫入時,會自動添加 OSSVECTORS-EMBED-SRC-LOCATION 欄位記錄來源,無需手動維護。

  • Key 首碼管理:使用 CLI 的 --key-prefix 參數為向量 Key 添加統一首碼,便於按業務維度批量管理和清理。

相關文檔