跨商店聚类的核心挑战与目标
Shopify平台承载着数百万家店铺中的数十亿商品列表,商家拥有极大的自由来组织其目录结构。然而,这种灵活性在需要处理整个平台目录时成为了挑战。不同的商品列表可能代表同一款实物产品,为了向买家、开发者和AI代理提供统一的产品视图及店铺信息,Shopify Catalog构建了一个标准化的智能层。其核心机制是产品聚类(Product Clustering),旨在将不同商家以不同方式构建的同一实物项归入同一个通用产品标识符(UPID)下。
在上一部分中,我们讨论了如何在单个店铺内将相关列表分组。但Shopify Catalog需要解决更复杂的问题:当不同商家销售相同产品或其变体时,如何确认它们是同一物品? 这就是跨商店聚类。店内方法无法直接迁移至店间,因为不同商家的命名习惯、品牌描述及变体区分方式各异。例如,一个商家可能在标题中包含型号,而另一个则将其埋在描述中;条形码虽有帮助,但并不总是可用或可靠。此外,搜索空间不再局限于单一商家,而是需要在数十亿列表中寻找匹配项,且不能比较所有可能的配对。
"Rather than asking an LLM to assign globally consistent product labels, we ask a narrower question: should these two product listings belong to the same UPI?"
从成对比较到全局聚类的系统架构
为了解决上述挑战,系统不再要求大语言模型(LLM)直接分配全局一致的产品标签,而是采用更窄义的问题:这两个商品列表是否应属于同一个UPID? 这种成对比较的方法避免了为同一产品生成独立且完全一致标签的需求,同时也无需预先存在可靠的全局聚类目录。系统首先收集匹配证据,再构建集群。
整个流程分为三个步骤:寻找合理的配对、对每对进行评分、将分数转化为聚类。首先,通过嵌入表示和近似最近邻搜索(Approximate Nearest-Neighbor Search)来检索每个产品的邻近列表。由于需要在数十亿向量中进行搜索,系统必须在检索质量、索引大小和搜索吞吐量之间取得平衡。近似搜索虽然使计算变得可行,但逼近误差和短列表限制可能导致真正的匹配项被排除在候选池之外。
"A missed match does not remove a product from Catalog... it just isn't grouped with other stores' listings of the same item until a later build finds the connection."
即使检索大幅缩小了搜索范围,仍会留下数万亿的候选配对。嵌入空间中的接近性并不证明两个列表代表同一产品,因此需要进一步的评分机制。
多级评分模型:L1、L2与L3的分工协作
为了在成本和控制精度之间取得平衡,系统使用了三种不同能力和推理成本的评分器(L1、L2和L3)。昂贵的比较通过后台队列处理,而快速评分则用于初步筛选。 L1作为第一道关卡,是一个使用低成本配对特征的GBDT分类器。它利用嵌入距离、标题和供应商相似度以及价格关系等特征,在不运行神经交叉编码器(neural cross-encoder)的情况下评估数万亿候选配对。L1有两个任务:提供快速的匹配证据,并决定哪些候选项值得更昂贵的关注。
L2则进一步评估两个列表的文本内容,而L3为选定的比较添加图像和更丰富的元数据。这种分层策略避免了使用最丰富模型对所有配对进行评分的高昂成本,同时也防止了仅依赖最便宜模型而忽略需要仔细检查的区别。
从评分到聚类的图构建与合并策略
在获得分数后,系统将产品表示为图的节点,将评分关系作为边。然而,不能简单地将通过路径连接的所有内容分组为一个集群,因为一个错误的连接可能会将两个无关的产品组合并。系统首先将图划分为受大小限制的组件,这些是独立处理的计算工作单元,而非最终的产品身份。
随后,UPI构建器使用经过训练的模型来评估提议的集群合并。该模型不仅考虑触发提案的对分数,还权衡支持和反对每次合并的证据。这种机制确保了聚类的准确性,避免了因单一错误连接导致的整体分类混乱。通过这种方式,Shopify能够在保持计算效率的同时,实现跨数百万商店的精确产品统一标识。
L2交叉编码器:联合编码解决细微差异
L2是一个经过微调的多语言E5交叉编码器,其核心优势在于联合编码(Joint Encoding)机制。与仅依赖独立生成的嵌入向量不同,L2同时读取两个商品列表的标题、商家名称、预测类别、URL和店铺名等字段。这种机制使模型能够关注两个输入之间的差异,而非仅仅比较整体相似度。
"Joint encoding lets the model attend to differences between the two inputs rather than relying only on separately generated embeddings."
这一特性在文本大部分一致但关键细节不同的场景中至关重要。例如,两个手机壳列表可能共享相同的品牌和系列,但适用机型不同(如“适用于iPhone 15”与“适用于iPhone 15 Pro”)。L2能够权衡简短的兼容性后缀与长串的匹配品牌文本,避免整体相似度掩盖了决定性的差异。然而,L2的局限性在于它不读取商品描述(descriptions)。当区分性细节仅存在于描述中时,L2无法发现差异并可能误判为匹配。因此,系统会将选定的成对数据发送给L3,由后者通过图像识别来寻找差异。
L3重排序器:引入视觉证据与评分策略
L3是一个微调过的开源模型重排序器,它将产品图像与文本及元数据结合进行决策。图像提供了文本可能遗漏的证据,如不同的连接器、按钮布局或外壳开孔。同时,图像也引入了歧义——不同商家可能从不同角度拍摄同一商品,因此模型必须在上下文中解释图像,而非简单比较像素。
"We ask L3 for a match score rather than a generated explanation."
在服务阶段,系统要求L3输出匹配分数(match score)而非生成的解释。这是一个重要的服务选择:聚类构建器需要的是数值化的匹配分数,复杂的推理过程被保留在训练数据管道中。更强的LLM裁判为采样示例提供标签,并为更便宜的模型提供训练信号。系统通过人工标注验证裁判的准确性,以防止错误传播到基于其标签训练的模型中。
图分割策略:有界组件与并行化处理
为了处理大规模数据,系统将图谱拆分为足够小的有界组件(Bounded Components),以便在单台机器上处理并实现并行化。挑战在于如何决定分割点:随机划分会切断有效匹配,而普通的连通分量可能导致组件过大。目标是在保持尽可能多的真实匹配在同一组件内的同时限制组件大小。
算法采用有界并查集(Union-Find): 1. 初始时每个产品自成一个组件。 2. 按分数从高到低处理边。 3. 如果边的端点已在同一组件则跳过;否则,若合并后仍在预算内则进行合并。
"We measure that budget using the sum of the products’ degrees... rather than product count alone."
预算衡量标准是产品度(连接数)的总和而非单纯的产品数量,因为密集连接的组需要更多计算资源。在并行化阶段,边被划分为多个分区由不同工人处理。每个工人使用普通并查集移除冗余连接(如三角形中的三条边保留两条),生成生成森林(spanning forest)而非转发完整边列表。最后,系统结合这些森林并运行有界合并算法,确保组件大小限制。
UPI构建器:基于边缘信息的层次聚类
将图谱拆分为有界组件后,每个组件可由独立的UPI构建器处理。在组件内部,系统使用层次聚合聚类(HAC)结合学习到的合并规则。通过GBDT模型对每次提议的合并进行评分,逐步将小簇合并为大簇。
"The UPI builder’s job is to use that information efficiently."
此时的边已携带类型和分数,这些分数总结了标题、品牌、类别、图像等大量产品信息。UPI构建器的任务是高效利用现有边缘信息,而不是为每次提议的合并重新读取产品数据。它将现有的预测结果组合成簇级决策:证据是否支持加入这两个组?由于错误合并会混合两个完全不同的产品群,系统设定了极高的精度目标。首先调整模型的接受阈值以确保高精度,然后在此约束下最大化召回率。
GBDT 聚类合并模型的特征工程
在跨商店产品聚类的核心环节,系统采用梯度提升决策树(GBDT)模型来评估两个潜在合并簇的合理性。该模型的输入特征不仅描述单个簇,更着重刻画簇与潜在合并对象之间的关系。具体而言,系统计算四类关键特征:Support(支持度)衡量连接两个簇的边数量及其相对于各自规模的密度;Coverage(覆盖率)判断这些连接是分散在大量产品上,还是集中在少数一两个产品周围;Cohesion(内聚性)对比簇内部产品的连接强度与外部连接的差异,以评估簇的紧密程度;Contradiction(矛盾性)则统计低分 L2 或 L3 证据中反对合并的数量。通过在不同类型的边证据上计算这些特征,系统能够区分强匹配与负面判断。这使得合并模型获得了一个紧凑的视图,不仅关注触发提议的那一对产品的得分,更能全面理解组间关系。
训练数据的迭代收集与动态更新
构建高质量训练集是一个多轮迭代的闭环过程。由于新模型会改变合并接受策略,进而影响中间簇的状态和后续决策,基于旧政策的训练数据无法完全覆盖新政策产生的场景。因此,团队重复执行“运行构建器 -> 采样合并提议 -> LLM 裁判标注 -> 重新训练”的循环。这一过程强调收集可接受与不可接受的合并案例,而非简单复制前代构建器的决策。每次迭代都扩展了训练集的范围,使其覆盖更多学习策略遇到的情况。此外,图结构的变化(如新分数到来或产品下架)会改变簇密度和连接关系。因此,系统需要定期刷新基于图的训练特征并收集新标签。这种机制确保训练数据始终与构建器不断变化的行为以及持续演变的目录保持对齐,维持模型的准确性。
应对动态目录的推理队列管理
产品目录并非静止不变,新产品的上架、商家对标题和图像的更新都会产生新的匹配候选者。为了应对这一挑战,系统采用了分层推理策略。L1 模型运行在 CPU 上,速度足够快以对整个候选集进行评分。当新产品或变更产生新候选对时,L1 立即分配初始匹配分数。L2 和 L3 模型则需要 GPU 推理,由于算力限制,无法对所有候选者进行同等规模的实时处理。为此,系统维护了等待这些模型处理的比较队列。新任务会与尚未获得昂贵评分的现有候选者一起加入队列。这种设计让 GPU 集群能够持续接收稳定的工作流。与其试图在每日聚类运行中完成所有昂贵比较,不如利用可用计算资源持续取得进展。队列不仅用于跟上目录变化,还通过优先级排序提升已有产品的匹配覆盖率。新比较根据模型分数、购买搜索信号及当前图结构进行优先级排序,确保关键比较优先处理。系统缓存已完成的分数并追踪所用模型及特征。当条件未变时,直接复用缓存结果。每日 UPI 构建结合当前 L1 结果与可用的 L2/L3 分数,无需等待队列清空。后台推理持续处理新增、变更及未评分的对子,实现每日更新集群与背景 GPU 推理的并行运作。
结论
Shopify的跨商店产品聚类系统通过分层评分与图算法,成功在数十亿商品规模下实现了高精度统一标识。其核心优势在于利用L1快速筛选、L2/L3精细验证及有界组件并行处理,在计算成本与匹配质量间取得平衡。联合编码机制有效解决了细微文本差异问题,视觉证据补充了描述缺失场景。
然而,系统存在明确局限:L2无法读取商品描述导致特定误判风险;近似最近邻搜索可能遗漏真实匹配,需依赖后续构建补全。此外,动态目录更新带来推理队列压力,且训练数据迭代需持续对齐不断变化的图结构。该方案适用于对精度要求极高但允许异步处理的电商场景,而非实时强一致性需求。