借助 EMR Serverless StarRocks 实现电商平台图搜图、文搜图场景

简介: 本文介绍如何基于 EMR Serverless StarRocks 构建统一的多模态电商搜索系统,通过内置 AI Function 实现图搜图与文搜图场景的一体化处理:利用 Object Table 直接挂载 OSS 图片,结合 HNSW/IVFPQ 向量索引与结构化字段联合查询,将图片/文本向量化、ANN 检索、业务过滤(价格、库存、类目等)全部收敛至单条 SQL,消除多系统割裂与数据延迟问题,显著提升搜索实时性、准确性和工程效率。

一、背景

电商搜索这些年走过三个阶段:关键词搜索、语义搜索、多模态搜索。今天用户的期待已经很直接——拍一张图就要找到同款,打一句"米白色宽松棉麻衬衫"就要出对的货。

这背后是两个高频场景。

  • 图搜图:用户上传或拍摄一张商品图,系统找出同款与相似款,支撑拍照购物、比价购物、以图找店
  • 文搜图:用户输入一句自然语言描述,系统直接匹配符合描述的商品主图,即使商品标题里根本没有"棉麻""宽松"这些词。

问题在于,这两件事传统上都很难落在同一套系统里。

  • 商品主图有几千万张、存在 OSS;
  • 向量要另建一套向量库;
  • 搜索结果又必须和价格、库存、类目、评分这些业务属性联合过滤——"找相似款"没有意义,"找有货、300 元以内、评分 4 分以上的相似款"才有意义。

于是团队维护两套系统、写两套链路,向量库里没有业务字段,OLAP 库里没有向量,中间靠应用层来回捞数据拼结果。商品换了主图,向量更新延迟几小时,搜索出来还是旧款。


二、整体技术架构

基于 EMR Serverless StarRocks,用 StarRocks AI Function 在库内直接调用多模态模型,把"OSS 图片 → 向量 → 混合检索 → 业务过滤与排序"整条链路收敛成标准 SQL。图片原图不出 OSS,用 Object Table 挂载增量文件;向量与商品业务属性同库存储,向量检索与结构化过滤在一条 SQL 里原生融合。

核心能力有:

  • ai_embed_multimodal(file, 'image') 把商品主图编码成向量;
  • ai_embed_multimodal(text, 'text') 把用户的自然语言查询编码到同一向量空间——这是文搜图能跨模态命中图片向量的关键;
  • approx_cosine_similarity 在向量索引上做 ANN 检索,配合 WHERE 里的价格、库存、类目条件,一条 SQL 出最终结果。

支持的算法与索引选型

数据源 索引类型 距离度量 典型特点 推荐场景
StarRocks 内表 HNSW L2、余弦相似度 低延迟、高召回;索引体积和内存占用相对较高 线上主搜、秒级响应的图搜图/文搜图
StarRocks 内表 IVFPQ L2、余弦相似度 通过聚类和乘积量化降低索引体积;通常需要精排以提高最终精度 亿级 SKU、成本与内存敏感
DLF Paimon 湖表 Lumina Global Index L2、余弦相似度、内积 数据保留在湖表;支持分片并行召回及结构化 Global Index 预过滤 全量商品资产留湖、多引擎共享、离线大批量召回
用户侧
  ├── 上传图片(图搜图)
  └── 输入文字描述(文搜图)
          │
          ▼
应用服务层
  ├── 图片预处理(裁剪 / 归一化)
  └── 调用 StarRocks AI Function 实时向量化
          │
          ▼
StarRocks Stella 2.2
  ├── 商品多模态表(SKU 信息 + 图像向量 + 文本向量)
  ├── ANN 向量索引(HNSW / IVF)
  └── AI Function:AI_EMBED(image / text, model)
          │
          ▼
结果处理层
  ├── Top-K 相似商品列表
  ├── 联合业务规则过滤(价格区间 / 库存 / 类目)
  └── 结果排序与展示

