ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

GPC与UNSPSC区别:商品分类编码映射与采购主数据治理

GPC与UNSPSC区别:商品分类编码映射与采购主数据治理

上周帮一位做日化品类的朋友梳理主数据表,表格里并排摆着两列:一列叫GPC,一列叫UNSPSC。他问我,这两列是不是填一个就行,另一个空着也没关系。我当时回得很直接:你要是不填,零售商的收货预约那一步就能让你卡住,采购那边的支出分析报表也会把你的货一股脑算进“未分类”里。这两个码看着像是同一件事的两种写法,实际上一个管的是“这东西在货架上属于哪儿”,另一个管的是“这东西在采购目录里归哪一类”。GPC 和 UNSPSC 分属两套完全不同的分类体系,一个是零售端商品识别的骨架,一个是采购端支出归类的尺子。搞混了,后面的品类分析、供应商对账、电商上架全是返工。这篇就把这两套标准的出身、结构、粒度差异和实际映射方法一次讲透,适合正在做主数据治理、商品上架、采购数字化的朋友,也适合刚接触这两个字段、被供应商表单问懵的新人。

1. 两个码摆在一起才看得出区别:GPC管货架,UNSPSC管采购

很多人第一次同时见到这两个字段,是在零售商的商品资料表或者供应商入驻系统里。表单上两列挨着,也没有说明文字,很容易默认它们是“主分类”和“备用分类”的关系。实际上它们服务于两条完全不同的业务链路,硬把它们当成同义词处理,是后面所有映射错误的源头。

1.1 GPC的底层诉求:让商品在零售链条里被一致地识别

GPC 的全称是Global Product Classification,它诞生的场景很具体:一个商品从工厂出来,要经过数据池、零售商系统、门店货架图、电商后台,每一环都要回答“这是什么”。如果每个环节各用一套叫法,数据就没法自动对齐。GPC 的思路是先把商品塞进一棵固定的四级树里,再用一组标准化属性把同一个 Brick 下的商品区分开。

所以你会看到 GPC 的粒度是面向消费者视角的:它关心的是“这瓶饮料是即饮还是冲调”“这块肥皂是香皂还是沐浴露”。零售商拿它来做品类陈列规划、商品数据池同步、电商筛选条件、货架图定位,这些都是围绕“卖”来展开的动作。它不负责告诉你这东西采购花了多少钱,也不负责把不同供应商的报价拉到同一个口径上比较——那是另一套体系要干的事。

我在实际操作中的一个体会是,GPC 的价值不在于那个八位码本身,而在于码加属性这一整套描述。光有一个 Brick 码,两个不同规格的咖啡可能落在同一个码里,但加上属性值之后,系统才能把它们区分成两条商品记录。这一点后面会展开讲。

1.2 UNSPSC的底层诉求:让采购支出能被横向比较

UNSPSC 的全称是United Nations Standard Products and Services Code,从名字就能看出它带着“服务”两个字。它的设计目标是给产品和服务提供一套统一的、可用于统计和比较的编码,典型使用场景是采购支出分析、电子采购目录、供应商分类、发票与采购订单的对账。

举个很直观的例子:一家企业想知道“今年包装材料一共花了多少钱”,如果每个事业部各自用自己的一套品类名,有的叫“纸箱”,有的叫“外包装”,有的叫“瓦楞箱”,汇总就无从谈起。UNSPSC 提供的是一个跨组织可比的公共语言,把所有这些叫法收敛到同一个八位码上,报表才能做出来。

这也解释了为什么 UNSPSC 的粒度偏向采购视角:它更关心“这类物料在采购目录里怎么归类”“这个服务属于哪一类外包支出”,而不是“它在货架上应该摆在哪个位置”。同一个实物商品,在 GPC 里可能细分到“口味”“包装形式”,在 UNSPSC 里可能就落在一个相对粗的 Commodity 上,这是设计目标不同导致的必然结果,不是哪一方做得不够细。

1.3 定位差异对照表

把两者的核心差异拉成一张表,比读十段文字都快:

