OSS 向量 Bucket 用於儲存、查詢和管理向量資料,基於向量Bucket和阿里雲大模型服務平台百鍊的多模態 Embedding 模型,可以搭建海量圖片的智能語義檢索系統,實現基於自然語言描述的文搜圖能力的最佳實務,適用於電商商品搜尋、智能相簿、媒體資產管理、AI 語義檢索、圖片知識庫等情境。
方案概覽
搭建多模態圖片語義檢索系統,包含以下步驟:
環境準備:擷取訪問憑證,並安裝 OSS Python SDK 和阿里雲百鍊 SDK。
上傳圖片資料到 OSS:準備待檢索的圖片資料集,上傳至 OSS Bucket。
建立 OSS 向量 Bucket 和向量索引:建立儲存向量資料的 OSS 向量 Bucket 和向量索引。
產生並寫入向量:使用阿里雲百鍊多模態 Embedding 模型將圖片轉換為高維向量,並將百鍊產生的向量資料寫入 OSS 向量索引中。
執行語義檢索:將查詢文本轉換為向量語義,在向量索引中執行相似性搜尋,同時通過中繼資料進行檢索結果過濾。
可視化 Demo:通過 OSS 提供的 Demo 平台展示語義檢索效果。
1. 環境準備
擷取訪問憑證
安裝SDK
已安裝 Python 3.12 及以上版本。
執行以下命令安裝阿里雲 OSS Python SDK V2和阿里雲百鍊SDK。
pip install alibabacloud-oss-v2 pip install dashscope
配置環境變數
為確保代碼安全與可移植性,建議將訪問憑證配置為環境變數。
# 百鍊 API Key
export DASHSCOPE_API_KEY=<您的百鍊API-KEY>
# OSS 訪問憑證
export oss_test_access_key_id=<您的AccessKey ID>
export oss_test_access_key_secret=<您的AccessKey Secret>
export oss_test_region=<您的Region,如cn-hangzhou>
export oss_test_account_id=<您的阿里雲帳號ID>2. 上傳圖片資料到 OSS
將圖片資料從本地上傳到 OSS Bucket。百鍊的 Embedding 模型需要通過 OSS 檔案 URL 來訪問這些圖片並進行向量化處理。以下代碼示範了如何批量上傳本地檔案夾中的圖片到指定的 Bucket。
-*- coding: utf-8 -*-
"""
樣本:使用檔案上傳管理器上傳圖片
本樣本展示如何使用 OSS SDK 的檔案上傳管理器進行更高效的檔案上傳。
適用於大檔案或需要斷點續傳的情境。
"""
import os
import alibabacloud_oss_v2 as oss
from alibabacloud_oss_v2.models import PutObjectRequest
def create_oss_client():
"""建立 OSS Client"""
access_key_id = os.environ.get('oss_test_access_key_id')
access_key_secret = os.environ.get('oss_test_access_key_secret')
region = os.environ.get('oss_test_region')
cfg = oss.config.load_default()
cfg.credentials_provider = oss.credentials.StaticCredentialsProvider(
access_key_id, access_key_secret
)
cfg.region = region
return oss.Client(cfg)
def upload_with_uploader(client, bucket_name: str, local_path: str, oss_key: str):
"""
使用上傳管理器上傳檔案
Args:
client: OSS Client
bucket_name: OSS Bucket 名稱
local_path: 本地檔案路徑
oss_key: OSS 對象鍵
"""
# 建立上傳管理器
uploader = client.uploader()
# 執行上傳
result = uploader.upload_file(
filepath=local_path,
request=PutObjectRequest(
bucket=bucket_name,
key=oss_key
)
)
return result
def main():
client = create_oss_client()
bucket_name = "your-bucket-name"
# 注意:文末的 Github倉庫裡 data/photograph/ 目錄已包含測試圖片,可直接使用
# 也可以修改 local_image_path 變數,指向自己的圖片目錄
local_image_path = "data/photograph/"
oss_prefix = "photograph/"
image_files = os.listdir(local_image_path)
print(f"待上傳圖片數量: {len(image_files)}")
for i, image_name in enumerate(image_files, 1):
local_path = os.path.join(local_image_path, image_name)
oss_key = f"{oss_prefix}{image_name}"
try:
result = upload_with_uploader(client, bucket_name, local_path, oss_key)
print(f"[{i}/{len(image_files)}] 上傳成功: {image_name}, status: {result.status_code}")
except Exception as e:
print(f"[{i}/{len(image_files)}] 上傳失敗 {image_name}: {e}")
print(f"\n上傳完成!")
if __name__ == "__main__":
main()3. 建立 OSS 向量 Bucket 和向量索引
3.1 建立向量Bucket
使用 OSS SDK 建立一個向量 Bucket,將其作為儲存所有向量資料和向量索引的雲資源。
# -*- coding: utf-8 -*-
"""
樣本:建立 VectorBucket
本樣本展示如何建立一個 OSS VectorBucket。
前提條件:
1. 已安裝 alibabacloud-oss-v2: pip install alibabacloud-oss-v2
2. 已設定環境變數(參考初始化 Client 樣本)
"""
import os
import alibabacloud_oss_v2 as oss
import alibabacloud_oss_v2.vectors as oss_vectors
def main():
# 從環境變數擷取憑證
access_key_id = os.environ.get('oss_test_access_key_id')
access_key_secret = os.environ.get('oss_test_access_key_secret')
region = os.environ.get('oss_test_region')
account_id = os.environ.get('oss_test_account_id')
# 初始化 Client
cfg = oss.config.load_default()
cfg.credentials_provider = oss.credentials.StaticCredentialsProvider(
access_key_id, access_key_secret
)
cfg.region = region
cfg.account_id = account_id
client = oss_vectors.Client(cfg)
# VectorBucket 名稱
vector_bucket_name = "my-test-2"
print(f"正在建立 VectorBucket: {vector_bucket_name}")
try:
# 建立 VectorBucket
result = client.put_vector_bucket(oss_vectors.models.PutVectorBucketRequest(
bucket=vector_bucket_name,
))
print(f"建立成功!")
print(f" status code: {result.status_code}")
print(f" request id: {result.request_id}")
except Exception as e:
print(f"建立失敗: {e}")
print("提示: 如果 Bucket 已存在,會返回錯誤")
if __name__ == "__main__":
main()3.2 建立向量索引
建立向量 Bucket 後,需要在其中建立向量索引,用於儲存和查詢向量資料。向量索引定義了向量的維度和距離度量方式,是寫入和檢索向量資料的基礎。建立向量索引後,可以逐行寫入向量資料及其關聯的標量中繼資料。
注意:向量索引的維度必須與在百鍊中使用的向量模型的維度保持一致。
以下樣本將建立一張 1024 維、距離度量函數為餘弦距離的向量索引表。
# -*- coding: utf-8 -*-
"""
樣本:建立向量索引(Index)
本樣本展示如何在 VectorBucket 中建立向量索引。
前提條件:
1. 已安裝 alibabacloud-oss-v2: pip install alibabacloud-oss-v2
2. 已設定環境變數
3. 已建立 VectorBucket
"""
import os
import alibabacloud_oss_v2 as oss
import alibabacloud_oss_v2.vectors as oss_vectors
def main():
# 從環境變數擷取憑證
access_key_id = os.environ.get('oss_test_access_key_id')
access_key_secret = os.environ.get('oss_test_access_key_secret')
region = os.environ.get('oss_test_region')
account_id = os.environ.get('oss_test_account_id')
# 初始化 Client
cfg = oss.config.load_default()
cfg.credentials_provider = oss.credentials.StaticCredentialsProvider(
access_key_id, access_key_secret
)
cfg.region = region
cfg.account_id = account_id
client = oss_vectors.Client(cfg)
# 配置參數
vector_bucket_name = "my-test-2"
vector_index_name = "test1"
dimension = 1024 # 百鍊多模態模型輸出向量維度
print(f"正在建立向量索引:")
print(f" Bucket: {vector_bucket_name}")
print(f" Index: {vector_index_name}")
print(f" 維度: {dimension}")
# 建立向量索引
result = client.put_vector_index(oss_vectors.models.PutVectorIndexRequest(
bucket=vector_bucket_name,
index_name=vector_index_name,
dimension=dimension,
data_type='float32', # 向量資料類型
distance_metric='cosine', # 距離度量方式:餘弦相似性
metadata={
"nonFilterableMetadataKeys": ["key1", "key2"] # 不參與過濾的中繼資料欄位
}
))
print(f"\n建立成功!")
print(f" status code: {result.status_code}")
print(f" request id: {result.request_id}")
if __name__ == "__main__":
main()參數說明:
參數 | 說明 |
dimension | 向量維度,需與 Embedding 模型輸出維度一致 |
data_type | 向量資料類型,支援 float32 |
distance_metric | 距離度量方式,支援 cosine、euclidean |
metadata | 中繼資料配置,配置非過濾中繼資料欄位,用於儲存不參與搜尋過濾的附加資訊,作為向量資料的描述資訊 |
4. 產生並寫入向量
OSS 向量 Bucket 支援寫入通過任意方式產生的向量資料,例如阿里雲百鍊或自建向量化服務產生的結果。向量產生與寫入可以分別調用阿里雲百鍊 SDK 和 OSS SDK 完成,也可以使用 OSS-Vectors-Embed-CLI 在一條命令中完成向量產生與寫入。
使用阿里雲百鍊 SDK 和 OSS SDK
以阿里雲百鍊提供的多模態 Embedding 模型 multimodal-embedding-v1 為例,將原始圖片轉換為 1024 維向量,並寫入 OSS 向量 Bucket 的向量索引中。
4.1 產生向量資料
import dashscope
from dashscope import MultiModalEmbeddingItemImage
def embedding_image(image_url: str) -> list[float]:
"""
將圖片轉換為向量
Args:
image_url: 圖片的 URL 地址(支援 OSS 地址或公網 URL)
Returns:
1024 維的向量列表
"""
resp = dashscope.MultiModalEmbedding.call(
model="multimodal-embedding-v1",
input=[MultiModalEmbeddingItemImage(image=image_url, factor=1.0)]
)
return resp.output["embeddings"][0]["embedding"]
def main():
# 樣本圖片 URL(需替換為實際可訪問的圖片地址,如為圖片為私人許可權,需要填入帶簽名的臨時 URL)
image_url = "http://your-bucket-name.oss-cn-hangzhou.aliyuncs.com/photograph/Zsd0YhBa8LM.jpg"
print(f"正在對圖片進行向量化: {image_url}")
# 調用 Embedding API
resp = dashscope.MultiModalEmbedding.call(
model="multimodal-embedding-v1",
input=[MultiModalEmbeddingItemImage(image=image_url, factor=1.0)]
)
# 列印完整響應
print("\n完整響應:")
print(resp)
# 擷取向量
embedding = resp.output["embeddings"][0]["embedding"]
print(f"\n向量維度: {len(embedding)}")
print(f"向量前10個元素: {embedding[:10]}")
if __name__ == "__main__":
main()4.2 寫入向量資料
# -*- coding: utf-8 -*-
"""
樣本:批量寫入圖片向量資料
本樣本展示如何批量寫入已經向量化的圖片資料到向量索引中。
前提條件:
1. 已安裝 alibabacloud-oss-v2: pip install alibabacloud-oss-v2
2. 已設定環境變數
3. 已建立向量索引
4. 已準備好圖片向量資料檔案(data/data.json)
"""
import os
import json
import alibabacloud_oss_v2 as oss
import alibabacloud_oss_v2.vectors as oss_vectors
def main():
# 從環境變數擷取憑證
access_key_id = os.environ.get('oss_test_access_key_id')
access_key_secret = os.environ.get('oss_test_access_key_secret')
region = os.environ.get('oss_test_region')
account_id = os.environ.get('oss_test_account_id')
# 初始化 Client
cfg = oss.config.load_default()
cfg.credentials_provider = oss.credentials.StaticCredentialsProvider(
access_key_id, access_key_secret
)
cfg.region = region
cfg.account_id = account_id
client = oss_vectors.Client(cfg)
# 配置參數
vector_bucket_name = "my-test-2"
vector_index_name = "test1"
# 載入預先處理好的圖片向量資料
# 注意:文末的 Github倉庫裡 data/目錄已包含測試檔案,可直接使用
# 也可以修改 data_file 變數,指向自己的圖片目錄
data_file = "./data/data.json"
print(f"正在載入圖片向量資料: {data_file}")
image_data_array = []
with open(data_file, "r") as f:
image_data_array = json.load(f)
print(f"共載入 {len(image_data_array)} 條圖片向量資料")
# 列印資料範例
if len(image_data_array) > 0:
sample = image_data_array[0]
print(f"\n資料範例:")
print(f" key: {sample.get('key', 'N/A')}")
if 'metadata' in sample:
print(f" metadata: {sample['metadata']}")
if 'data' in sample and 'float32' in sample['data']:
print(f" 向量維度: {len(sample['data']['float32'])}")
# 批量寫入,每批 500 條
batch_size = 500
vectors = []
total_written = 0
print(f"\n開始批量寫入 (batch_size={batch_size})...")
for idx in range(len(image_data_array)):
vectors.append(image_data_array[idx])
if len(vectors) == batch_size:
result = client.put_vectors(oss_vectors.models.PutVectorsRequest(
bucket=vector_bucket_name,
index_name=vector_index_name,
vectors=vectors,
))
total_written += len(vectors)
print(f" 已寫入 {total_written}/{len(image_data_array)} 條, "
f"status code: {result.status_code}")
vectors = []
# 寫入剩餘資料
if len(vectors) > 0:
result = client.put_vectors(oss_vectors.models.PutVectorsRequest(
bucket=vector_bucket_name,
index_name=vector_index_name,
vectors=vectors,
))
total_written += len(vectors)
print(f" 已寫入 {total_written}/{len(image_data_array)} 條, "
f"status code: {result.status_code}")
print(f"\n寫入完成! 共寫入 {total_written} 條向量資料")
if __name__ == "__main__":
main()使用 OSS-Vectors-Embed-CLI
OSS-Vectors-Embed-CLI 調用阿里雲百鍊向量模型,對 OSS 中的原始檔案或本地檔案進行向量化,並將向量結果寫入 OSS 向量 Bucket;也可用於發起多模態語義檢索。工具支援批量處理、自訂配置,以及寫入標量中繼資料等能力。
oss-vectors-embed \
--account-id <your-account-id> \ //阿里雲 ID
--vectors-region cn-hangzhou \ //OSS 向量 Bucket 所在地區
put \
--region cn-hangzhou \ //OSS 原始檔案所在 Bucket 的地區
--vector-bucket-name my-vector-bucket \ //OSS 向量 Bucket 名稱
--index-name my-index \ //OSS 向量 Index 名稱
--model-id multimodal-embedding-v1 \ //使用的向量模型
--image "oss://bucket/path/*" //對 OSS 該 Prefix 下的檔案批量發起向量化和向量結果的寫入
--filename-as-key //將原始檔案 Key 值自訂設定為向量 Key 值5. 執行語義檢索
使用自然語言文本作為查詢條件,通過 OSS SDK 或 OSS-Vectors-Embed-CLI 命令列工具進行向量語義檢索,或向量與標量的混合檢索,從向量索引中找到最相似的圖片。OSS-Vectors-Embed-CLI 封裝了查詢內容的向量化和相似性檢索功能,支援"以文搜圖"、"以圖搜圖"等多模態語義檢索情境,詳見OSS-Vectors-Embed-CLI 命令列工具。
5.1 基礎檢索
將查詢文本(例如“狗狗”)向量化後,在索引中尋找最接近的Top-K個圖片向量。
使用阿里雲百鍊 SDK 和 OSS SDK
# -*- coding: utf-8 -*-
"""
樣本:向量檢索查詢(Query Vector)
本樣本展示如何使用向量進行相似性檢索,支援中繼資料過濾。
前提條件:
1. 已安裝 alibabacloud-oss-v2 和 dashscope
2. 已設定環境變數
3. 已設定百鍊 API Key: export DASHSCOPE_API_KEY=<您的 API Key>
4. 已寫入向量資料
"""
import os
import alibabacloud_oss_v2 as oss
import alibabacloud_oss_v2.vectors as oss_vectors
import dashscope
from dashscope import MultiModalEmbeddingItemText
def embedding(text: str) -> list[float]:
"""
文本向量化用於將查詢文本轉換為向量,實現文搜圖能力
Args:
text: 待轉換的文本
Returns:
1024 維的向量列表
"""
return dashscope.MultiModalEmbedding.call(
model="multimodal-embedding-v1",
input=[MultiModalEmbeddingItemText(text=text, factor=1.0)]
).output["embeddings"][0]["embedding"]
def main():
# 從環境變數擷取憑證
access_key_id = os.environ.get('oss_test_access_key_id')
access_key_secret = os.environ.get('oss_test_access_key_secret')
region = os.environ.get('oss_test_region')
account_id = os.environ.get('oss_test_account_id')
# 初始化 Client
cfg = oss.config.load_default()
cfg.credentials_provider = oss.credentials.StaticCredentialsProvider(
access_key_id, access_key_secret
)
cfg.region = region
cfg.account_id = account_id
client = oss_vectors.Client(cfg)
# 配置參數
vector_bucket_name = "my-test-2"
vector_index_name = "test1"
# 查詢文本
query_text = "狗狗"
print(f"進行中向量檢索:")
print(f" Bucket: {vector_bucket_name}")
print(f" Index: {vector_index_name}")
print(f" 查詢文本: {query_text}")
# 將查詢文本轉換為向量
print(f"\n正在將查詢文本轉換為向量...")
query_vector = embedding(query_text)
print(f" 向量維度: {len(query_vector)}")
# 執行向量檢索
print(f"\n執行向量檢索 ...")
result = client.query_vectors(oss_vectors.models.QueryVectorsRequest(
bucket=vector_bucket_name,
index_name=vector_index_name,
query_vector={
"float32":query_vector
},
top_k=5, # 返回最相似的 5 個結果
return_distance=True, # 返回相似性距離
return_metadata=True, # 返回中繼資料
))
print(f"\n檢索結果 (共 {len(result.vectors)} 條):")
for i, vector in enumerate(result.vectors, 1):
print(f"\n [{i}] key: {vector.get('key', 'N/A')}")
if 'distance' in vector:
print(f" 距離: {vector['distance']:.6f}")
if 'metadata' in vector:
print(f" 中繼資料: {vector['metadata']}")
# 不帶過濾條件的檢索
print(f"\n" + "=" * 50)
print(f"執行向量檢索 (無過濾條件)...")
result = client.query_vectors(oss_vectors.models.QueryVectorsRequest(
bucket=vector_bucket_name,
index_name=vector_index_name,
query_vector={
"float32": query_vector
},
top_k=5,
return_distance=True,
return_metadata=True,
))
print(f"\n檢索結果 (共 {len(result.vectors)} 條):")
for i, vector in enumerate(result.vectors, 1):
print(f" [{i}] key: {vector.get('key', 'N/A')}, "
f"距離: {vector.get('distance', 'N/A')}")
if __name__ == "__main__":
main()使用 OSS-Vectors-Embed-CLI
oss-vectors-embed \
--account-id <your-account-id> \
--vectors-region cn-hangzhou \
query \
--vector-bucket-name my-vector-bucket \
--index-name my-index \
--model-id multimodal-embedding-v1 \
--text-value "狗狗" \ // Query 檢索文本
--top-k 100 // 檢索返回 100 個最相似的向量結果{
"results": [
{
"Key": "myimage03.jpg", //檢索返回的向量結果,返迴向量 Key-Value 和標量中繼資料
"metadata": {
"OSSVECTORS-EMBED-SRC-CONTENT-TYPE": "TEXT",
"OSSVECTORS-EMBED-SRC-LOCATION": "./images/photo.jpg", //CLI 會自動在向量 Bucket 該向量所在行添加源資訊欄位(OSSVECTORS-EMBED-SRC-*),用於追溯向量來源。
}
},
...
],
"summary": {
"queryType": "text",
"model": "multimodal-embedding-v1",
"index": "my-index",
"resultsFound": 100,
"queryDimensions": 1024
}
}4.2 結合過濾條件檢索
在進行向量相似性檢索的同時,可以根據圖片的中繼資料(如city、height)進行精確過濾,以縮小檢索範圍。向量檢索支援使用$in、$and、$or等操作符對中繼資料進行過濾。
使用阿里雲百鍊 SDK 和 OSS SDK
將查詢文本(例如“狗狗”)向量化後,在索引中尋找最接近的Top-K個圖片向量,並添加不同的標量中繼資料過濾條件。
# -*- coding: utf-8 -*-
"""
樣本:進階向量檢索查詢(Advanced Query)
本樣本展示向量檢索的進階用法,包括複雜過濾條件和多個查詢樣本。
前提條件:
1. 已安裝 alibabacloud-oss-v2 和 dashscope
2. 已設定環境變數
3. 已設定百鍊 API Key: export DASHSCOPE_API_KEY=<您的 API Key>
4. 已寫入向量資料
"""
import os
import alibabacloud_oss_v2 as oss
import alibabacloud_oss_v2.vectors as oss_vectors
import dashscope
from dashscope import MultiModalEmbeddingItemText
def embedding(text: str) -> list[float]:
"""文本向量化用於將查詢文本轉換為向量,實現文搜圖能力"""
return dashscope.MultiModalEmbedding.call(
model="multimodal-embedding-v1",
input=[MultiModalEmbeddingItemText(text=text, factor=1.0)]
).output["embeddings"][0]["embedding"]
def create_client():
"""建立 OSS Vector Client"""
access_key_id = os.environ.get('oss_test_access_key_id')
access_key_secret = os.environ.get('oss_test_access_key_secret')
region = os.environ.get('oss_test_region')
account_id = os.environ.get('oss_test_account_id')
cfg = oss.config.load_default()
cfg.credentials_provider = oss.credentials.StaticCredentialsProvider(
access_key_id, access_key_secret
)
cfg.region = region
cfg.account_id = account_id
return oss_vectors.Client(cfg)
def query_with_filter(client, bucket, index, query_text, filter_body, top_k=5):
"""執行帶過濾條件的向量檢索"""
result = client.query_vectors(oss_vectors.models.QueryVectorsRequest(
bucket=bucket,
index_name=index,
query_vector={"float32": embedding(query_text)},
filter=filter_body,
top_k=top_k,
return_distance=True,
return_metadata=True,
))
return result.vectors
def main():
client = create_client()
vector_bucket_name = "my-test-2"
vector_index_name = "test1"
print("=" * 60)
print("進階向量檢索樣本")
print("=" * 60)
# 樣本 1: $in 操作符 - 匹配多個城市
print("\n【樣本 1】使用 $in 操作符 - 查詢杭州或上海的圖片")
print("-" * 40)
filter_in = {
"city": {"$in": ["hangzhou", "shanghai"]}
}
results = query_with_filter(client, vector_bucket_name, vector_index_name,
"城市風景", filter_in)
print(f"查詢: '城市風景', 過濾: city in ['hangzhou', 'shanghai']")
print(f"結果數量: {len(results)}")
for v in results[:3]:
print(f" - {v.get('key')}: {v.get('metadata', {}).get('city', 'N/A')}")
# 樣本 2: $and 操作符 - 組合多個條件
print("\n【樣本 2】使用 $and 操作符 - 組合多個過濾條件")
print("-" * 40)
filter_and = {
"$and": [
{"city": {"$in": ["hangzhou", "shanghai"]}},
{"height": {"$in": ["1024"]}}
]
}
results = query_with_filter(client, vector_bucket_name, vector_index_name,
"高樓大廈", filter_and)
print(f"查詢: '高樓大廈', 過濾: city in [hangzhou, shanghai] AND height=1024")
print(f"結果數量: {len(results)}")
for v in results[:3]:
meta = v.get('metadata', {})
print(f" - {v.get('key')}: city={meta.get('city')}, height={meta.get('height')}")
# 樣本 3: 不同查詢文本的比較
print("\n【樣本 3】不同查詢文本的語義檢索效果")
print("-" * 40)
query_texts = ["狗狗", "海邊日落", "城市夜景", "美食"]
for qt in query_texts:
results = query_with_filter(client, vector_bucket_name, vector_index_name,
qt, None, top_k=3)
print(f"\n查詢: '{qt}'")
for i, v in enumerate(results, 1):
print(f" [{i}] {v.get('key')}, 距離: {v.get('distance', 0):.4f}")
if __name__ == "__main__":
main()使用 OSS-Vectors-Embed-CLI
# AND: 兩個條件都必須匹配
oss-vectors-embed \
--account-id <your-account-id> \
--vectors-region cn-hangzhou \
query \
--vector-bucket-name my-vector-bucket \
--index-name my-index \
--model-id multimodal-embedding-v1 \
--text-value "狗狗" \
--filter { //組合過濾條件
"$and": [
{"city": {"$in": ["hangzhou", "shanghai"]}},
{"height": {"$in": ["1024"]}}
]
} \
--top-k 5
{
"results": [
{
"Key": "fd91808c-8d7c-480e-a72b-2bfa7d313a80",
"metadata": {
"OSSVECTORS-EMBED-SRC-CONTENT-TYPE": "IMAGE",
"author": "admin",
"city": "hangzhou",
"OSSVECTORS-EMBED-SRC-CONTENT": "狗狗",
"height": "1024",
"OSSVECTORS-EMBED-SRC-LOCATION": "./images/photo.jpg"
}
},
{
...
],
"summary": {
"queryType": "text",
"model": "multimodal-embedding-v1",
"index": "my-index",
"resultsFound": 5,
"queryDimensions": 1024
}
}過濾條件說明:
操作符 | 說明 | 樣本 |
$in | 包含在列表中 |
|
$and | 邏輯與 |
|
$or | 邏輯或 |
|
複雜過濾樣本:
{
"$and": [
{"city": {"$in": ["hangzhou", "shanghai"]}},
{
"$or": [
{"height": "1024"},
{"height": "768"}
]
}
]
}6. 構建可視化檢索介面
為直觀地展示檢索效果,可使用Gradio構建一個簡單的Web介面,提供一個包含文本輸入、條件過濾和圖片結果展示的互動式檢索介面。
安裝Web 使用者介面架構
pip install gradio==5.44.1將以下代碼儲存為
gradio_app.py# -*- coding: utf-8 -*- import json import logging import os import alibabacloud_oss_v2 as oss import alibabacloud_oss_v2.vectors as oss_vectors import dashscope import gradio as gr from PIL import Image from dashscope import MultiModalEmbeddingItemText logging.basicConfig(level=logging.INFO) logger = logging.getLogger(__name__) class Util: access_key_id = os.environ.get('oss_test_access_key_id') access_key_secret = os.environ.get('oss_test_access_key_secret') region = os.environ.get('oss_test_region') account_id = os.environ.get('oss_test_account_id') cfg = oss.config.load_default() cfg.credentials_provider = oss.credentials.StaticCredentialsProvider(access_key_id, access_key_secret) cfg.region = region cfg.account_id = account_id client = oss_vectors.Client(cfg) vector_bucket_name = "my-test-2" vector_index_name = "test1" dimension = 1024 @staticmethod def embedding(text) -> list[float]: return dashscope.MultiModalEmbedding.call( model="multimodal-embedding-v1", input=[MultiModalEmbeddingItemText(text=text, factor=1.0)] ).output["embeddings"][0]["embedding"] @staticmethod def query_text(text: str, top_k: int = 5, city: list[str] = None, height: list[str] = None, return_meta: bool = True, return_distance: bool = True) -> list[tuple[Image.Image, str]]: logger.info(f"search text:{text}, top_k:{top_k}, city:{city}, height:{height}") sub_filter = [] if city is not None and len(city) > 0: sub_filter.append({"city": {"$in": city}}) if height is not None and len(height) > 0: sub_filter.append({"height": {"$in": height}}) if len(sub_filter) > 0: filter_body = {"$and": sub_filter} else: filter_body = None result = Util.client.query_vectors(oss_vectors.models.QueryVectorsRequest( bucket=Util.vector_bucket_name, index_name=Util.vector_index_name, query_vector={ "float32": Util.embedding(text) }, filter=filter_body, top_k=top_k, return_distance=return_distance, return_metadata=return_meta, )) gallery_data = [] current_dir = os.path.dirname(os.path.abspath(__file__)) # 前端展示依賴本地圖片檔案,請確保已按倉庫結構準備圖片資源: # - 預設使用文末倉庫內 data/photograph/ 目錄下的圖片,前端會讀取並展示其中的檔案; # - 如需使用自己的圖片,可將圖片放入其他目錄,並修改下方 path 指向該目錄。 for vector in result.vectors: file_path = os.path.join(current_dir, "data/photograph/", vector["key"]) img = Image.open(file_path) gallery_data.append((img, json.dumps(vector))) ret = gallery_data logger.info(f"search text:{text}, top_k:{top_k}, request_id:{result.request_id}, ret:{ret}") return ret @staticmethod def on_gallery_box_select(evt: gr.SelectData): result = "" img_data = evt.value["caption"] img_data = json.loads(img_data) for key in img_data: img_data_item = img_data[key] if type(img_data_item) is str: img_data_item = img_data_item.replace("\n", "\\n").replace("\t", "\\t").replace("\r", "\\r") if type(img_data_item) is dict: for sub_key in img_data_item: img_data_item[sub_key] = img_data_item[sub_key].replace("\n", "\\n").replace("\t", "\\t").replace("\r", "\\r") result += f' - **{sub_key}**: {img_data_item[sub_key]}\r\n' continue result += f' - **{key}**: {img_data_item}\r\n' return result with gr.Blocks(title="OSS Demo") as demo: with gr.Tab("OSS QueryVector 圖片樣本") as search_tab: with gr.Row(): query_text_box = gr.Textbox(label='query_text', interactive=True, value="狗狗") top_k_box = gr.Slider(minimum=1, maximum=30, value=10, step=1, label='top_k', interactive=True) with gr.Column(): return_meta_box = gr.Checkbox(label='return_meta', interactive=True, value=True) return_distance_box = gr.Checkbox(label='return_distance', interactive=True, value=True) with gr.Row(): city_box = gr.Dropdown(label='city', multiselect=True, choices=["hangzhou", "shanghai", "beijing", "shenzhen", "guangzhou"]) height_box = gr.Dropdown(label='height', multiselect=True, choices=["1024", "683", "768", "576"]) with gr.Row(): query_button = gr.Button(value="query", variant='primary') with gr.Row(): with gr.Column(scale=8): gallery_box = gr.Gallery(columns=5, show_label=False, preview=False, allow_preview=False, visible=True, show_download_button=False) with gr.Column(scale=2): with gr.Row(variant="panel"): md_box = gr.Markdown(visible=True, elem_classes="image_detail") gallery_box.select(Util.on_gallery_box_select, [], [md_box]) query_button.click( Util.query_text, inputs=[ query_text_box, top_k_box, city_box, height_box, return_meta_box, return_distance_box ], outputs=[ gallery_box, ], concurrency_limit=1, ) if __name__ == "__main__": demo.launch(server_name="0.0.0.0", server_port=7860)啟動介面
python gradio_app.py啟動成功後,訪問
http://localhost:7860即可使用檢索介面。檢索樣本:輸入"狗狗" → 返回包含狗的圖片。功能
說明
query_text
輸入自然語言描述,如"狗狗"、"山峰"等
top_k
設定返回結果數量(1-30)
city
按城市過濾(支援多選)
height
按圖片高度過濾(支援多選)
return_meta
是否返回中繼資料資訊
return_distance
是否返回相似性距離
相關文檔
本教程的完整專案工程:https://github.com/aliyun/alibabacloud-oss-vector-index-demo
OSS 向量 Bucket 功能:向量Bucket概述
OSS-Vectors-Embed-CLI 命令列工具:使用OSS Vectors Embed CLI工具寫入和檢索向量資料