三、实践步骤

第一步,用 Object Table 挂载 OSS 商品图片。

主图按类目/年月目录沉淀在 OSS,建 Object Table 把对象映射进来,file 描述符直接交给 AI 函数、签名地址由系统自动生成,SQL 里不出现 AK/SK。

SET CATALOG default_catalog;
CREATE DATABASE IF NOT EXISTS ec_search;

CREATE OBJECT TABLE ec_search.obj_product_images PROPERTIES (
  "path" = "oss://<BUCKET>/product/images/",
  "aliyun.oss.endpoint" = "oss-cn-hangzhou-internal.aliyuncs.com",
  "aliyun.oss.public_endpoint" = "oss-cn-hangzhou.aliyuncs.com",
  "aliyun.oss.access_key" = "<AK>",
  "aliyun.oss.secret_key" = "<SK>",
  "recursive" = "true",
  "file_pattern" = ".*\\.(jpg|jpeg|png|webp)$"
);
REFRESH OBJECT TABLE ec_search.obj_product_images;

Object Table 固定 8 列(object_uri/etag/size/last_modified/content_type/storage_class/refresh_id/file),其中 etag 是做增量水位的关键——主图被替换后 etag 变化,会自动触发重新向量化。

第二步,建商品多模态表并规划向量索引。

线上主搜用内表,向量列必须是 NOT NULL 的 ARRAY<FLOAT>,表模型为 Primary Key 或 Duplicate Key;

CREATE TABLE ec_search.product_image_search (
  sku_id       BIGINT NOT NULL,
  spu_id       BIGINT,
  title        VARCHAR(1024),
  category     VARCHAR(64),
  brand        VARCHAR(64),
  price        DECIMAL(10,2),
  stock        INT,
  rating       FLOAT,
  sales_30d    BIGINT,
  object_uri   VARCHAR(1024),          -- 关联 OSS 主图
  etag         VARCHAR(256),           -- 主图版本,做增量幂等
  image_vector ARRAY<FLOAT> NOT NULL,  -- 多模态图像向量,2560 维
  updated_at   DATETIME,
  INDEX idx_image_vec (image_vector) USING VECTOR (
    "index_type"       = "hnsw",
    "dim"              = "2560",
    "metric_type"      = "cosine_similarity",
    "is_vector_normed" = "false",
    "M"                = "16",
    "efconstruction"   = "200"
  )
) PRIMARY KEY (sku_id)
DISTRIBUTED BY HASH(sku_id) BUCKETS 32;

按检索路径分表:product_image_search 承载图像向量(服务图搜图 + 文搜图,因为文本查询向量与图像同空间),另建 product_text_search 用 ai_embed 的 1024 维文本向量服务"文搜文"。

若全量商品向量要留在湖上供多引擎共享,则落 DLF Paimon 表。

-- StarRocks 可写:parquet + partial-update,便于只回写向量或业务列
CREATE TABLE dlf_catalog.`default`.product_vectors (
  sku_id BIGINT, object_uri STRING, etag STRING,
  category STRING, brand STRING, price DECIMAL(10,2), stock INT,
  image_vector ARRAY<FLOAT>, updated_at TIMESTAMP
) ENGINE = paimon
PROPERTIES ("file.format"="parquet","primary-key"="sku_id",
            "merge-engine"="partial-update","bucket"="4");

第三步,批量向量化入库,去重在 AI 函数之前。

把 Object Table 的 file 交给 ai_embed_multimodal,并用 object_uri + etag 做 LEFT ANTI JOIN 过滤已处理主图:

INSERT INTO ec_search.product_image_search
  (sku_id, spu_id, title, category, brand, price, stock, rating, sales_30d,
   object_uri, etag, image_vector, updated_at)
SELECT
  p.sku_id, p.spu_id, p.title, p.category, p.brand, p.price, p.stock, p.rating, p.sales_30d,
  o.object_uri, o.etag,
  ai_embed_multimodal(o.file, 'image') AS image_vector,
  now()
