图片搜索快速入门

更新时间:
复制 MD 格式

本文通过一个完整示例,介绍如何使用 AnalyticDB for MySQL 图片搜索 API,搭建一个同时支持以文搜图和以图搜图的图像检索系统。示例使用公开图片数据,您可以跟随操作快速体验图片入库和语义检索的完整流程。

背景信息

AnalyticDB for MySQL 图片搜索服务基于多模态大模型和向量检索技术,提供图片库管理、图片导入和图片检索 API。您可以通过图片库统一管理图片数据,通过 OSS JSONL 文件批量入库,并在应用中调用以文搜图或以图搜图接口完成相似图片召回。

图片库支持以下三种工作模式:

模式

适用场景

检索能力

说明

item_search

商品、服饰等特定物品检索

以图搜图

创建时需指定关注物品名称。

general_search

企业图库、内容推荐、多类别自然图片

以图搜图、以文搜图

面向整图语义检索,适合本文使用的公开自然图片。

adaptive_search

人脸与普通图片混合检索

以图搜图

根据图片属性在人脸检索和整图语义检索之间自适应处理。

本文创建 general_search 模式的图片库,该模式同时支持以图搜图和以文搜图两种检索方式。

效果预览

跟随本文,您将基于图片搜索 API 搭建一个同时支持以文搜图以图搜图的检索系统。由于响应体仅返回 image_uri 和相似度分数,以下先直观展示两种检索方式的最终效果。

以文搜图:输入文本 a macbook,返回语义最相关的图片。

以文搜图效果:查询 a macbook 的返回结果

以图搜图:输入一张查询图片,返回视觉最相似的图片。

以图搜图效果:查询图片的返回结果

前提条件

开始前,请确认已完成以下准备工作:

  1. 已创建 AnalyticDB for MySQL 集群。

  2. 已开通图片搜索服务。

    重要

    图片搜索功能当前处于邀测阶段。如需使用,请提交工单或联系技术支持申请开通。

  3. 已准备 OSS Bucket,且 Bucket 与 AnalyticDB for MySQL 集群在同一地域。OSS 用于存放示例图片和批量导入所需的 JSONL 文件。

  4. 本地已安装 Python 3 和 curl。

示例中使用以下环境变量,请根据实际环境替换:

export IMAGE_SEARCH_ENDPOINT="http://<host>:<port>"
export API_PREFIX="$IMAGE_SEARCH_ENDPOINT/api/v1/operators/image-search"
export OSS_BUCKET="<YOUR-BUCKET-NAME>"
export OSS_PREFIX="image-search/picsum"
export LIBRARY_NAME="picsum_general_search"

变量

说明

IMAGE_SEARCH_ENDPOINT

图片搜索服务的访问地址。开通服务后,可在 AnalyticDB for MySQL 控制台获取。

OSS_BUCKET

OSS Bucket 名称,需与集群在同一地域。

OSS_PREFIX

示例数据在 OSS 中的存放路径前缀。

LIBRARY_NAME

本文创建的示例图片库名称。

步骤一:准备并上传示例图片

本文使用 Lorem Picsum 提供的公开图片。Lorem Picsum 提供图片列表 API,可按分页获取图片元数据。本示例下载其中 100 张固定尺寸(800×600)的图片用于演示。

创建 prepare_picsum_data.py,用于下载图片并生成批量导入所需的 JSONL 文件:

import json
import urllib.request
from pathlib import Path

# 输出目录和文件
ROOT = Path(".")
IMAGE_DIR = ROOT / "images"
OUTPUT_FILE = ROOT / "import_task.jsonl"

# 图片在 OSS 中的路径前缀
IMAGE_PREFIX = "image-search/picsum/images"

# Lorem Picsum 公开 API
LIST_URL = "https://picsum.photos/v2/list?page=1&limit=100"
IMAGE_SIZE = "800/600"

IMAGE_DIR.mkdir(exist_ok=True)

# 获取图片列表
with urllib.request.urlopen(LIST_URL) as resp:
    items = json.loads(resp.read().decode("utf-8"))