对比维度GPCUNSPSC
主要服务对象零售、电商、商品数据池采购、供应链、财务支出分析
核心视角消费者如何识别和选购商品组织如何归类和统计采购支出
层级结构Segment / Family / Class / Brick 四级Segment / Family / Class / Commodity 四级
编码形态八位数字 Brick 码 + 属性与属性值八位数字 + 可选业务职能码
覆盖范围以实体零售商品为主产品与服务并重
典型落地场景商品上架、货架图、数据同步支出分析、采购目录、供应商分类

看这张表的时候要抓住一句话:GPC 是为了让商品被卖掉,UNSPSC 是为了让支出被算清。理解了这句话,后面所有的细节都能对上号。

2. GPC的四级骨架:从Segment一路走到Brick

GPC 的结构看起来只是一棵树,但真正用起来,难点不在层级本身,而在于层级之间怎么收窄、属性怎么配合。很多人只记住了四级名称,实际映射的时候还是凭感觉填,结果同一个品类在不同人手里落到不同分支上。

2.1 四级结构是怎么收窄的

GPC 的四级从粗到细依次是 Segment、Family、Class、Brick。用生活化的说法,它像是一个不断追问“再具体一点”的过程:

  • Segment:最粗的一层,大致对应“这是哪一大类生意”,比如食品饮料、个人护理、家居用品这类划分。
  • Family:在 Segment 之下再切一刀,回答“属于这一类里的哪个族群”。
  • Class:继续收窄,回答“这个族群里的哪一类”。
  • Brick:最细的一层,是真正带八位编码、可以挂到商品记录上的那一级。

关键点在于:只有 Brick 有独立的八位编码,上面三级更多是导航路径。你在系统里存商品分类的时候,实际存的是 Brick 码,其余三级是从 Brick 反查出来的。这个设计很实用,因为商品记录里塞四个字段容易不一致,只存最细的一级,其余由码表推导,数据一致性就有保障了。

我自己建表的时候会额外把四级路径都冗余存一份,不是为了业务逻辑,纯粹是为了排查问题方便——一旦发现某个 Brick 挂错了,能一眼看出它挂在哪个 Family 下面,判断错误影响的范围。

2.2 Brick后面的属性才是重头戏

只讲四级树,其实是把 GPC 讲浅了。GPC 真正区分商品的地方在于Brick 之上的属性组。每个 Brick 都会关联一组属性,每个属性有一批标准化的取值,每个取值还有对应的编码。

举个咖啡的例子。假设某个 Brick 大致对应“咖啡”这个细分类,那么它下面可能挂着这些属性:咖啡形态(烘焙研磨、速溶、胶囊等)、是否含咖啡因、包装形式、口味类型、是否有机。同一个 Brick 下的两条商品记录,靠这些属性值的组合就能被区分开。零售商在做电商筛选、做货架陈列、做数据池同步的时候,用的就是“Brick 码 + 属性值”这个组合。

注意:属性值必须从标准列表里选,不能自己造词。我见过有人为了省事,在属性值里手填“大包装”“家庭装”这种描述,结果数据池同步直接报错,因为对方系统里根本没有这个取值。

这一步是很多人容易忽略的:以为填完 Brick 码就完事了,属性一律跳过。等到对接零售商数据池的时候才发现,对方要求的字段里有一半是属性值,只能返工补录。

2.3 拿咖啡走一遍完整路径

为了让结构更具体,我们拿咖啡这条线完整走一遍。假设某个商品是“某品牌速溶黑咖啡,罐装,无添加糖”。

第一步,从 Segment 层判断它属于食品饮料这个大类。第二步,往下找到饮料相关的 Family。第三步,进入咖啡与茶相关的 Class。第四步,落到咖啡相关的 Brick,拿到那个八位码。

拿到 Brick 之后,再补属性:形态选“速溶”,是否含咖啡因选“含”,包装形式选“罐装”,是否添加糖选“无”。这一组值填完,这条商品记录在 GPC 体系里才算描述完整。