FROM ec_search.obj_product_images o
JOIN ec_search.dim_product p
  ON p.image_key = regexp_extract(o.object_uri, '.*/(.+)$', 1)
LEFT ANTI JOIN ec_search.product_image_search t
  ON t.object_uri = o.object_uri AND t.etag = o.etag
WHERE object_file_is_image(o.file);

-- 校验:向量非空、维度与索引 dim 一致
SELECT COUNT(*) AS total,
       SUM(IF(image_vector IS NOT NULL AND array_length(image_vector)=2560,1,0)) AS valid_vec
FROM ec_search.product_image_search;

第四步,图搜图。

关键点:要命中向量索引,查询向量必须是优化阶段可确定的常量数组。所以线上是两步——应用层先调一次向量化拿到数组,再作为字面量拼进检索 SQL:

-- ① 先取查询向量(用户上传图的公读或签名 URL)
SELECT ai_embed_multimodal('https://<BUCKET>.oss-cn-hangzhou.aliyuncs.com/upload/q.jpg', 'image');

-- ② 用常量向量做 ANN 检索 + 业务条件过滤(余弦降序 + LIMIT)
SELECT sku_id, title, category, price, rating, object_uri,
       approx_cosine_similarity(image_vector, [0.0131, -0.0247, /* …2560 维字面量… */]) AS score
FROM ec_search.product_image_search
WHERE stock > 0
  AND category = '女装'
  AND price BETWEEN 100 AND 500
  AND rating >= 4.0
ORDER BY score DESC
LIMIT 20;

第五步,文搜图(跨模态)。

用户输入的文字用同一个多模态模型编码成 2560 维向量,直接与商品的 image_vector 比相似度——这就是跨模态检索:

-- ① 文本编码到与图像同一空间(2560 维)
SELECT ai_embed_multimodal('米白色宽松棉麻衬衫', 'text');

-- ② 用文本向量检索图像向量(跨模态)+ 属性过滤
SELECT sku_id, title, brand, price, object_uri,
       approx_cosine_similarity(image_vector, [/* 上一步的 2560 维常量 */]) AS score
FROM ec_search.product_image_search
WHERE stock > 0
  AND category IN ('衬衫','女士衬衫')
  AND price < 2000
ORDER BY score DESC
LIMIT 20;

如果要做"文搜文"(按标题、属性描述做同模态语义搜索),用 ai_embed 的 1024 维向量、在独立的文本向量表上检索——不要与 2560 维图像向量混算。

高频查询词的查询向量建议在应用层缓存,避免重复调用模型。

第六步,融合排序与多路召回。

向量相似度只是排序信号之一,线上通常还要叠加评分、销量、活动权重:

SELECT sku_id, title, price, rating, sales_30d,
       0.7 * approx_cosine_similarity(image_vector, [/* qv */])
     + 0.2 * (rating / 5.0)
     + 0.1 * LOG(sales_30d + 1) / 10 AS final_score
FROM ec_search.product_image_search
WHERE stock > 0
ORDER BY final_score DESC
LIMIT 20;

注意:要命中 TopK 向量索引,ORDER BY 只能包含单个近似距离表达式。上面这种加权融合会使索引不生效,适合作为精排层——正确做法是先用纯 approx_cosine_similarity 索引召回 Top-200 到 CTE,再在 CTE 上做加权重排。

多路召回(图像向量召回 + 文本向量召回 + 关键词倒排召回)用 RRF 融合,各路各自 ROW_NUMBER() 出排名后按 SUM(1/(k+rank)) 打分;ORDER BY 用裸别名,不要带表前缀:

WITH img_recall AS (
  SELECT sku_id, ROW_NUMBER() OVER (ORDER BY approx_cosine_similarity(image_vector,[/* qv_img */]) DESC) AS r
  FROM ec_search.product_image_search WHERE stock>0 ORDER BY r LIMIT 200),
