YY一下淘宝商品模型

淘宝的电商产品种类非常丰富,必然得力于其商品模型的高度通用性和扩展性。

下面我将亲自操作淘宝商品的发布过程,结合网上其他博客对淘宝网商品库的分析,简单谈谈我的理解。

注:下面不特殊说明,各个表除主键外的无需建立其他唯一索引。

品类

在淘宝网发布宝贝,需要先选择所属的品类:

f8614261-1e45-4f32-a474-58c2936dbcfe

我要卖的商品,属于『流行男装 -> 帆布鞋 -> YINGLUNKUANGWEI/英伦匡威 』这个品类。可见,品类存在层级关系,流行男装是帆布鞋的父品类,英伦匡威属于帆布鞋的子品类,同时英伦匡威也是一个品牌。

撇开品牌不谈,维护这样一个品类关系,应该有这样一个表结构:

品类ID 主键
父品类ID 父级品类ID
品类名称 例如:帆布鞋
品类权重 上图每一列展示有次序先后之分

商品

选好品类好,点击编辑宝贝,最上面是这样的:

2f3d3009-b239-4016-a8e1-2cf55a45a18d

也就是说,你要编辑一个商品的名称和描述,并且商品属于一个分类,因此商品表大概如此:

商品ID 主键
品类ID 最子品类,比如:衣服->毛衣,那么这里应该是毛衣品类ID
标题 例如:一个YY出来的匡威鞋
描述 例如:买不了吃亏,买不了上当

属性和属性值

d7d42b56-5a31-46e4-ae82-85e27c5dc11d

宝贝属性部分,淘宝规定了若干必填项和选填项,其中必填项一般用来商品检索用途,比如进入检索页可以看到”鞋帮高度”和”闭合方式”的筛选项:

65285482-e17d-461b-9ea2-a82f44446eae

我们知道,淘宝售卖各式各样的商品,需要支持各式各样的属性信息,比如:尺寸,颜色…等等。同样的道理,单单就颜色这个属性来说,其对应的属性值也可能是:绿色,红色…等等。

因此,我们可以用属性表存储属性,用属性值表存储与属性相关联的可选值,例如下面:

属性表

属性ID 主键
属性名称 例如:颜色

属性值表

属性值ID 主键
所属的属性ID 例如:归属于 颜色 属性
属性值  例如:红色

有这两个表之后,可以找一个运营人员小C专门负责接属性&属性值的增删改查需求,比如:

负责鞋品类的运营小A找小C说:颜色下面给我加一个彩虹色。

负责车品类的运营小B找小C说:颜色下面给我加一个蓝色。

在小C编辑完成后,小A可以给自己的品类引入:颜色 -> 彩虹色的选项,小B可以给自己的品类引入:颜色->蓝色的选项。

上面这段工作场景,其实引申出了接下来要谈到的另一个关键点,就是品类和属性&属性值的关系。

品类和属性&属性值

前面我们谈到小C的工作职责,是接小A和小B的需求,其中小A负责鞋品类,小B负责车品类。现在小C维护的数据中,颜色属性有2个值:彩虹色,蓝色,但是小A的品类只需要彩虹色,小B的品类只需要蓝色,如果他们俩去查询小C的属性值库会得到彩虹色,蓝色两个选项,这将导致一个淘宝卖家在编辑一辆汽车的时候可以选择彩虹色,可是我还没见过汽车是彩虹色喷漆的呢!

问题就在于,小C维护的是整个淘宝所有的属性与属性值,而小A和小B需要的仅仅所有属性中的部分,以及属性对应的属性值中的部分,因此我们需要维护一个”品类”与”属性”,”属性值”之间的关系,从而形成一个子集。

我们先建一个”品类属性”关系表,来标明某个品类关联到哪些属性子集合

品类属性模板ID 主键
品类ID 例如:帆布鞋的 品类ID
属性ID 例如:颜色的 属性ID
是否必填 之前的图片里,带*号的属性

再来建一个”品类属性值”关系表,来标明某个品类某个属性关联到哪些属性值子集合:

品类属性模板ID  例如:上面那个表的主键
属性值ID  例如:蓝色 的属性值ID

经过这样的设计,我通过先选择品类,就可以通过品类ID查询上述2个表得到属性子集合和属性值子集合,也就是最上面看到的各种”宝贝属性”的数据来源了。