这里有个实操细节值得说:同一个 Brick 下的属性组不是随便挑的,是标准规定好的。你不能给咖啡 Brick 硬加一个“电池容量”属性,系统也不认。所以映射工作的正确顺序是“先定 Brick,再看这个 Brick 挂了哪些属性,逐个填”,而不是“先把能填的属性填完,再找 Brick”。顺序反了,返工量会很大。

具体某个品类落在哪个 Brick、挂了哪些属性,最稳妥的做法是查官方发布的 GPC 浏览器工具,按关键词检索,别凭记忆填。版本更新之后编码和属性都可能调整,凭记忆是最容易出错的。

3. UNSPSC的八位数字:四级分段加业务职能码

UNSPSC 的结构比 GPC 好记一些,因为它就是一串八位数字,每两位一段,逻辑非常规整。但规整不等于简单,实际用起来还是有几个点需要提前搞清楚。

3.1 八位码怎么拆

UNSPSC 的八位码从左到右依次是:

位置层级含义
第 1-2 位Segment最大的分类段,决定这是哪一大类产品
第 3-4 位Family段之下的族群
第 5-6 位Class族群之下的类别
第 7-8 位Commodity最细的物料层级,实际挂到采购记录上的就是这一级

以咖啡与茶这个类别为例,它大致落在食品饮料这个 Segment 下的饮料 Family,再往下到咖啡与茶这个 Class,最后一组数字定位到具体的 Commodity。完整八位码在公开资料里可以查到,但具体编码一定要以你所用版本为准,因为不同版本之间会有增补和调整。

这里有个和 GPC 类似的设计:实际业务记录上挂的是最细的 Commodity 码,上面三级由码表推导。所以在采购系统里建物料主数据的时候,核心字段就是那八位 Commodity 码,其余层级用于报表汇总。

一个很实用的技巧是:做支出分析报表的时候,按 Segment 或 Family 汇总比按 Commodity 汇总更好看。因为 Commodity 太细,一行一个码,报表会碎成几百行,没人看得下去;而按 Family 汇总,通常十几个到几十个分组,管理层一眼就能看出钱花在哪儿了。我在做第一版支出分析的时候就是按最细层级出表,结果被要求重做,后来改成默认按 Family 展开、可下钻到 Commodity,接受度立刻不一样了。

3.2 业务职能码这个附加维度

UNSPSC 有一个 GPC 没有的附加维度:业务职能码。它是一个两位的补充码,用来标识这个商品或服务在采购过程中所处的业务环节,比如采购、租赁、维修、回收这类区分。

为什么需要这个?因为同一个实物,在不同业务环节下的采购含义完全不同。一台设备是买断还是租赁,在支出分析里应该分开看;一批耗材是直接采购还是包含在维保服务里,对成本结构的影响也不一样。业务职能码就是用来把这个维度单独拎出来的。

实际落地的时候,大部分企业的系统只存了八位主码,业务职能码直接省略。这在纯商品采购场景下问题不大,但如果你的采购范围里包含设备租赁、运维外包这类业务,建议把这两位也存下来,否则后面拆成本结构的时候会很难受。我见过一个项目,前期没存业务职能码,后来要做租赁与采购的成本对比,只能靠订单文本去猜,工作量翻了好几倍。

3.3 版本节奏与历史码的处理

UNSPSC 是持续维护的,会定期发布新版本,新增品类、调整归属、废弃部分旧码都属于正常操作。GPC 同样有版本迭代。这就带来一个绕不开的问题:存量数据怎么跟上版本。

我的处理原则是三条:

第一条,主数据表里永远存一份“录入时所用的版本号”。这一列看起来没用,出了问题就是救命稻草。没有版本号,你根本不知道某条记录是按哪一版填的,排查时只能全表重扫。

第二条,废弃码不删除,标记为失效并保留映射关系。有些系统为了“干净”,把废弃码直接从码表里删掉,结果历史订单关联的分类全断了,报表出现大量空值。

第三条,版本升级后做一次存量复核,重点查被调整过归属的品类。不需要全表重映射,只查变更清单里涉及的码,工作量能控制住。具体怎么查,第 5 节会给一个脚本思路。