txt_recall AS (
  SELECT sku_id, ROW_NUMBER() OVER (ORDER BY approx_cosine_similarity(text_vector,[/* qv_txt */]) DESC) AS r
  FROM ec_search.product_text_search WHERE stock>0 ORDER BY r LIMIT 200),
fused AS (
  SELECT sku_id, SUM(1.0/(60+r)) AS rrf
  FROM (SELECT sku_id,r FROM img_recall UNION ALL SELECT sku_id,r FROM txt_recall) u
  GROUP BY sku_id)
SELECT f.sku_id, p.title, p.price, ROUND(f.rrf,5) AS rrf_score
FROM fused f JOIN ec_search.product_image_search p ON f.sku_id=p.sku_id
ORDER BY rrf_score DESC LIMIT 20;

第七步,湖表检索与增量更新。

在 DLF Paimon 湖表上检索时同样用近似函数与常量向量;查询向量要用原生数组字面量,具备兼容 Bitmap/BTree Global Index 的结构化条件会作为 Prefilter 下推,其余作为 Postfilter 执行:

SELECT sku_id, approx_cosine_similarity(image_vector, [/* 常量向量 */]) AS score
FROM dlf_catalog.`default`.product_vectors
WHERE category = '女装' AND stock > 0
ORDER BY score DESC LIMIT 20;

增量维护上,新品与换图都靠 object_uri + etag 的 anti-join 自动纳入,周期调度执行 REFRESH OBJECT TABLE → 向量化 INSERT 即可;ANN 索引支持增量构建,无需全量重建,大批量回填建议低峰执行。

四、实施成效

方案落地后,最直接的变化是商品图片第一次变成了可被语义检索的资产,而且检索天然带业务约束。

  • 图搜图与文搜图共用同一份图像向量与同一条检索链路,不需要为跨模态单独建库;
  • "有货 + 类目 + 价格区间 + 评分"这些条件在召回阶段就生效,不再出现召回 20 条过滤剩 3 条的空结果;商品换主图后靠 etag 自动触发重新向量化,搜索结果不再滞后;
  • 向量与业务属性同库,运维从两套系统收敛为一套。

归纳起来四点收益。

  • 架构上,向量库与 OLAP 库合一,减少一套系统的部署、同步与故障面。
  • 效果上,向量检索与结构化过滤原生融合,搜索结果直接可用于展示与排序。
  • 成本上,object_uri + etag 增量水位保证只对新增和换图的 SKU 调用模型,存量不重复推理。安全上,商品图片不导出到第三方,在库内完成加工与检索。

五、 总结

通过 StarRocks,把多模态模型能力以 SQL 函数的形式嵌入混合搜索链路,构建了"OSS 图片挂载 → 向量化入库 → ANN 索引 → 图搜图 / 文搜图 → 业务过滤与融合排序"的全链路闭环。

图片不出 OSS,向量与业务数据同库,推理即查询——用一套 SQL 同时支撑拍照购物与自然语言找货。

同一套模板还可平移到 UGC 图文匹配、以图找店、盗图与侵权检测、同款比价、素材去重等场景。对于同样面临"图片在对象存储、检索要带业务条件、还不想多维护一套向量库"的团队,StarRocks 提供了一条清晰的落地路径——会写 SQL,就能做多模态搜索。