# 生成 JSONL 文件
with OUTPUT_FILE.open("w", encoding="utf-8") as out:
    for index, item in enumerate(items, start=1):
        source_id = int(item["id"])
        image_id = f"picsum_{source_id:06d}"
        file_name = f"{image_id}.jpg"
        local_path = IMAGE_DIR / file_name
        image_url = f"https://picsum.photos/id/{source_id}/{IMAGE_SIZE}"

        # 下载图片到本地
        if not local_path.exists():
            print(f"正在下载 {image_url}")
            urllib.request.urlretrieve(image_url, local_path)

        # 写入 JSONL 记录
        record = {
            "image_id": image_id,
            "image_uri": f"{IMAGE_PREFIX}/{file_name}",
            "action": "ADD",
            "tags": {
                "dataset": "picsum",
                "source_id": source_id,
                "author": item.get("author", ""),
                "sample_index": index,
                "width": 800,
                "height": 600,
            },
        }
        out.write(json.dumps(record, ensure_ascii=False) + "\n")

print(f"已生成 {OUTPUT_FILE}")

执行脚本并检查输出:

python3 prepare_picsum_data.py
head -n 3 import_task.jsonl

生成的 JSONL 文件中每行为一条 JSON 记录,格式如下:

{"image_id": "picsum_000000", "image_uri": "image-search/picsum/images/picsum_000000.jpg", "action": "ADD", "tags": {"dataset": "picsum", "source_id": 0, "author": "Alejandro Escamilla", "sample_index": 1, "width": 800, "height": 600}}

JSONL 记录中各字段说明如下:

字段

类型

说明

image_id

string

图片唯一标识。

image_uri

string

图片在 OSS Bucket 中的对象路径。

action

string

操作类型,ADD 表示添加图片。

tags

object

自定义标签键值对,用于检索时的过滤。

images/ 目录下的图片和 import_task.jsonl 文件上传到同一个 OSS Bucket。上传可通过 OSS 控制台、ossutil 或 OSS SDK 完成。

上传完成后,请确认 OSS 中存在以下对象:

image-search/picsum/images/picsum_000000.jpg
image-search/picsum/import_task.jsonl