4. 容易混的四个点:粒度、视角、更新、覆盖范围

讲完两套结构,回到最开始的问题:为什么这么多人会把它们搞混。我梳理下来,混淆主要集中在四个地方,每一个都对应一类典型的错误操作。

4.1 粒度差异:一个管“是什么”,一个管“买什么”

最典型的误解是认为“GPC 比 UNSPSC 细”或者反过来。实际上它们细的地方不一样。GPC 在消费者可感知的差异上做得细,比如口味、包装形式、是否含糖;UNSPSC 在采购可归类的差异上做得细,比如材质、规格、行业用途,同时还覆盖服务。

举个具体场景:一款洗发水和它的旅行装。在 GPC 体系里,如果容量差异会影响消费者选购和货架陈列,它们可能需要落到不同的 Brick;但在 UNSPSC 里,它们很可能就是同一个 Commodity,因为采购归类上没必要区分。反过来,一批工业用的同规格润滑油,在 UNSPSC 里可能因为用途和应用场景不同落到不同码上,而 GPC 里未必有对应的细分。

所以映射的时候,不能假设两套码是一一对应的。一对多、多对一都是常态,强行做一对一映射,最后一定有一边是错的。

4.2 视角差异带来的映射陷阱

第二个容易踩的坑是“用零售的叫法去查采购的码”。比如某个商品在 GPC 里叫“即饮茶饮料”,你直接拿这个词去 UNSPSC 里搜,很可能搜不到理想结果,因为 UNSPSC 那边的叫法可能是“茶饮料”或者归在更粗的“饮料”下面。

我的做法是准备两套检索词:一套是面向消费者的商品名称和卖点词,用来查 GPC;一套是面向采购的物料名称和规格词,用来查 UNSPSC。这两套词往往不一样,硬用一套去搜两边,命中率会很低。

还有一种更隐蔽的陷阱:销售包装和采购包装不是一回事。零售端看到的是一箱 24 瓶的销售单元,采购端进的是整托盘。如果不区分这层,映射出来的码可能指向了错误的包装层级。这个坑我在一个饮料类项目里踩过,后面专门加了一列“包装层级”字段才解决。

4.3 更新机制不同,维护成本也不同

两套标准都在更新,但节奏和影响面不一样。GPC 的更新往往伴随属性调整,影响的是商品数据池同步和电商展示;UNSPSC 的更新影响的是采购报表口径和历史数据可比性。

这意味着维护策略要分开设计:

  • GPC 侧重点关注“新增 Brick 和属性变更”,因为零售商对接时对属性字段的校验很严。
  • UNSPSC 侧重点关注“废弃码和归属调整”,因为这会直接影响支出报表的连续性。

我一般的做法是每次版本更新后拉一份变更清单,先做影响面评估,判断涉及多少存量记录,再决定是全量复核还是抽样复核。没有变更清单就盲目全表重跑,是很浪费时间的做法。

4.4 覆盖范围:服务类商品怎么办

最后一个容易混淆的点是服务。UNSPSC 从设计上就覆盖服务,所以咨询服务、物流服务、IT 运维服务都能找到对应的码。GPC 的覆盖面则以实体商品为主。

这就导致一个常见问题:服务类采购在填表时被硬塞进商品分类里。我见过把“仓储服务”填到某个物流设备的 GPC 码下的情况,原因很简单——填表的人找不到对应项,就随便挑了个看起来相关的。

正确的处理方式是:服务类条目在 GPC 侧留空,只在 UNSPSC 侧填写,并在内部主数据表里用一个“条目类型”字段区分商品和服务。这样报表汇总的时候不会把服务混进实物采购里,数据分析才站得住。

5. 落地映射:从建表到批量校验的完整路径

讲完理论,说点能直接抄作业的。下面这套流程是我在几个项目里反复用过的,从建表到脚本校验,全流程都能落地。

5.1 先建内部品类主数据表

不要一上来就往业务系统里灌数据,先在中间层建一张主数据表,把所有映射关系集中管理。表结构大致这样:

字段说明
item_id内部商品唯一标识
item_name商品名称
item_type商品 / 服务
pack_level销售单元 / 采购单元
gpc_brick_codeGPC 八位码,服务类留空
gpc_attr_jsonGPC 属性值集合,用 JSON 存
unspsc_codeUNSPSC 八位 Commodity 码
unspsc_func_code业务职能码,可空
src_version录入时所用标准版本号
map_status待映射 / 已映射 / 待复核
reviewer复核人

这张表的关键在于map_status 和 reviewer 两列。没有状态字段,你永远不知道哪些记录还没处理完;没有复核人字段,出了问题找不到人回溯。这两个字段看起来是管理开销,实际上是整个映射工程能不能持续运转的基础。

5.2 候选码检索脚本

人工一条条查码效率极低,先做一层机器初筛,把候选码缩小到三五个,再人工确认,效率能提升好几倍。下面这个脚本用关键词和相似度做粗筛:

import csv import json from difflib import SequenceMatcher def load_ref(path, code_field, name_field): """加载参考码表,返回 [(code, name), ...]""" rows = [] with open(path, encoding="utf-8-sig") as f: for r in csv.DictReader(f): code = (r.get(code_field) or "").strip() name = (r.get(name_field) or "").strip() if code and name: rows.append((code, name)) return rows def score(query, text, keywords): """名称相似度 + 关键词命中加权""" base = SequenceMatcher(None, query, text).ratio() hit = sum(1 for k in keywords if k and k in text) return base * 0.6 + min(hit, 3) * 0.15 def top_candidates(query, ref_rows, keywords, n=5): scored = [(code, name, score(query, name, keywords)) for code, name in ref_rows] scored.sort(key=lambda x: x[2], reverse=True) return scored[:n] if __name__ == "__main__": gpc_ref = load_ref("gpc_brick_ref.csv", "brick_code", "brick_name") unspsc_ref = load_ref("unspsc_ref.csv", "commodity_code", "commodity_name") # 示例:一条商品记录 item = { "name": "速溶黑咖啡 罐装 无糖", "keywords": ["咖啡", "速溶", "饮料"] } print("GPC 候选:") for code, name, s in top_candidates(item["name"], gpc_ref, item["keywords"]): print(f" {code} {name} score={s:.2f}") print("UNSPSC 候选:") for code, name, s in top_candidates(item["name"], unspsc_ref, item["keywords"]): print(f" {code} {name} score={s:.2f}")

这段代码有几个地方值得说明。相似度权重只占六成,剩下四成给关键词命中,是因为纯字符串相似度对中文商品名很不友好,“速溶黑咖啡”和“咖啡(速溶)”的字符重叠不高,但语义上是同一个东西。关键词命中能把这层语义补回来。

关键词的构造也有讲究:要包含品类词、形态词、用途词,不要只放商品名。比如上面例子里,除了“咖啡”,还放了“速溶”和“饮料”,这两个词能帮助脚本把候选拉到正确的 Family 附近。

提示:这个脚本只做初筛,输出的一定要人工过一遍。真实项目里机器初筛的准确率大概在六七成,剩下三成靠人判断,别指望全自动。

5.3 人工校准的抽检规则

机器初筛之后是人工确认,这一步最容易出现“每个人标准不一样”的问题。我的做法是定三条硬规则,所有人按同一个口径走:

第一条,先定层级再定码。不要一上来就在最细层级里找,先判断 Segment 和 Family 对不对,层级错了往下全错。

第二条,属性值必须逐项对照标准列表,不接受自造词,不接受“差不多就行”。属性错一个值,下游数据池同步就可能失败。

第三条,服务类条目不进 GPC,直接判定,不做讨论。这条规则看着粗暴,但能省掉大量来回沟通。

抽检比例上,我一般按首次映射全检、后续批次抽检 20%来走。首次全检是因为大家还没形成统一手感;后续稳定之后,20% 的抽检率足以发现问题,又不至于拖慢进度。

5.4 版本升级后的存量复核