相关文章
|
5月前
|
存储 搜索推荐 API
阿里云图像搜索完整对接指南:从开通到API/SDK深度集成
本文系统性地讲解了阿里云图像搜索(Image Search)服务的完整对接流程与使用方法。首先介绍了图像搜索的核心概念——以深度学习和机器视觉技术为基础,通过提取图片内容特征实现相似性检索。随后详细说明了开通服务的完整步骤,包括账号注册、实名认证、AccessKey获取以及购买实例时的关键配置项(地域、服务类型、QPS、最大容量等)。接着深入讲解了控制台的核心操作:实例创建、图片新增(含商品ID、图片名称、主体识别等参数)、以及相似图片搜索(SearchByPic与SearchByName两种模式)。在技术对接层面,文章提供了Java SDK与Python SDK的完整代码示例,涵盖Add、S
|
26天前
|
人工智能 前端开发 小程序
我把女儿的作文改成了游戏
我用AI把女儿的作文改编成了小游戏。
|
26天前
|
物联网 API 知识图谱
类Jev项目Kev从入门到实战(7):如何选型:决策树与 checklist
本文详解决策树模型选型逻辑:聚焦“分类/打分/路由”任务,通过结构化决策树与6项实测checklist(含零样本验证、微调可行性、显存匹配等),指导选用Kev(可微调)或Jev(零样本强)。强调“任务形状先行”,拒绝盲目套用大模型。
187 1
|
29天前
|
人工智能 运维 前端开发
接入多家模型供应商之后,我总结的 7 条铁律
AI 应用接了第二家模型供应商之后,事情就不再是"多加一个接口"那么简单——不是调不通,是钱会算错。这篇讲我们定下来的 7 条规则:幂等键、任务落库时机、备用线路的切换边界、退款、凭据隔离、付款来源固化、密钥不进浏览器。
|
18天前
|
人工智能 关系型数据库 知识图谱
我们做了一次横评:五大 RAG 方案在四个场景下的真实表现
ContextDB 团队开展了一次客观、多维度的 RAG 方案横向评测,对比自身方案与 PageIndex、HippoRAG 2、LightRAG、OpenViking 在四大真实场景(金融、教学、学术、常识)下的准确率、Token 成本、延迟及跨场景稳定性,强调数据说话、局限自陈,助力开发者理性选型。
221 0
|
2月前
|
JSON 自然语言处理 物联网
基于魔搭 MS-Swift 实现大模型微调落地指南
MS-Swift是阿里达摩院魔搭社区开源的一站式大模型开发框架,支持预训练、微调、对齐、推理、量化与部署全链路,兼容600+文本及300+多模态模型,助力企业高效落地Agent定制。
394 2
|
2月前
|
人工智能 监控 JavaScript
最近火爆出圈的,FDE 到底是个什么岗位?
FDE(前沿部署工程师)是AI时代新型复合岗:驻客户现场,贯通技术与业务,主导大模型在真实场景的端到端落地。需兼具AI应用开发、工程化交付与业务沟通三大能力,非单纯“调API”或售前角色。高薪热门,但重实战、重结果。
2559 2
最近火爆出圈的,FDE 到底是个什么岗位?
|
29天前
|
API 异构计算
类Jev项目Kev从入门到实战(6):Jev / Kev / Laya 对比
Jev闭源不可训,Laya轻量但微调难,Kev是唯一支持本地微调的开源方案(Apache-2.0),兼容Jev API,可将业务规则、领域知识注入模型,真正实现“数据进模型”。
387 0
|
3月前
|
人工智能 搜索推荐 算法
FDE前沿部署工程师的两种范式:技术纵深型 vs 场景应用型
FDE(前沿部署工程师)是AI产业化落地的关键角色,已分化为技术纵深型与场景应用型两大范式:前者攻坚底层工程与私有化部署,后者聚焦业务适配与商业闭环。二者互补协同,共同破解AI落地难、转化低等核心痛点,成为2026年高薪紧缺的标准化核心岗位。
1066 0
|
4月前
|
人工智能 分布式计算 Serverless
EMR Serverless Daft 如何简化多模态数据处理:视频抽帧、清洗、标注全流程与具身智能实践
阿里云 EMR Serverless Spark 引入 Ray 分布式计算框架与 Daft 高性能数据引擎,为用户提供了一套开箱即用、免运维且极致高效的多模态数据处理基础设施。