PS:品类属性模板表没有对”品类ID+属性ID”做唯一性限制,这是出于真实运营场景下灵活性的考虑,同一时刻相同”品类ID+属性ID”应该只有一条记录处于有效状态,运营可以灵活的切换,这是程序来保障的,当然运营同学也不应该留存太多用不到的品类属性模板。

另外提一下,因为品类有父子关系,所以通常子品类会继承父品类的品类属性与品类属性值,这个不是关注的重点。

SKU

上面勾选的这些属性,其实都是为了描述商品的一些特性,然而我们在实际购买的时候其实并不是购买商品自身,而是购买一个SKU,那么SKU是什么?和商品是什么关系?

dabb7388-3858-4d5e-ac1f-15f16023371e

继续之前的编辑页面,向下滚动进入这个区域:这里是编辑宝贝的规格,这里的规格其实背后对应的就是SKU的概念

详细来说:

  • 颜色分类和尺码是2个品类属性,它们和之前勾选的其他属性相比,数据来源一样,但是用途不同,这个后面会说。
  • 选颜色时候,黑色和柠檬黄是2个品类属性值,选尺码的时候48.5和49.5是品类属性值。

经过程序的排列组合,产生了如下几种组合关系:

8756f8e3-6d69-4817-b6a7-226c7b3adb0c

这里将颜色和尺码组合后,产生了4行记录,每一行记录就称作一个SKU,在购买时的效果我们应该很熟悉:

ef8c2d68-cc50-47d6-8ef9-5de0b7738f98

每一种尺码和颜色的组合选定之后,价格等信息都随之变动,这就是选择了一个SKU,也就是我们真实购买的东西,因此尺码和颜色分类这两种属性我们也称为销售属性(应该给”品类属性”表添加一个”是否为销售属性”),也就是控制SKU选择的属性。

根据上面的分析,SKU首先应该属于一个商品,也就是上面的购买页面代表一个商品,上面的多选按钮可以指定一个SKU,商品和SKU之间有1:N的关系。

其次,SKU应该与属性以及属性值有关联,比如:37码-绿色,39码-咖啡色,也就说:”尺码属性:37码,颜色分类:绿色”以及”尺码属性:39码,颜色属性:咖啡色”。

SKU表

SKU ID 主键
商品ID 所属的商品ID,例如:静熙男士帆布鞋 的商品ID
价格 SKU的售价

SKU销售属性表(也可以打包放在sku表的一个字段里)

SKU ID 联合主键 一个SKU一个属性只能对应一个值
属性ID
属性值ID

库存

库存系统本身是个独立于商品库外的系统,通常要求较高的处理能力,这里仅说明库存应该与SKU关联:

SKU ID 主键
剩余库存 例如:10个

说在最后

既然一个商品库,需要维护那么多表,那么表之间的一致性就是很大的问题。

举几个例子:

  • 新建商品:正常来说应该保存1个商品记录,4个sku记录,4个库存记录,以及若干其他表的信息,如果开启数据库事务可以保证要么都成功,要么都失败。但是我们知道淘宝这种规模一定是分布式的mysql部署,另外,商品和库存是2个系统,一般也不会共享数据库,这些都导致单机事务的做法是行不通的。通常来说,都是考虑最终一致性,或者说不一致不会导致错误,比如:先插入库存记录,再插入sku记录,最后插入商品记录,这样就算前一步失败也可以保证用户搜索不到商品,不会导致致命错误。
  • 修改商品:修改商品,除了改商品自身的描述信息,还可能对sku进行增删改查。如果一个商品2个人同时改,那么有可能导致2个人提交瞬间,请求各种交错,谁都得不到想要的结果,因此一般可以考虑用数据库锁住商品记录,然后对sku信息进行独占的查询与修改,这样可以保证2个人串行生效,任何一方提交时发现现在的数据在编辑期间发生了变化,都可以回滚事务,重新查询最新状态。

另外,我们也不应该执行数据库的delete命令来删除属性,属性值,或者任何其他信息,因为极有可能已有商品对其产生了依赖,必须采用逻辑删除,也就是标记删除的方法,保证已有商品就算依赖了删除的属性也可以正常售卖,直到商家主动的重新编辑商品时重新选择商品的属性即可。

如果文章帮助您解决了工作难题,您可以帮我点击屏幕上的任意广告,或者赞助少量费用来支持我的持续创作,谢谢~