版本升级之后,最省力的复核方式是只查变更清单涉及的记录。下面这段逻辑用来统计影响面:

def impact_scope(master_rows, changed_codes): """统计受版本变更影响的存量记录""" hit = [r for r in master_rows if r["gpc_brick_code"] in changed_codes or r["unspsc_code"] in changed_codes] total = len(master_rows) print(f"存量总数: {total}") print(f"受影响数: {len(hit)}") if total: print(f"影响占比: {len(hit) / total:.1%}") return hit

先跑一遍拿到影响占比,再决定复核策略:

影响占比建议策略
5% 以下直接逐条复核,成本可控
5% 到 20%按 Family 分批复核,优先处理高金额品类
20% 以上暂停新增映射,集中做一轮全量治理

这个判断标准不是死的,但方向是明确的:影响面小就逐条改,影响面大就先停手再治理。最怕的是边改边加,越改越乱。

6. 实际操作里踩过的坑

理论和流程讲完了,最后说说踩过的坑。这些坑的共同点是:看文档的时候完全想不到,真跑起来一个接一个冒出来。

6.1 只按名称匹配

最开始做映射的时候,我图省事,直接拿商品名称去码表里搜。结果很快翻车:同一个名字“咖啡”,可能是速溶咖啡、咖啡豆、咖啡饮料,甚至咖啡味零食。名称匹配把它们全拉进同一个候选池,人工确认的时候全靠猜。

后来改成名称 + 属性双条件匹配,先把 Brick 定下来,再看属性,问题才解决。这件事让我明白一个道理:GPC 的码和属性是绑定的,脱离属性谈码,等于只做了一半的活。

6.2 一条商品挂多个Brick

有一种商品天然跨类,比如“带杯子的咖啡礼盒”。它到底算咖啡还是算礼盒?我一开始试图给它挂两个 Brick,结果系统直接报错,因为业务系统里这个字段是单选。

后来的处理方式是:按主要销售属性定性,次要属性放到扩展字段。礼盒的主属性是咖啡,就挂咖啡相关的 Brick,杯子作为附属品在描述里体现。如果礼盒本身就是主推卖点,那就反过来挂礼盒类的 Brick。这个判断标准要在团队里统一,否则同一种商品会被不同人挂到不同地方。

6.3 把包装规格当成商品差异

这个坑挺隐蔽。同一款洗发水有 200ml 和 750ml 两种规格,我一开始把它们当成两条独立商品,分别映射。后来发现,在 GPC 里它们可能落在同一个 Brick,差异体现在容量属性上;在 UNSPSC 里更是同一个 Commodity。

正确处理是先判断规格差异是否影响分类层级,再决定是否拆分记录。如果只影响属性值,就一条记录挂一组属性;如果确实跨了 Brick,才拆成两条。拆多了的后果是主数据表膨胀,报表重复计算,后续维护成本翻倍。

6.4 没有单一事实源

最后一个坑是组织层面的:不同部门各自维护一套分类表,销售那边一套叫法,采购那边一套叫法,电商后台又是另一套。表面上大家都有码,实际上对不上。

解决办法说起来简单做起来难:指定一张主数据表作为唯一事实源,其他系统通过接口或定期同步取数,不允许各自本地维护。这件事必须有明确的责任人推动,靠技术手段解决不了。我参与过的项目里,凡是主数据治理做得顺的,都是因为有一个明确的归口部门在管;凡是各自为政的,最后都回到“每月人工对一次表”的老路上。

回到开头那位朋友的问题。他问的是“两列能不能填一列”,本质上是把两套服务于不同目标的体系当成了重复项。真正该问的是:这些商品要不要卖给零售渠道?要,就得把 GPC 和属性填完整;这些采购支出要不要做归口分析?要,就得把 UNSPSC 挂准。两个问题的答案都是要,那两列就都得填,而且要用同一张主数据表管起来。我自己的经验是,一开始嫌麻烦想省掉其中一列,最后往往要在报表出错或者数据同步失败的时候,花三倍的力气补回来。

返回列表