搞过图像检索的人都知道那条老路:先搭一套计算机视觉服务,再部署一个向量数据库,接着写数据同步管道把特征向量灌进去,最后还得维护一套查询网关把文本和图像对齐。整套下来,技术栈至少横跨三四个框架,运维成本远超业务本身的价值。
MySQL HeatWave GenAI 正在把这条路径压扁——图像理解、向量生成、语义检索,全部收进 SQL 工作流里完成。不需要外部向量数据库,不需要单独的 ML pipeline,一条 SELECT 就能跑语义搜索。这篇文章带你用 HeatWave GenAI 搭一个图像语义理解平台的骨架,目标不是再做一个分类器,而是让数据库本身具备"看懂图片、按语义找图"的能力。
从"存图"到"懂图":数据库角色的变化
传统方案里,MySQL 只负责存 BLOB 或存图片 URL,"理解"这件事完全交给外部服务。HeatWave GenAI 的思路不同:它把多模态嵌入模型的推理能力内嵌到数据库引擎中,通过 ML_EMBED、ML_GENERATE 等内置 AI routine 直接在 SQL 里生成向量。
这意味着三件事变了:
- 向量存储不再需要外部数据库——HeatWave 本身支持向量列类型和向量索引,嵌入向量直接存在行里,和元数据同表共存。
- 特征提取不再需要单独的推理服务——调用
ML_EMBED时,HeatWave 内部调度模型推理,无需你管理 GPU 或模型权重。 - 语义检索变成一条 SQL——向量距离计算是内置操作,不需要写 HTTP 请求去查 Milvus 或 Pinecone。
对已经用 MySQL 作为主存储的团队来说,这是最短的落地路径:数据不动,能力加进来。
搭建图像语义搜索的核心步骤
整个流程可以拆成四步:建表、灌数据、生成嵌入、语义查询。下面逐一展开,并给出可以直接跑的 SQL。
第 1 步:建一张能存向量的图片表
HeatWave 支持向量列(VECTOR 类型),维度取决于你选的嵌入模型。以常用的多模态模型为例,输出维度通常是 512 或 768。建表时直接声明:
CREATE TABLE vision_images (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
file_name VARCHAR(255) NOT NULL,
description TEXT,
image_url VARCHAR(512),
embedding VECTOR(768) -- 与所选嵌入模型的输出维度一致
);
description 和 image_url 是业务字段,embedding 列存模型推理出的向量。三者同表,后续查询时不需要跨库 JOIN。
第 2 步:灌入图片元数据
这一步和普通 INSERT 没区别,先把业务数据写进去:
INSERT INTO vision_images (file_name, description, image_url) VALUES
('cat_sofa.jpg', '一只橘猫躺在灰色沙发上打盹', 'https://storage.example.com/img/cat_sofa.jpg'),
('city_night.jpg', '雨夜城市街景,霓虹灯倒映在湿路面', 'https://storage.example.com/img/city_night.jpg'),
('mountain_lake.jpg','高山湖泊,清晨薄雾笼罩水面', 'https://storage.example.com/img/mountain_lake.jpg');
第 3 步:用内置 AI routine 生成嵌入向量
这是关键一步。HeatWave GenAI 的 ML_EMBED routine 可以直接对文本或图像内容做嵌入推理。对于图像语义搜索,通常的做法是对图片的文本描述(或图片本身,取决于模型能力)生成向量,然后写回 embedding 列:
UPDATE vision_images v
SET v.embedding = ML_EMBED(
JSON_OBJECT('model', 'multimodal-embedding-v1',
'input', v.description),
JSON_OBJECT('task', 'semantic-search')
);
这条 SQL 做了两件事:读取每行的 description 字段,调用 HeatWave 内置的多模态嵌入模型,把输出的 768 维向量写回同一行的 embedding 列。不需要 Python 脚本、不需要 API 调用、不需要批量导出再导入。
如果你的模型支持直接吃图像 URL(HeatWave GenAI 的多模态模型正在朝这个方向演进),input 参数可以换成图像 URL 或 BLOB,让模型直接从像素提取语义特征,跳过文本描述的中间层。
第 4 步:语义查询——用自然语言找图
现在表里已经有向量了,语义搜索只需要一条 SQL。先对查询文本生成嵌入,再算向量距离:
-- 用自然语言查询,返回语义最接近的 5 张图
SELECT v.id, v.file_name, v.description, v.image_url,
VECTOR_DISTANCE(v.embedding,
ML_EMBED(
JSON_OBJECT('model', 'multimodal-embedding-v1',
'input', '安静的室内场景'),
JSON_OBJECT('task', 'semantic-search')
)) AS distance
FROM vision_images v
ORDER BY distance ASC
LIMIT 5;
VECTOR_DISTANCE 是 HeatWave 内置的向量距离函数,默认计算余弦距离。ML_EMBED 在查询时实时生成查询向量,不需要预计算。整条 SQL 从生成查询向量到排序返回,一次完成。
结果大致会是:
| file_name | description | distance |
|---|---|---|
| cat_sofa.jpg | 一只橘猫躺在灰色沙发上打盹 | 0.12 |
| mountain_lake.jpg | 高山湖泊,清晨薄雾笼罩水面 | 0.34 |
| city_night.jpg | 雨夜城市街景... | 0.71 |
"安静的室内场景"语义上最接近猫在沙发上打盹,这正是语义搜索该有的表现——它不是关键词匹配,而是理解意图。
用 Python 把流程串成可复用的服务
SQL 能跑,但生产环境通常需要一个服务层。下面是一个最小可用的 Python 示例,用 mysql-connector-python 把语义查询封装成 HTTP 接口:
import json
from flask import Flask, request, jsonify
import mysql.connector
app = Flask(__name__)
def get_db():
return mysql.connector.connect(
host="heatwave-host",
user="vision_user",
password="your_password",
database="vision_db"
)
@app.route("/search", methods=["POST"])
def semantic_search():
"""接收自然语言查询,返回语义最接近的图片列表"""
query_text = request.json.get("query", "")
top_k = request.json.get("top_k", 5)
sql = """
SELECT v.id, v.file_name, v.description, v.image_url,
VECTOR_DISTANCE(v.embedding,
ML_EMBED(
JSON_OBJECT('model', 'multimodal-embedding-v1',
'input', %s),
JSON_OBJECT('task', 'semantic-search')
)) AS distance
FROM vision_images v
ORDER BY distance ASC
LIMIT %s
"""
conn = get_db()
cursor = conn.cursor(dictionary=True)
cursor.execute(sql, (query_text, top_k))
results = cursor.fetchall()
cursor.close()
conn.close()
return jsonify({"query": query_text, "results": results})
if __name__ == "__main__":
app.run(host="0.0.0.0", port=5000)
启动后,一行 curl 就能测:
curl -X POST http://localhost:5000/search \
-H "Content-Type: application/json" \
-d '{"query": "安静的室内场景", "top_k": 3}'
这个示例假设 HeatWave GenAI 的 ML_EMBED 和 VECTOR_DISTANCE 已在实例上启用,且 multimodal-embedding-v1 模型已加载。实际部署时,模型名称和参数需对照你实例上的可用模型列表调整——可以用 SHOW ML_MODELS; 或查阅 HeatWave 文档确认。
语义理解 vs 分类:为什么这不是"又做一个分类器"
原文特别强调了一个定位差异:这个平台的目标是语义理解,不是分类。
分类器回答的是"这张图属于哪个预设类别",语义搜索回答的是"这张图和这段话在意思上有多近"。后者的灵活性远高于前者:
- 你不需要预先定义类别体系。用户想搜"适合做壁纸的风景",分类器没有这个类,语义搜索可以直接理解。
- 同一张图可以从多个语义角度被检索。猫的图片既匹配"宠物",也匹配"室内安静场景",分类器只能给一个标签。
- 新查询意图零成本上线。不需要重新训练,不需要加类别,直接写新的查询文本。
当然,语义搜索的精度取决于嵌入模型的质量。对于高度专业化的领域(比如医学影像的特定病理识别),通用多模态模型可能不够,需要领域微调或补充规则过滤——这是下一段要说的边界。
落地前需要想清楚的几件事
模型选择与维度对齐。 HeatWave GenAI 内置了多个嵌入模型,不同模型的输出维度和语义空间不同。建表时 VECTOR 列的维度必须和模型输出一致,一旦选错,后续 ML_EMBED 的结果写不进去。建议先用 ML_EMBED 对一条样本数据跑一次,确认维度后再建表。
图像直接嵌入 vs 文本代理嵌入。 当前示例用图片的文本描述生成向量,这是最稳定的起步方式。如果 HeatWave 实例上的多模态模型支持直接吃图像数据,可以跳过文本描述,让模型从像素提取特征——语义精度会更高,但推理成本也更大。建议从文本代理开始,验证流程后再切换到图像直入。
规模与索引。 几千张图不需要索引,VECTOR_DISTANCE 全表扫描够快。到了十万级以上,需要创建向量索引(HeatWave 支持 VECTOR INDEX),否则查询延迟会线性增长。建索引的语法类似:
CREATE VECTOR INDEX vimg_emb_idx ON vision_images (embedding);
成本与延迟。 ML_EMBED 每次调用都触发模型推理。批量灌数据时,用 UPDATE 一次性生成所有行的嵌入是合理的;但在高频查询场景下,每次查询都实时 ML_EMBED 查询文本会带来额外延迟。可以考虑在应用层缓存常见查询的嵌入向量,减少推理调用次数。
不是所有图像任务都适合。 如果你的需求是像素级匹配、OCR 精确提取、或特定目标的边界框检测,语义嵌入不是正确工具——这些任务仍然需要专门的 CV 模型。HeatWave GenAI 解决的是"语义层面的理解和检索",不是替代所有视觉 AI。
一句话总结:MySQL HeatWave GenAI 把图像语义搜索从"四个系统拼起来"压缩到"一条 SQL 搞定"。如果你的主存储已经是 MySQL,这是目前最省运维成本的图像语义检索落地路径。从文本代理嵌入起步,验证流程,再逐步切换到图像直入和向量索引——每一步都在 SQL 里完成,不需要换技术栈。