步骤二:创建图片库

  1. 创建 general_search 模式的图片库,并声明后续入库和过滤会使用的标签字段。

    curl -X POST "$API_PREFIX/library/create" \
      -H 'Content-Type: application/json' \
      -d "{
        \"library_name\": \"$LIBRARY_NAME\",
        \"mode\": \"general_search\",
        \"description\": \"Lorem Picsum public images for image search demo\",
        \"tag_schema\": [
          {\"name\": \"dataset\", \"type\": \"string\"},
          {\"name\": \"source_id\", \"type\": \"int\"},
          {\"name\": \"author\", \"type\": \"string\"},
          {\"name\": \"sample_index\", \"type\": \"int\"},
          {\"name\": \"width\", \"type\": \"int\"},
          {\"name\": \"height\", \"type\": \"int\"}
        ]
      }"
    

    创建请求提交成功后,返回结果示例如下:

    {
      "status": "SUCCESS",
      "message": null,
      "data": {
        "library_name": "picsum_general_search",
        "status": "initing"
      }
    }
    

    data.statusiniting 表示图片库正在初始化。初始化完成后状态会变为 ready。图片库创建后不能修改工作模式和标签字段,如需调整,请删除后重新创建。

  2. 调用图片库列表接口,确认目标图片库状态为 ready 后再继续后续操作。

    curl -X GET "$API_PREFIX/library/list"
    

    返回结果示例:

    {
      "status": "SUCCESS",
      "message": null,
      "data": {
        "total": 1,
        "libraries": [
          {
            "library_name": "picsum_general_search",
            "mode": "general_search",
            "image_count": 0,
            "status": "ready",
            "message": null,
            "description": "Lorem Picsum public images for image search demo"
          }
        ]
      }
    }
    
    说明

    如果目标图片库的 status 仍为 initing,请等待后重试。如果为 failed,请查看返回的 message 字段获取失败原因,并重新创建图片库。

步骤三:导入图片

使用 OSS 上的 JSONL 文件创建异步批量导入任务:

curl -X POST "$API_PREFIX/image/tasks/create" \
  -H 'Content-Type: application/json' \
  -d "{
    \"library_name\": \"$LIBRARY_NAME\",
    \"meta_file_uri\": \"oss://$OSS_BUCKET/$OSS_PREFIX/import_task.jsonl\",
    \"save_image\": false
  }"

成功后返回任务 ID:

{
  "status": "SUCCESS",
  "message": null,
  "data": {
    "task_id": "task_x9y8z7w6v5"
  }
}

记录返回的 task_id,使用该 ID 查询导入进度:

export TASK_ID="task_x9y8z7w6v5"

curl -X GET "$API_PREFIX/image/tasks/results/$TASK_ID"

当任务完成且全部图片处理成功时,返回结果示例如下:

{
  "status": "SUCCESS",
  "message": null,
  "data": {
    "task_id": "task_x9y8z7w6v5",
    "task_status": "SUCCESS",
    "total": 100,
    "processed": 100,
    "failed_count": 0,
    "message": null
  }
}
说明

本文将 save_image 设置为 false,检索结果中不返回图片的 Base64 原始数据,仅返回 image_uri、相似度分数和标签信息。如需在检索结果中直接返回图片内容,请设置为 true

如果 failed_count 大于 0,请依次检查以下内容:

  • JSONL 文件格式是否正确(每行一条 JSON 记录)。

  • image_uri 路径对应的图片是否已上传到 OSS。

  • 图片搜索服务是否具有读取 OSS 对象的权限。

  • 标签字段是否与创建图片库时声明的 tag_schema 一致。

步骤四:以文搜图

创建请求生成脚本 search_by_text.py,用于构造以文搜图的请求体:

import json
import os
import sys

query_text = " ".join(sys.argv[1:]) or "a macbook"
payload = {
    "library_name": os.environ.get("LIBRARY_NAME", "picsum_general_search"),
    "query_text": query_text,
    "top_k": 3,
    "tag_filter": [
        {"field": "dataset", "op": "=", "value": "picsum"},
    ],
    "return_frame": False,
}
print(json.dumps(payload, ensure_ascii=False))

执行以文搜图请求:

python3 search_by_text.py "a macbook" | \
  curl -X POST "$API_PREFIX/search/by-text" \
    -H 'Content-Type: application/json' \
    -d @-

响应中 results 按相似度分数从高到低排列。以查询文本 a macbook 为例,返回的图片如下:

以文搜图效果:查询 a macbook 的返回结果

请求参数说明:

参数

说明

query_text

搜索文本描述。支持多语言输入。

top_k

返回的最大结果数量,默认为 10。

tag_filter

标签过滤条件,支持精确匹配、包含匹配和逻辑组合(AND/OR)。

return_frame

是否在结果中返回图片的 Base64 编码内容。设为 false 可减少传输量。

说明

返回结果中的 tags 会包含图片库的完整标签列,除创建图片库时声明的标签字段外,也可能包含 int_tag1int_tag5str_tag1str_tag5 等内部预留标签字段,未写入值的字段通常为 null。业务展示时可以忽略这些预留字段。

步骤五:以图搜图

创建请求生成脚本 search_by_image.py,用于读取本地图片并构造以图搜图的请求体:

import base64
import json
import os
import sys
from pathlib import Path

query_image = Path(sys.argv[1])
payload = {
    "library_name": os.environ.get("LIBRARY_NAME", "picsum_general_search"),
    "image_base64": base64.b64encode(query_image.read_bytes()).decode("utf-8"),
    "top_k": 3,
    "tag_filter": [
        {"field": "dataset", "op": "=", "value": "picsum"},
    ],
    "return_frame": False,
}
print(json.dumps(payload, ensure_ascii=False))

执行以图搜图请求:

python3 search_by_image.py images/picsum_000000.jpg | \
  curl -X POST "$API_PREFIX/search/by-image" \
    -H 'Content-Type: application/json' \
    -d @-

本示例使用的查询图片如下:

以图搜图的查询图片

成功响应示例:

{
  "status": "SUCCESS",
  "message": null,
  "data": {
    "results": [
      {
        "image_id": "picsum_000000",
        "image_uri": "image-search/picsum/images/picsum_000000.jpg",
        "image_base64": null,
        "score": 1.0000,
        "tags": {
          "dataset": "picsum",
          "source_id": 0,
          "author": "Alejandro Escamilla",
          "sample_index": 1,
          "width": 800,
          "height": 600
        }
      }
    ]
  }
}

服务返回的视觉最相似图片如下(Top-K):

以图搜图效果:查询图片的返回结果

说明

如果查询图片本身在图片库中,通常会优先返回自身(相似度分数为 1.0)或高度相似的图片。如果查询图片不在图片库中,服务会返回视觉或语义上最接近的图片。

清理资源

如不再需要示例图片库,可删除图片库释放资源:

curl -X POST "$API_PREFIX/library/delete" \
  -H 'Content-Type: application/json' \
  -d "{
    \"library_name\": \"$LIBRARY_NAME\"
  }"
警告

删除图片库会同时删除库内所有图片数据,操作不可恢复。OSS 上的图片文件和 JSONL 文件不会被自动删除,如需释放 OSS 存储空间,请单独清理。

相关文档