SKU聚合SPU算法


1. 问题背景

商品结构包含SKU和SPU,淘宝的商品展示是基于SPU,京东的商品展示基于SKU。这两种展示方式各有什么优缺点。

1.1. 基于SKU的展示方式

SKU展示的优点:

  • 可以过滤SKU的特性(规格、库存等)

    用户最终购买的都是SKU,规格、库存等特性也是SKU上的,筛选和过滤条件可以控制到规格等SKU属性。比如搜索“iPhone 6s 银色 16G”,可以直接展示该SKU,过滤掉其它颜色、其它容量的6s SKU。这种过滤方式对服装行业是很有用的,服装通常一个SPU下面有几十个SKU,我们搜索会加上想要的颜色、尺寸等规格。

  • 可以更精确地建立用户画像

    一个用户买衣服时经常选择颜色为黑色、尺寸为XXXL,那么我们给用户建立的画像就是喜好黑色、本人衣服尺寸为XXXL。这样后续推荐商品可以推荐这些规格的衣服给他;或者做千人千面个性化搜索时,可以把这些规格的衣服权重调搞,排在页面的前面。

SKU展示的缺点

  • 同一个SPU下面SKU很多时,列表展示的都是同一个SPU下的SKU

    京东搜索“马牌轮胎”关键词,出来的SKU列表如下图:

    前面5个SKU属于同一个SPU,前面10个SKU有8个属于同一个SPU,只是轮胎的尺寸不同。如果是服装类SPU,旗下的SKU会更多,这样可能一页都属于同一个SPU。

1.2. 基于SPU的展示方式

SPU展示的优点

  • 每页可以展示更多的信息,给用户更多的选择空间

    正常我们搜索商品时可能只会浏览前面几页的商品数据,更多情况下可能就第一页的商品。这时展示更多的商品就很重要了,可能会提升客户的购买率。

SPU展示的缺点

  • 无法筛选规格

    当用户购买衣服时,可能只关心自己的颜色和Size,基于SPU展示方式无法做到这一点,并且某个规格下的SKU可能没货,也需要点击进详情页才能知道。

2. 问题分析

既然SKU和SPU展示都有各自的优缺点,是否有一种展示方式能够吸取这两种方式的优点呢。我们可以看下京东手机类目下的搜索:

京东输入“iphone 6s”,展示的结果如下:

如果我们只对金色感兴趣,输入关键词“iphone 6s 金色”,展示的结果如下:

我们来分析一下京东的这种展示方式:

  • 商品展示列表是以SPU纬度的。
    否则搜索“iphone 6s”时,前面的SKU肯定是京东自营的“iphone 6s 64G 银色”、“iphone 6s 64G 金色”、“iphone 6s 64G 灰色”、“iphone 6s 64G 玫瑰金色”、“iphone 6s 16G 银色”、“iphone 6s 16G 金色”、“iphone 6s 16G 灰色”、“iphone 6s 16G 玫瑰金色”等。

  • 商品展示SPU下的SKU是根据搜索条件动态变化的
    搜索“iphone 6s”时,SPU下面的SKU有4个,分别对应4种颜色;搜索“iphone 6s 金色”时,SPU下面的SKU只有两个“金色”、“玫瑰金”。这样用户很清楚就可以找到符合要求的商品。

  • 商品的分页信息也是SPU纬度的。
    一共71个商品,2页,71显然是SPU数目。

  • 商品的筛选条件是基于SKU纬度的
    如果筛选条件是基于SPU的,那么搜索“iphone 6s”和搜索“iphone 6s 玫瑰金”这两个关键词,符合条件的SPU应该是相同的,筛选条件也应该是相同的,事实却不是这样。

    可以看到京东的这种展示方式融合了SPU展示和SKU展示的优点,对于数码3C、服装、快消品等行业是最佳展示方式。

3. 解决方案

通过上面的分析可知,我们只要将搜索和聚合作用于SKU,然后将符合条件的SKU按照SPU纬度做个分组(sku groupBy spu ),然后获取SPU的分页信息即可。

3.1 算法简要步骤

  1. 搜索和聚合SKU

    根据搜索请求参数,获取符合条件的SKU和相应聚合条件。搜索时,采用scan方式,将SKU加载在内存中。聚合条件增加spuId字段cardinality方式的聚合。

  2. 按照SPU纬度分组SKU

    对SKU进行GroupBy spuId操作,不需要对所有SKU进行操作,只需要对分页要求的SPU进行。

  3. 根据ID查找SPU

    根据步骤2获取的SKU分组中的spuId,根据ID查询对应的SPU数据结构。

  4. zip压缩SPU、SKU

    对步骤2获取的SKU、步骤3获取的SPU进行zip压缩操作,形成的SPU结构为:{spuId:11111, k1:v1, k2:v2, skuList:[sku1, sku2]}。最终返回数据结构为:{total: 120, root:[spu1, spu2, ...]}

results matching ""

    No results matching ""