rexwong

rexwong 查看完整档案

北京编辑  |  填写毕业院校  |  填写所在公司/组织填写个人主网站
编辑
_ | |__ _ _ __ _ | '_ \| | | |/ _` | | |_) | |_| | (_| | |_.__/ \__,_|\__, | |___/ 该用户太懒什么也没留下

个人动态

rexwong 收藏了文章 · 11月10日

电商系统设计之商品 (上)

clipboard.png

电商大伙每天都在用,类似某猫,某狗等。
电商系统设计看似复杂又很简单,看似简单又很复杂
本章适合初级工程师及中级工程师细看,大佬请随意

前言

商品的设计是电商系统中占据重要地位,如何设计出高扩展,高性能的商品系统并非一件简单的事情,我的设计是观摩互联网各大佬的设计后自行研究的,并非完全正确,但也不完全错误,现在我设计的这套电商系统已经在使用,如果在逻辑上遇到什么问题,会及时修改我关于电商系统相关文章的设计思想部分。

元素

clipboard.png
见上图,本次我们先讲解下系统规格与自定义规格、系统属性与自定义属性的关于及其他们存在的意义。

SPU

SPU(Standard Product Unit)标准化产品单元

什么叫标准化产品单元?

抛弃标准化一词来看,产品单元?就是以一个产品为一个单位。例如你是手记销售商,你在厂家进货的时候说我要iphonex 100部型号随意规格随意,进货的时候没考虑到内存或者屏幕尺寸,这个时候你就把iphonex这个商品当作一个单位。这就是产品单位。再谈标准化,只是一些人或一个人制定的这么一个标准,所以称为标准化产品单元,不要拿百度百科上的解释反驳我,我只是用更通俗易懂的方式解释一下SPU。

clipboard.png

例如iphonex的价格也不同的地方,分别为iphonex 64g 是8888,iphonex 256g是18888。这个时候我们不能建立2个spu去管理这2个商品。这个时候就需要用到spu的概念了。

SKU

SKU(Stock Keeping Unit)库存量单元

什么叫库存量单位?

字面意思来看,库存则是指的某个商品的某个规格还有多少件,这个时候就不能只针对商品了。上面的例子iphonex有2个不同规格的商品,这个时候无法计算其每个规格的库存(创建2个商品可是不切实际,未来管理会很复杂,就例如安踏的跑鞋有十几个尺码,难道要创建十几个商品吗?),此时只能针对当前商品再创建子商品,我们叫它规格,例如iphonex 有 存储和颜色2个规格

clipboard.png

有木有发现还是有点问题?那具体的存储大小与具体颜色该如何表达呢?这个时候需要创建规格的子商品,我们称他为属性

clipboard.png

这个每个属性的结合则就是一个新的商品,我们称它为SKU,一个SPU对应着N个SKU

clipboard.png
这样就生成了N个商品

  • iphonex 64G白色
  • iphonex 32G黑色
  • iphonex 256G白色 等等...

系统规格/属性

为什么要设立系统规格属性呢?

clipboard.png
盗用一张淘宝的图,以上都是根据分类品牌设定好的规格及属性

主要是为了方便商家添加商品及其对商品的规格属性进行统一的管理,当然一个电商系统在前期运营的情况下尽量减少系统属性规格的使用(方便商家入住嘛)。

自定义属性就不用说了。不让商家添加自己的规格和尺码什么的怎么能行?

数据

具体数据表的设计如下

product

商品表 (spu表)

CREATE TABLE `product` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '商品标题',
  `category_id` int(11) NOT NULL COMMENT '商品分类编号',
  `mer_id` int(11) NOT NULL COMMENT '商家编号',
  `freight_id` int(11) DEFAULT NULL,
  `type_id` tinyint(4) NOT NULL COMMENT '类型编号',
  `sketch` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '简述',
  `intro` text COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '商品描述',
  `keywords` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '商品关键字',
  `tags` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '标签',
  `marque` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '商品型号',
  `barcode` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '仓库条码',
  `brand_id` int(11) NOT NULL COMMENT '品牌编号',
  `virtual` int(11) NOT NULL DEFAULT '0' COMMENT '虚拟购买量',
  `price` decimal(8,2) NOT NULL COMMENT '商品价格',
  `market_price` decimal(8,2) NOT NULL COMMENT '市场价格',
  `integral` int(11) NOT NULL DEFAULT '0' COMMENT '可使用积分抵消',
  `stock` int(11) NOT NULL COMMENT '库存量',
  `warning_stock` int(11) NOT NULL COMMENT '库存警告',
  `picture_url` varchar(125) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '封面图',
  `posters` varchar(125) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `status` tinyint(4) NOT NULL COMMENT '状态 -1=>下架,1=>上架,2=>预售,0=>未上架',
  `state` tinyint(4) NOT NULL DEFAULT '0' COMMENT '审核状态 -1 审核失败 0 未审核 1 审核成功',
  `is_package` enum('0','1') COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '0' COMMENT '是否是套餐',
  `is_integral` enum('0','1') COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '0' COMMENT '是否是积分产品',
  `sort` int(11) NOT NULL DEFAULT '99' COMMENT '排序',
  `deleted_at` timestamp NULL DEFAULT NULL,
  `created_at` timestamp NULL DEFAULT NULL,
  `updated_at` timestamp NULL DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=24 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

system_attribute

系统规格表

CREATE TABLE `system_attribute` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `category_id` int(11) NOT NULL COMMENT '商品类别编号',
  `name` varchar(25) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '属性名称',
  `sort` int(11) NOT NULL DEFAULT '999' COMMENT '排列次序',
  PRIMARY KEY (`id`),
  KEY `product_attribute_category_id_name_index` (`category_id`,`name`)
) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

system_attribute_option

系统属性表

CREATE TABLE `product_attribute_option` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(125) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '选项名称',
  `attr_id` int(11) NOT NULL COMMENT '属性编码',
  `sort` int(11) NOT NULL DEFAULT '999' COMMENT '排序',
  PRIMARY KEY (`id`),
  KEY `product_attribute_option_name_attr_id_index` (`name`,`attr_id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

product_attribute_and_option

规格属性绑定表

CREATE TABLE `product_attribute_and_option` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `sku_id` int(11) NOT NULL COMMENT 'sku编码',
  `option_id` int(11) NOT NULL DEFAULT '0' COMMENT '属性选项编码',
  `attribute_id` int(11) NOT NULL COMMENT '属性编码',
  `sort` int(11) NOT NULL DEFAULT '999' COMMENT '排序',
  `supplier_option_id` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `product_attribute_and_option_sku_id_option_id_attribute_id_index` (`sku_id`,`option_id`,`attribute_id`)
) ENGINE=InnoDB AUTO_INCREMENT=6335 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

product_sku

sku表

CREATE TABLE `product_sku` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `product_id` int(11) NOT NULL COMMENT '商品编码',
  `name` varchar(125) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT 'sku名称',
  `img` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '主图',
  `price` decimal(8,2) NOT NULL COMMENT '价格',
  `stock` int(11) NOT NULL DEFAULT '0' COMMENT '库存',
  `code` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '商品编码',
  `barcode` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '商品条形码',
  `data` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT 'sku串',
  PRIMARY KEY (`id`),
  KEY `product_sku_name_product_id_index` (`name`,`product_id`)
) ENGINE=InnoDB AUTO_INCREMENT=530 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

product_attribute

自定义规格表

CREATE TABLE `product_attribute` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `product_id` int(11) NOT NULL COMMENT '商品编码',
  `name` varchar(125) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '规格名称',
  `sort` int(11) NOT NULL DEFAULT '999' COMMENT '排序',
  PRIMARY KEY (`id`),
  KEY `product_supplier_attribute_name_product_id_index` (`name`,`product_id`)
) ENGINE=InnoDB AUTO_INCREMENT=40 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

致谢

其实在商品的设计层面看懂后还是很简单的,后续文章主要讲解的更多的是这些数据该如何存储更合理。如果设计不合理例如商品添加很简单,但是修改商品就很复杂。在前期设计上我们要尽量避免这些“坑”

谢谢你看到这里,希望我的文章能够帮助到你。有什么问题可以在评论区留言,我看到会第一时间回复。谢谢

查看原文

rexwong 收藏了文章 · 11月3日

电商系统设计之订单

timg?image&quality=80&size=b9999_10000&sec=1532631649974&di=1d2a5259543900a105826e512fb6e8a3&imgtype=0&data-original=http%3A%2F%2Fpic.cifnews.com%2Fupload%2F201503%2F23%2F201503230925232295.jpg

前言

用户交易将经历一段艰辛的历程,一般用户感觉不到,实际程序是经历了一段生死离别。具体付款流程如下

clipboard.png

不(wo)是(gu)这(yi)张(chuan)图(de),请看正经流程图

clipboard.png

之前的几篇文章介绍了

  • 购物车如何设计
  • 用户系统如何设计
  • 商品系统如何设计

其实他们都在为交易系统做铺垫,一个产品如果没有收入,那这只能是寺庙的公益产品。任何产品最终都要走向这步 (收钱)。

付款

用户付款过程中有很多场景也会出现意外,以下是我碰到的“天灾人祸”

成功

  • 用户发起微信支付并成功支付
  • 用户发起支付宝支付并成功支付
  • 用户发起银联支付并成功支付
  • 用户发起其他支付并成功支付

人祸

  • 用户发起微信支付但取消支付
  • 用户发起支付宝支付但取消支付
  • 用户发起银联支付但取消支付
  • 用户发起其他支付但取消支付

天灾

  • 用户发起微信支付“手机爆炸了”
  • 用户发起支付宝支付“瞬间没网了”
  • 用户发起银联支付“老婆来电话了”
  • 用户发起其他支付“老板进来了”

注释

遇到以上的情况,不要害怕、不要惊慌,并且不要“理会”,你只需要将这些操作记录下来即可。
正常我们都会将用户通过哪种支付方式存储到订单表中,方便查询。我想说这种做法没错,但是少了点什么,你应该有一张交易记录表,来记录用户发起了多少次支付,只有支付成功的时候方可记录到订单表中。这样做的优点有以下两点

  • 订单表是比较重要的,迫不得已尽量不要操作这张表,防止出现意外,订单表除了收货发货外一般没有其他需要操作的地方。
  • 可以记录每次用户发起支付的时间,通过所谓大数据分析用户对产品的需求度和认可度,如果用户多次发起付款但取消支付,那就说明(他没钱)他可能很期望得到,但是因为某种原因一直在犹豫,这个时候可以针对当前用户做优惠处理,例如发一张优惠券等等。

clipboard.png

表结构

交易表

CREATE TABLE `transaction` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `order_sn` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '交易单号',
  `member_id` bigint(20) NOT NULL COMMENT '交易的用户ID',
  `amount` decimal(8,2) NOT NULL COMMENT '交易金额',
  `integral` int(11) NOT NULL DEFAULT '0' COMMENT '使用的积分',
  `pay_state` tinyint(4) NOT NULL COMMENT '支付类型 0:余额 1:微信 2:支付宝 3:xxx',
  `source` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '支付来源 wx app web wap',
  `status` tinyint(4) NOT NULL DEFAULT '0' COMMENT '支付状态 -1:取消 0 未完成 1已完成 -2:异常',
  `completion_time` int(11) NOT NULL COMMENT '交易完成时间',
  `note` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '备注',
  `created_at` timestamp NULL DEFAULT NULL,
  `updated_at` timestamp NULL DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `transaction_order_sn_member_id_pay_state_source_status_index` (`order_sn`(191),`member_id`,`pay_state`,`source`(191),`status`)
) ENGINE=InnoDB AUTO_INCREMENT=36 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

支付记录表

CREATE TABLE `transaction_record` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `order_sn` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
  `events` text COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '事件详情',
  `result` text COLLATE utf8mb4_unicode_ci COMMENT '结果详情',
  `created_at` timestamp NULL DEFAULT NULL,
  `updated_at` timestamp NULL DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=36 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

这个记录表可能让你匪夷所思,不知你对日志有什么概念,但我能说的就是,将用户的所有动作全部记录下来。这是很重要的,早晚你会懂。

订单表

CREATE TABLE `order` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `order_no` varchar(100) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '订单编号',
  `order_sn` varchar(100) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '交易号',
  `member_id` int(11) NOT NULL COMMENT '客户编号',
  `supplier_id` int(11) NOT NULL COMMENT '商户编码',
  `supplier_name` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '商户名称',
  `order_status` tinyint(4) NOT NULL DEFAULT '0' COMMENT '订单状态 0未付款,1已付款,2已发货,3已签收,-1退货申请,-2退货中,-3已退货,-4取消交易',
  `after_status` tinyint(4) NOT NULL DEFAULT '0' COMMENT '用户售后状态 0 未发起售后 1 申请售后 -1 售后已取消 2 处理中 200 处理完毕',
  `product_count` int(11) NOT NULL DEFAULT '0' COMMENT '商品数量',
  `product_amount_total` decimal(12,4) NOT NULL COMMENT '商品总价',
  `order_amount_total` decimal(12,4) NOT NULL DEFAULT '0.0000' COMMENT '实际付款金额',
  `logistics_fee` decimal(12,4) NOT NULL COMMENT '运费金额',
  `address_id` int(11) NOT NULL COMMENT '收货地址编码',
  `pay_channel` tinyint(4) NOT NULL DEFAULT '0' COMMENT '支付渠道 0余额 1微信 2支付宝',
  `out_trade_no` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '订单支付单号',
  `escrow_trade_no` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '第三方支付流水号',
  `pay_time` int(11) NOT NULL DEFAULT '0' COMMENT '付款时间',
  `delivery_time` int(11) NOT NULL DEFAULT '0' COMMENT '发货时间',
  `order_settlement_status` tinyint(4) NOT NULL DEFAULT '0' COMMENT '订单结算状态 0未结算 1已结算',
  `order_settlement_time` int(11) NOT NULL DEFAULT '0' COMMENT '订单结算时间',
  `is_package` enum('0','1') COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '0' COMMENT '是否是套餐',
  `is_integral` enum('0','1') COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '0' COMMENT '是否是积分产品',
  `created_at` timestamp NULL DEFAULT NULL,
  `updated_at` timestamp NULL DEFAULT NULL,
  `deleted_at` timestamp NULL DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `order_order_sn_unique` (`order_sn`),
  KEY `order_order_sn_member_id_order_status_out_trade_no_index` (`order_sn`,`member_id`,`order_status`,`out_trade_no`(191))
) ENGINE=InnoDB AUTO_INCREMENT=44 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

运输

用户付款结束后接下来就是快递公司的事了,当然咱们不搭理送快递的。到这一步我们就应该给客户展示运输信息。现在一些api开放平台都有快递查询的服务,有收费有免费的,性能方面差异也不大。但这里要注意一点。不是每次用户都会查询到新的信息。对于小公司来说,这样成本极高。所以我们应该定时去查询快递物流信息。这个地方有个简单的算法。

if(用户点击查看了){
    从用户点击查看两小时后更新物流信息 // 这里是按照两小时来更新的,也可以拉长这个时间
}else{
    每两小时更新一次物流信息
}

这种频繁的更新绝对要使用nosql,当用户确认收货后再存储到mysql等数据库中。

收货

当用户收到货后,这其实是最难伺候的时候,用户对产品的各种不满意就可能导致退换货,收货操作既改变订单状态为已收货,复杂点的可能还需要im,短信,推送提醒下。一般都直接提醒,量大的话加入队列内处理。

退换货

退换货淘宝是这样处理的。
淘宝将订单分两种状态

  • 未付款、已付款、已收货、已评价
  • 发起售后、售后审核、售后处理、处理完成

clipboard.png

图1展示了每个商品,包括子商品都可以单独发起售后

clipboard.png

图2是点击申请售后之后的页面

clipboard.png

图3是选择退换货的相关事项

当完成这些步骤后,就会开启售后审核,卖家审核成功后方可进行下一步操作

售后申请表

CREATE TABLE `order_returns_apply` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `order_no` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '订单单号',
  `order_detail_id` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '子订单编码',
  `return_no` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '售后单号',
  `member_id` int(11) NOT NULL COMMENT '用户编码',
  `state` tinyint(4) NOT NULL COMMENT '类型 0 仅退款 1退货退款',
  `product_status` tinyint(4) NOT NULL DEFAULT '0' COMMENT '货物状态 0:已收到货 1:未收到货',
  `why` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '退换货原因',
  `status` tinyint(4) NOT NULL DEFAULT '0' COMMENT '审核状态 -1 拒绝 0 未审核 1审核通过',
  `audit_time` int(11) NOT NULL DEFAULT '0' COMMENT '审核时间',
  `audit_why` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '审核原因',
  `note` text COLLATE utf8mb4_unicode_ci COMMENT '备注',
  `created_at` timestamp NULL DEFAULT NULL,
  `updated_at` timestamp NULL DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

售后表

CREATE TABLE `order_returns` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `returns_no` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '退货编号 供客户查询',
  `order_id` int(11) NOT NULL COMMENT '订单编号',
  `express_no` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '物流单号',
  `consignee_realname` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '收货人姓名',
  `consignee_telphone` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '联系电话',
  `consignee_telphone2` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '备用联系电话',
  `consignee_address` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '收货地址',
  `consignee_zip` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '邮政编码',
  `logistics_type` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '物流方式',
  `logistics_fee` decimal(12,2) NOT NULL COMMENT '物流发货运费',
  `order_logistics_status` int(11) DEFAULT NULL COMMENT '物流状态',
  `logistics_settlement_status` int(11) DEFAULT NULL COMMENT '物流结算状态',
  `logistics_result_last` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '物流最后状态描述',
  `logistics_result` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '物流描述',
  `logistics_create_time` int(11) DEFAULT NULL COMMENT '发货时间',
  `logistics_update_time` int(11) DEFAULT NULL COMMENT '物流更新时间',
  `logistics_settlement_time` int(11) DEFAULT NULL COMMENT '物流结算时间',
  `returns_type` tinyint(4) NOT NULL DEFAULT '0' COMMENT '0全部退单 1部分退单',
  `handling_way` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT 'PUPAWAY:退货入库;REDELIVERY:重新发货;RECLAIM-REDELIVERY:不要求归还并重新发货; REFUND:退款; COMPENSATION:不退货并赔偿',
  `returns_amount` decimal(8,2) NOT NULL COMMENT '退款金额',
  `return_submit_time` int(11) NOT NULL COMMENT '退货申请时间',
  `handling_time` int(11) NOT NULL COMMENT '退货处理时间',
  `remark` text COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '退货原因',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

评价

如果用户收货后直接评价了,那恭喜你,这笔订单基本成交了。这个没什么可讲的,一般小的电商也没有刷评价的,类似淘宝的防止刷评价的做法太过于复杂,这里也不过多讲解(其实我也没接触过)。

评价数据表

CREATE TABLE `order_appraise` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `order_id` int(11) NOT NULL COMMENT '订单编码',
  `info` text COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '评论内容',
  `level` enum('-1','0','1') COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '级别 -1差评 0中评 1好评',
  `desc_star` tinyint(4) NOT NULL COMMENT '描述相符 1-5',
  `logistics_star` tinyint(4) NOT NULL COMMENT '物流服务 1-5',
  `attitude_star` tinyint(4) NOT NULL COMMENT '服务态度 1-5',
  `created_at` timestamp NULL DEFAULT NULL,
  `updated_at` timestamp NULL DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `order_appraise_order_id_index` (`order_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

致谢

感谢你看到这里,希望我的文章和代码可以帮助到你。如果有什么疑问可以在评论区留言,谢谢

查看原文

rexwong 关注了用户 · 9月12日

CrazyCodes @crazycodes

https://github.com/CrazyCodes... 我的博客
_
| |__ __ _
| '_ | | | |/ _` |
| |_) | |_| | (_| |
|_.__/ \__,_|\__, |

         |___/   感谢生命可以让我成为一名程序员

                         CrazyCodes To Author

关注 4673

rexwong 关注了专栏 · 9月12日

Grace development

记录分享开发、学习中的点点滴滴

关注 4671

rexwong 关注了专栏 · 9月12日

code-craft

spring boot , docker and so on 欢迎关注微信公众号: geek_luandun

关注 721

rexwong 收藏了文章 · 2018-03-20

多模型融合推荐算法在达观数据的运用

研发背景

互联网时代也是信息爆炸的时代,内容太多,而用户的时间太少,如何选择成了难题。电商平台里的商品、媒体网站里的新闻、小说网站里的作品、招聘网站里的职位……当数量超过用户可以遍历的上限时,用户就无所适从了。

对海量信息进行筛选、过滤,将用户最关注最感兴趣的信息展现在用户面前,能大大增加这些内容的转化率,对各类应用系统都有非常巨大的价值。

搜索引擎的出现在一定程度上解决了信息筛选问题,但还远远不够,其存在的两个主要弊端是:第一搜索引擎需要用户主动提供关键词来对海量信息进行筛选。当用户无法准确描述自己的需求时,搜索引擎的筛选效果将大打折扣,而用户将自己的需求和意图转化成关键词的过程有时非常困难(例如“找家附近步行不太远就可以到的餐厅,别太辣的”)。更何况用户是懒惰的,很多时候都不愿意打字。第二是搜索结果往往会照顾大多数用户的点击习惯,以热门结果为主,很难充分体现出个性化需求。

解决这个问题的最好工具就是——推荐系统(Recommendation System)。

推荐系统的效果好坏,体现在推荐结果的用户满意度上,按不同的应用场景,其量化的评价指标包括点击率、成交转化率、停留时间增幅等。为了实现优秀的推荐效果,众多的推荐算法被提出,并在业界使用。但是其中一类方法非常特殊,我们称为多模型融合算法。融合算法的意思是,将多个推荐算法通过特定的方式组合的方法。融合在推荐系统中扮演着极为重要的作用,本文结合达观数据的实践经验为大家进行系统性的介绍。(达观数据 纪达麒)

为什么需要融合推荐算法

推荐系统需要面对的应用场景往往存在非常大的差异,例如热门/冷门的内容、新/老用户,时效性强/弱的结果等,这些不同的上下文环境中,不同推荐算法往往都存在不同的适用场景。不存在一个推荐算法,在所有情况下都胜过其他的算法。而融合方法的思想就自然而然出现了,就是充分运用不同分类算法各种的优势,取长补短,组合形成一个强大的推荐框架。俗话说就叫“三个臭皮匠顶个诸葛亮”。

在介绍融合方法前,先简单介绍几类常见推荐算法的优缺点

基于物品的协同过滤(Item-based Collaborative Filtering)是推荐系统中知名度最高的方法,由亚马逊(Amazon)公司最早提出并在电商行业内被广泛使用。


图片地址图片描述

基于物品的协同过滤在面对物品冷启动(例如新上架物品),或行为数据稀疏的情况下效果急剧下降。另外,基于物品的协同过滤倾向于为用户推荐曾购买过的类似商品,通常会出现多样性不足、推荐惊喜度低的问题。

而另一类协同过滤方法,基于用户的协同过滤(User-based Collaborative Filtering)方法,其公式略有不同:


图片地址图片描述

基于用户的协同过滤在推荐结果的新颖性方面有一定的优势,但是推荐结果的相关性较弱,而且容易受潮流影响,推荐大众热门物品。同时新用户或低活跃用户也会遇到用户冷启动的棘手问题。

还有一类方法称为基于模型的方法。常见的有隐语义与矩阵分解模型(Latent Factor Model),LFM对评分矩阵通过迭代的方法进行矩阵分解,原来评分矩阵中的missing value可以通过分解后的矩阵求得。


图片描述

在达观数据的实践经验里,LFM通常是推荐精度较好的一类计算模型。但当数据规模大时其运算性能会明显降低,同时计算依赖全局信息,因而很难作增量更新,导致实际工程中会遇到不少困难。而且隐语义模型还存在调整困难、可解释性差等问题。

基于内容的推荐算法(Content-based Recommendation)是最直观的推荐算法,这个方法实现简单方便,不存在冷启动问题,应对的场景丰富,属于“万金油”型打法。例如按同类别、同标签等进行推荐。但在一些算法公开评测中,基于内容的方法效果都是效果较差的。原因时基于内容的方法缺少用户行为的分析,存在“结果相关但是不是用户想要的”这样难以克服的问题。同时该算法往往受限于对文本、图像或音视频内容分析的技术深度,很难准确把握住用户真正关注的“内容点”。

基于统计思想的一些方法,例如Slope One,关联规则(Association Rules),或者分类热门推荐等,计算速度快,但是对用户个性化偏好的描述能力弱,实际应用时也存在各种各样的问题,在此不多赘述。

即使相同的算法,当使用不同数据源时也会产生不同的推荐结果。比如协同过滤,使用浏览数据和使用交易数据得到的结果就不一样。使用浏览数据的覆盖面比较广,而使用交易数据的偏好精度比较高。

常见的多模型融合算法

达观数据的众多实践发现,多模型融合算法可以比单一模型算法有极为明显的效果提升。但是怎样进行有效的融合,充分发挥各个算法的长处?这里总结一些常见的融合方法:

1)线性加权融合法

线性加权是最简单易用的融合算法,工程实现非常方便,只需要汇总单一模型的结果,然后按不同算法赋予不同的权重,将多个推荐算法的结果进行加权,即可得到结果:


图片描述

Score("u,i" )是给用户(user)推荐商品(item)的得分, β_k是算法K的权重,rec_k (u,i)是算法k得到的用户(user)对商品item的推荐得分。这种融合方式实现简单,但效果较差。因为线性加权的参数是固定的,实践中参数的选取通常依赖对全局结果升降的总结,一旦设定后,无法灵活的按照不同的推荐场景来自动变换。比如如果某个场景用算法A效果较好,另外一种场景用算法B效果较好,线性融合的方式在这种情况下不能取得好的效果。为了解决这个问题,达观数据进行了改进,通过引入动态参数的机制,通过训练用户对推荐结果的评价、与系统的预测是否相符生成加权模型,动态的调整权重使得效果大幅提升。

2) 交叉融合法

交叉融合常被称为Blending方法,其思路是在推荐结果中,穿插不同推荐模型的结果,以确保结果的多样性。

这种方式将不同算法的结果组合在一起推荐给用户


图片描述

交叉融合法的思路是“各花入各眼”,不同算法的结果着眼点不同,能满足不同用户的需求,直接穿插在一起进行展示。这种融合方式适用于同时能够展示较多条结果的推荐场景,并且往往用于算法间区别较大,如分别基于用户长期兴趣和短期兴趣计算获得的结果。(达观数据 纪达麒 陈运文)

3)瀑布融合法

瀑布型(Waterfall Model)融合方法采用了将多个模型串联的方法。每个推荐算法被视为一个过滤器,通过将不同粒度的过滤器前后衔接的方法来进行:


图片描述

在瀑布型混合技术中,前一个推荐方法过滤的结果,将作为后一个推荐方法的候选集合输入,层层递进,候选结果在此过程中会被逐步遴选,最终得到一个量少质高的结果集合。这样设计通常用于存在大量候选集合的推荐场景上。

设计瀑布型混合系统中,通常会将运算速度快、区分度低的算法排在前列,逐步过渡为重量级的算法,让宝贵的运算资源集中在少量较高候选结果的运算上。在面对候选推荐对象(Item)数量庞大,而可曝光的推荐结果较少,要求精度较高、且运算时间有限的场景下,往往非常适用。

4)特征融合法

不同的原始数据质量,对推荐计算的结果有很大的影响。以用户兴趣模型为例,我们既可以从用户的实际购买行为中,挖掘出用户的“显式”兴趣,又可以用用户的点击行为中,挖掘用户“隐式”兴趣;另外从用户分类、人口统计学分析中,也可以推测用户偏好;如果有用户的社交网络,那么也可以了解周围用户对该用户兴趣的影响。

所以通过使用不同的数据来源,抽取不同的特征,输入到推荐模型中进行训练,然后将结果合并。这种思路能解决现实中经常遇到的数据缺失的问题,因为并非所有用户都有齐全的各类数据,例如有些用户就缺少交易信息,有些则没有社交关系数据等。通过特征融合的方法能确保模型不挑食,扩大适用面。

5)预测融合法

推荐算法也可以被视为一种“预测算法”,即我们为每个用户来预测他接下来最有可能喜欢的商品。而预测融合法的思想是,我们可以对每个预测算法再进行一次预测,即不同的算法的预测结果,我们可以训练第二层的预测算法去再次进行预测,并生成最终的预测结果。

如下图所示,我们把各个推荐算法的预测结果作为特征,将用户对商品的反馈数据作为训练样本,形成了第二层预测模型的训练集合,具体流程如下


图片描述

图中的二层预测模型可以使用常用的分类算法,如SVM、随机森林、最大熵等,但达观实践中,融合效果较好的是GBDT(Gradient Boosting Decision Tree)方法。

6)分类器Boosting思想

推荐问题有时也可以转化为模式分类(Pattern Classification)问题去看待,我们将候选集合是否值得推荐划分为几个不同的集合,然后通过设计分类器的方法去解决。这样一来我们就可以用到分类算法中的Boosting思想,即将若干个弱分类器,组合成一个强分类器的方法。Boosting的核心思想是每轮训练后对预测错误的样本赋以较大的权重,加入后续训练集合,也就是让学习算法在后续的训练集中对较难的判例进行强化学习,从而得到一个带权重的预测函数序列h,预测效果好的预测函数权重较大,反之较小。最终的预测函数H对分类问题采用有权重的投票方式,对回归问题采用加权平均的方法对新示例进行判别。算法的流程如下:(参考自treeBoost论文)


图片描述

通过模型进行融合往往效果最好,但实现代价和计算开销也比较大。

达观的多级融合技术

在达观数据(http://datagrand.com)的实践中,采用的多级融合架构如下:


图片描述

Online系统
直接面向用户,是一个高性能和高可用性的推荐服务,其中的Online Ensemble模块会融合Nearline计算的推荐结果以及基于content Base的推荐结果。Online系统往往请求压力比较大,需要在较短的时间内返回结果,所以这里往往使用最简单的优先级融合算法。

Nearline系统
这个系统部署在服务端,一方面会接收User Behavior Log,根据用户最新的动作行为,生成推荐结果,并且和Offline Model进行融合,达观这边使用通过点击反馈进行调整的线性融合方法,具体方法如下,

  • Nearline获取用户的展现日志和点击日志。展现日志包括了用户展现的哪些item,以及这些item是通过什么算法推荐出来,推荐的位置,以及对应的权重

  • 如果是展现日志,则减小推荐出item对应策略的权重,更新方式如下

图片描述

β_k^' 是更新后的权重,Ctr_i是展现位置i的平均点击率,Score_k是算法K对该item的得分。Score_item是该item的总得分。ℷ是位置点击率的衰减常数、E是算法点击率的衰减常数,可以根据具体的业务场景设置不同的值。

  • 如果是点击日志,则增加推荐出item的对应策略的权重,更新方式如下

图片描述

β_k^' 是更新后的权重,Score_k是算法K对该item的得分,Score_item是该item的总得分, ∂是点击衰减常数

  • 根据更新后的权重,重新计算该用户的推荐结果。

通过这种融合方式,会为每个用户生成一个加权线性融合算法的Model,根据这个Model计算出对应的推荐结果。(达观数据 纪达麒)

Offline系统
挖掘长期的、海量的用户行为日志。以优化点击率为例,我们可以把用户的展现过的item,以及是否点击形成训练数据,我们就需要生成一个是否点击的分类模型。我们的分类器分为两个Level: L1层和L2层。L1层是基础分类器,可以使用协同过滤、矩阵分解、contentbase等基础算法;L2层基于L1层,将L1层的分类结果形成特征向量,再组合一些其他的特征后,形成L2层分类器(如GBDT)的输入。

Ensemble的训练过程稍微复杂,因为L1层模型和L2层模型要分别进行训练后再组合。实践中我们将训练样本按照特定比例切分开,分别简称为Train pig和Test Pig。基于划分后的样本,整个训练过程步骤如下:

-列表项目

  • 使用Train pig抽取特征,形成特征向量后训练L1层模型

  • 使用训练好的L1层模型,预测Test pig,将预测结果形成L2层的输入特征向量

  • 结合其他特征后,形成L2层的特征向量,并使用Test pig训练L2层模型

  • 使用全部训练样本(Tain pig + Test pig)重新训练L1层模型
    将待测样本Test抽取特征后先后使用上述训练好的L1层模型生成预测结果,再把这些结果通过L2层Ensemble模型来生成最终的预测结果

达观在使用过程中的一些心得如下
1)算法融合的特征除了算法预测值之外,也可以加入场景特征。比如在场景1算法A效果较好,场景2中算法B效果较好,当我们把场景也作为特征进行融合,就可以学习出这种特征
2)数据切分一定要干净。往往容易犯的错误是基础算法用的一些词典使用了全部的数据,这会使得融合算法效果大打折扣,因为相当于基础算法已经提前获知了融合算法的测试数据
3)基础算法的区分度越好,融合算法的效果越好,比较不容易出现过拟合
4)L2层也一样可能出现过拟合(Overfitting),所以也可以加交叉验证,L2层示意图如下图所示


图片描述

总结和展望
推荐系统中的融合技术是非常重要的一个环节,在实战中,灵活运用融合技术可以发挥各个算法的长处,满足多样的用户需求,大大提升推荐结果的质量,达观数据在此方面将不懈努力,探索出更多更好的应用。(达观数据 纪达麒)

查看原文

rexwong 收藏了文章 · 2018-03-20

推荐系统中所使用的混合技术介绍

文/陈运文

在推荐系统实际运用中,各种混合技术是其中一项极为重要的核心技术。在工程实践中我们发现,混合技术对提升推荐效果、改进推荐系统的性能等都有重要意义,因此本文对该专题进行如下的一些总结和介绍。

引言

在这个信息爆炸的时代,消费者面临众多选择、未知的领域、过载的信息时,往往无所适从;然而与此同时,内容的生产者(例如商家)也在苦苦寻觅合适的用户,寻找最便捷的渠道,而解决这两类矛盾的最好工具就是推荐系统。

推荐系统缘起于搜索系统,在底层系统上两者有大量相通的技术,但是在相应用户需求和产生应用的场景上,推荐系统离用户更进一步:当用户的需求具体而明确时,他搜索;但当用户需求不明确或难以表达时,他需要推荐。另一方面,当用户需要找某个领域下公认的、热门的内容时,他搜索;但当用户需要找个性化的内容时,他需要推荐。很多场景下,用户的个性化需求是很难转化为简短明确的查询词的,例如“今天中午想找个附近的、符合我口味的、消费不贵的餐馆”这样的需求,非常常见但很难用查询词来表达清楚。推荐系统恰好可以填补这个空白,根据挖掘用户历史行为来将个性化的需求深入挖掘清楚,实现用武之地。

目前在电商、视频、文学、社交网络等等各类网站或应用中,推荐系统都开始扮演起一个越来越重要的角色。但是无论应用于什么系统,归根结底最关键的是必须保证高质量的推荐效果。

撇开产品、交互设计、基础数据等方面,如果从系统和算法的角度来看,混合推荐的思路是其中最为重要的部分。毫不夸张的说,在真实世界的应用中,无论产品规模的大或小、用户的多与少,只要是想要追求推荐效果的高水准,那么混合推荐一定是必不可少的一门绝技。原因为何?——下面来作个解释

为什么要有混合技术

推荐技术发展至今已经历了十余年,这期间众多的算法被提出并在业界运用,经过大量的实践,人们发现似乎没有任何一个方法可以独领风骚、包打天下,每种推荐方法都有其局限性,下面举些典型的例子说明:

基于物品的协同过滤(Item-based Collaborative Filtering)是推荐系统中知名度最高的方法,由亚马逊(Amazon)公司最早提出并在电商行业内被广泛使用。但基于物品的协同过滤在面对物品冷启动,以及数据稀疏的情况下效果急剧下降。同时基于物品的协同过滤倾向于推荐用户购买过商品的类似商品,往往会出现多样性不足、推荐惊喜度低的问题。

基于用户的协同过滤(User-based Collaborative Filtering)方法在推荐结果的新颖性方面有一定的优势,但是推荐结果的相关性较弱,且容易受潮流影响而倾向于推荐出大众性物品。同时新用户或低活跃用户也会遇到冷启动(Cold-Start)的棘手问题。

在多个推荐算法竞赛中,我们发现隐语义与矩阵分解模型(Latent Factor Model)及其各种改进升级方法(包括SVD++等)是推荐精度最好的单一模型方法,但当数据规模大时其运算性能会明显降低,同时基于MF的方法依赖全局进行计算信息,因而很难作增量更新,导致实际工程中会遇到不少困难。另外,隐语义模型还存在调整困难、可解释性差等问题。

基于内容的推荐算法(Content-based Recommendation)是最直观的推荐算法,这种方法实现简单,不存在冷启动问题,应对的场景丰富,属于“万金油”型打法。但在一些算法公开评测中,基于内容的方法效果都是垫底的之一。同时该算法依赖内容的描述程度,往往受限于对文本、图像或音视频内容进行分析的深度。

基于统计思想的一些方法,例如Slope One,关联规则(Association Rules),或者分类热门推荐等,计算速度快,但是对用户个性化偏好的描述能力弱,实际应用时也存在各种各样的问题,在此不多赘述。

怎样混合是个问题

解决各种推荐方法“硬伤”的一条最好的解决途径就是混合技术——它的思路非常明确,俗称“三个臭皮匠顶个诸葛亮”——即综合运用各种方法的优势、扬长避短,组合起来成为一个效果强大的系统。

道理虽然简单,但是怎样组合才能真正发挥威力?联想到一个有趣的电影片段:周星驰的喜剧电影《国产零零漆》中,神志不清的特工达文西“发明”了一个“要你命3000”的武器,这个“超级武器霸王”把一堆街头武器——“西瓜刀、铁链、火药、硫酸、毒药、手枪、手榴弹、杀虫剂”——用绳子绑在一起,但是完全没有作用,被对手一枪击毙。

在实际应用中,从系统、算法、结果、处理流程等不同的角度,都有一些具体的混合策略。下面依次从不同的角度来进行介绍。

多段组合混合推荐框架

推荐系统一方面要处理海量的用户、物品的数据,一方面要实时相应线上用户的请求,迅速的生成结果并返回。在这里存在一个矛盾是,离线数据挖掘(例如常见的Hadoop系统)虽然擅长处理大量数据,但运算周期长(小时级或天级)、实时推荐能力差,而在线系统由于要迅速(例如几十毫秒)计算出推荐结果,无法承担过于消耗资源的算法。

请输入图片描述
图1:Netflix的Online-Nearline-Offline混合推荐系统

在业界实际部署时,解决此类常见问题的流行方法是采用三段式混合系统:即Online-Nearline-Offline Recommendation(在线-近线-离线)三层混合机制。曾经举办过著名的国际推荐竞赛的Netflix公司,在所公开的后台推荐系统架构中,即采用了该混合系统(如图1)。

其中Online系统直接面向用户,是一个高性能和高可用性的推荐服务,在这里通常会设计有缓存(Cache)系统,来处理热门的请求(Query)重复计算的问题。而当Cache不命中的情况下,Online推荐运行一个运算简单可靠的算法,及时生成结果。Online系统后是Nearline系统,这个系统部署在服务端,一方面会接收Online系统发过来的请求,将Online计算的一些缓存结果,采用更复杂的算法重新计算并更新后更新缓存。另一方面Nearline是衔接Online和Offline系统的桥梁,因为Offline结果往往会挖掘长期的、海量的用户行为日志,消耗的资源大、挖掘周期长,但是Offline推荐系统计算所得的结果质量往往是最高的,这些结果会通过Nearline系统输送到线上,发挥作用。

另外一个不可忽视的问题是用户反馈的及时收集,并及时用于调整推荐结果。挖掘用户的反馈对调整推荐结果有莫大的帮助,但这个调整往往越及时越好,否则用户很容易对结果不满意而流失。这个点击挖掘和反馈的功能往往由Nearline推荐系统来承担,因为该系统收集前端反馈比较方便,又可以保证适当的处理时长。

加权型混合推荐技术

上面介绍了从系统架构的角度如何进行混合。而从算法的角度来看,则最常用的是采用加权型的混合推荐技术,即将来自不同推荐算法生成的候选结果及结果的分数,进一步进行组合(Ensemble)加权,生成最终的推荐排序结果。

具体来看,比较原始的加权型的方法是根据推荐效果,固定赋予各个子算法输出结果的权重,然后得到最终结果。很显然这种方法无法灵活处理不同的上下文场景,因为不同的算法的结果,可能在不同的场景下质量有高有低,固定加权系统无法各取所长。所以更好的思路是设置训练样本,然后比较用户对推荐结果的评价、与系统的预测是否相符,根据训练得到的结果生成加权的模型,动态的调整权重。

请输入图片描述
图2:加权混合技术能明显提高推荐精度

加权混合的模型有很多,除了简单的线性模型外,常用的有回归模型(Logistic Regression)、RBM(Restricted Boltzmann Machines)、GBDT(Gradient Boosted Decision Trees),这三种混合模型在推荐算法竞赛中大放异彩,在2009年结束的Netflix百万美元推荐竞赛中,优胜队伍将充分运用和多种加权混合模型的优势,组合后的算法推荐精度非常高。获胜队的Yehuda Koren在论文The BellKor Solution to the Netflix Grand Prize中对此有非常详细的介绍。另外值得一提的是台湾大学推荐团队,他们通过混合甚至二次混合的方式(如图2),将众多单独推荐算法的结果进行最合理的加权组合,在最近几届的KDD Cup数据挖掘竞赛中所向披靡,经常取得极为优异的推荐效果。

分级型混合推荐技术

尽管上述加权组合型混合推荐技术有非常高的精度,但系统复杂度和运算负载都较高。在工业界实际系统中,往往采用一些相对简单的方案,其中分级型混合推荐技术就是一类思想简单但效果也不错的方法。这种混合推荐技术根据不同的推荐场景,将不同的推荐算法按照效果优劣进行层次性划分。在对应的推荐场景下,优先采用高可信度的推荐算法生成的结果,然后依次采用后续方法生成结果。

在各种推荐场景中,Top-N推荐是最为常见的一类。这种推荐应用有时需要展示较多的推荐结果,而此时一种推荐算法的结果往往不够丰富,通常会采用分级型的混合技术,通过事先的数据挖掘,优先将推荐精度高的算法结果先列出,然后用依次用其他方法的结果递补。不同的推荐算法往往在精度(Precision)和召回(Recall)之间有所折衷,因此优先列出高精度结果,长尾部分则采用高召回的结果进行补足,能兼顾对推荐结果数量和质量的两种需求。

交叉调和技术

交叉调和技术有些类似西方酿造威士忌(Whisky)酒的过程——将纯麦威士忌、谷物威士忌、或者不同产地、口味的陈酿进行一定比例的调配后最终成品。交叉调和推荐技术(Blending Recommendation)的主要动机是保证最终推荐结果的多样性。因为不同用户对同一件物品的着眼点往往各不相同,而不同的推荐算法,生成的结果往往代表了一类不同的观察角度所生成的结果,交叉调和技术将不同推荐算法的生成结果,按照一定的配比组合在一起,打包后集中呈现给用户。

交叉调和技术需要注意的问题是结果组合时的冲突解决问题,通常会设置一些额外的约束条件来处理结果的组合展示问题。另外我们发现为了让用户更多的注意到结果的多样性,对不同类型的推荐结果辅以展示不同的推荐理由,往往能获得更多收益。

瀑布型混合方法

瀑布型(Waterfall Model)的混合方法采用了过滤(Filtering)的设计思想,将不同的推荐算法视为不同粒度的过滤器,尤其是面对待推荐对象(Item)和所需的推荐结果数量相差极为悬殊时,往往非常适用。

在瀑布型混合技术中,前一个推荐方法过滤的结果,将输出给后一个推荐方法,层层递进,候选结果在此过程中会被逐步遴选,最终得到一个高精确的结果。设计瀑布型混合系统中,通常会将运算速度快、区分度低的算法排在前列,逐步过渡为重量级的算法,这样的优点是充分运用不同算法的区分度,让宝贵的运算资源集中在少量较高候选结果的运算上。

推荐基础特征混合技术

数据是推荐系统的基础,一个完善的推荐系统,其数据来源也是多种多样的。从这些数据来源中我们可以抽取出不同的基础特征。以用户兴趣模型为例,我们既可以从用户的实际购买行为中,挖掘出用户的“显式”兴趣,又可以用用户的点击行为中,挖掘用户“隐式”兴趣;另外从用户分类、人口统计学分析中,也可以计算出用户兴趣;如果有用户的社交网络,那么也可以了解周围用户对该用户兴趣的投射,等等。另一方面,从物品(Item)的角度来看,也可以挖掘出不同的特征。

不同的基础特征可以预先进行组合或合并,为后续的推荐算法所使用。这样处理的优点是将推荐算法切分得比较清楚,这样将一个整体的推荐问题,分解为特征的抽取、组合、使用等各个环节的优化问题,在进行个性化推荐时较为适用。

推荐模型混合技术

和特征合并的技术不同,多模型的合并技术在模型计算阶段,将整个模型作为第二种算法的输入。这种组合方式,事实上形成了一种新的独立的推荐模型。例如在进行基于用户的协同过滤计算的时候,在计算相邻用户的距离的基础上,可以进一步根据用户的属性内容(Content)信息、采用基于内容的推荐的思想,进一步生成相似用户的候选结果;或者利用用户的社交网络信息(Social Network)来扩展相邻用户集合。这种在算法设计阶段而不是特征利用或推荐结果合并阶段的混合技术,被成为推荐模型混合技术。

这种技术往往适用于数据稀疏或质量较差时,单个推荐模型结果都比较差的情况。此时对多个较差的模型的最终结果进行合并无法获得满意的结果(因为候选结果都比较差),因此提前在模型计算阶段进行算法思路的合并,这样能提前召回好的结果,提升推荐效果。

整体式混合推荐框架

除了上述的系统架构、特征、算法、推荐结果等等角度的推荐融合技术,还有很多的内容是没有包括的,例如从商业逻辑的角度来分析,商家往往有一些特定的推荐需求或者推荐规则,需要对算法生成的结果进行调整。亦或者从交互设计的角度来看,推荐结果的展示方式等都有所不同;一些特殊的应用场景可能需要强调地域、时间等信息,对应的推荐挖掘方法和展现都有特殊的要求,这个时候对结果的混合往往要从整个产品的角度来进行设计和处理,从而能够满足不同的需要,这些可以被纳入整体式的混合推荐框架中考虑。

讨论和小结

推荐效果是一个推荐系统是否能获得成功的生命线,而混合推荐技术是其中最为重要的一个环节。在各种实际应用中,广大的研发工程师在处理很多问题时,往往都从直觉出发在不同程度的使用各种混合推荐技术,也解决了很多实际问题,取得了很好的效果。本文从理论角度对此进行了梳理,希望能帮助大家提升对推荐系统的领悟和理解。心中装着进行混合的意念,并理论联系实际,对开发一个成功的推荐系统会有莫大的帮助。


转载自:推荐系统中所使用的混合技术介绍 | Resys China

查看原文

rexwong 收藏了文章 · 2018-03-19

深入了解机器学习

摘要: 了解机器学习发展史、机器学习是什么?机器学习有什么?看看本文就够了。

如今机器学习已经成为了这个时代的热门话题。机器学习已经存在了几十年,但直到最近我们才得以利用这项技术。

接下来,让我们一起回顾一下机器学习的发展历史:

图片描述

图片描述

它是怎么运行的呢?

机器学习(ML)的处理系统和算法主要通过在数据和通过找出数据里隐藏的模式进而做出预测的识别模式。这里值得一提的是,机器学习属于人工智能(AI)领域,而人工智能又与更广泛的数据挖掘和知识发现领域相交叉。

图片描述

机器学习(ML)其他用法的例子:

机器学习还可以用于下列内容:

  • 医疗保健:识别高危客户;优化诊断准确性;改进健康计划成本。
  • 社会:预测广告活动效果;预测消费者情绪或其反馈。
  • 航空:预测火箭发动机爆炸;预测试点能力;预测航线。

还有其他一些行业也希望通过利用这种技术来获得商业价值。事实上,根据普华永道2017年全球数字智商调查,54%的机构正在大量投资人工智能和机器学习。

它是如何完成的呢?

机器学习任务分为三类。

1. 监督ML:

大多数情况下,机器学习依赖于被标记为真或假的数据。

示例:教计算机学会根据人类完成的交易标签来识别潜在的欺诈性或非欺诈性交易,以确保获得高质量的数据。了解到欺诈性交易与非欺诈性交易之间的差异后,ML会自动对新交易数据进行分类以获得潜在的欺诈性活动。

2. 未受监督的ML:

与监督学习依赖于标签有所不同,该种类型的算法需要对象的各个方面提供大量的数据。

示例:在欺诈发生的情况下,提供欺诈者的各种属性以及一些交易价值,根据交易的固有特征和描述特征,无监督ML可以将交易分为两个不同的组。

3. 强化学习的ML:

示例:学习玩流行的棋盘游戏奥赛罗,ML会收到关于玩家是赢还是输的信息。该程序没有将数据库中的所有的动作都标记为赢了或输了,但却能知道整个游戏的最终结果。然后,ML可以进行多种游戏,每次都重视那些导致获胜组合的动作。

一些流行的方法:

ML中采用了多种学习方法,下面将为大家介绍一些最为常见的方法。

决策树学习:

一个预测模型,通过映射关于项目的观察结果,得出结论;使用决策节点的层次结构,当逐步回答时,可以将交易分类为欺诈或非欺诈。

clipboard.png

回归学习:

回归学习是最重要和广泛使用的机器学习和统计工具之一。它能够通过学习依赖变量和预测变量之间的关系做出数据预测。

图片描述

朴素贝叶斯学习:

这是一个概率图形模型,表示一组随机变量及其条件独立性;例如,欺诈者与交易金额,年龄,行为等之间的概率关系。

clipboard.png

神经网络学习:

神经网络学习由多个隐藏层组成,模仿人脑的行为。深度学习包括多个一个接一个的神经网络。

clipboard.png

使用机器学习打击金融诈骗:

由于金融诈骗给企业带了很大的信誉损失和财务破坏,引起了全球很多方面的关注。每年都有数百万的家庭遭受金融诈骗,经济损失达数亿美元。

曾经,有一家金融界被称为佼佼者的机构同意支付165亿美元来解决金融诈骗案。考虑到所有这些情况,将数据挖掘工具和技术用于检测可能的欺诈活动或事件变得很重要。

在研究可帮助我们识别欺诈活动的数据挖掘技术之前,首先根据2016年普华永道经济犯罪调查来查看欺诈行为。

图片描述

图片描述

排名前三的风险预测算法和案例:

三大风险预测算法和案例如下:

  • 分类方法:用于生成可能的值(即true,false,yes,no,o,1等)。这种机器学习技术可以根据各种预测变量来分类特定债务会变成“好”还是“坏”。
  • 神经网络:在包含神经元和具有输入、输出和隐藏层节点的大型数据集上显示更好的结果。这种方法通常用于使用各种人口学,年龄和其他变量作为输入来执行信用评级预测。
  • 随机决策森林:分类的集合学习方法。他们在培训和输出种类时(即分类模式)构建了许多决策树。这被广泛用于执行信用风险预测。

Beneish M-Score是另一个在财务报表欺诈领域受欢迎的新兴数学模型。该模型使用财务比率和八个变量来确定一个组织是否操纵了其收入。这些变量是根据公司财务报表中的数据构建的,一旦计算出来,就会创建一个M-Score来描述盈余被操纵的程度。请注意,作为概率模型,它不会识别100%准确度的操纵器。

结论:

机器学习的好处主要是:

  • 通过快速集成进行数据驱动的决策:机器学习利用各种数据,帮助企业根据最新的数据模式不断升级其策略。
  • 加速洞察力:机器学习能够加快识别相关数据的速度使得利益相关者能够及时行动。例如,机器学习可以不断优化客户的下一个最佳报价,因此客户在中午可能看到的内容可能与同一个客户在晚上看到的内容不同。
  • 风险规避:机器学习给企业提供了防止诈骗者陷入困境并减轻潜在货币和监管复杂化的能力。

文章原标题《Deep Dive Into Machine Learning》

作者:Sunil Kappal

更为详细的内容,请查看原文文章

查看原文

rexwong 关注了标签 · 2018-03-18

关注 33

rexwong 发布了文章 · 2018-03-17

The Universal Recommender

The Universal Recommender

The Universal Recommender (UR) is a new type of collaborative filtering recommender based on an algorithm that can use data from a wide variety of user taste indicators—it is called the Correlated Cross-Occurrence algorithm. Unlike the matrix factorization embodied in things like MLlib's ALS, The UR's CCO algorithm is able to ingest any number of user actions, events, profile data, and contextual information. It then serves results in a fast and scalable way. It also supports item properties for filtering and boosting recommendations and can therefor be considered a hybrid collaborative filtering and content-based recommender.

The use of multiple types of data fundamentally changes the way a recommender is used and, when employed correctly, will provide a significant increase in quality of recommendations vs. using only one user event. Most recommenders, for instance, can only use "purchase" events. Using all we know about a user and their context allows us to much better predict their preferences.

用户单一行为举例

UserActionItem
u1viewt1
u1viewt2
u1viewt3
u1viewt5
u2viewt1
u2viewt3
u2viewt4
u2viewt5
u3viewt2
u3viewt3
u3viewt5

整理后得到以下关系:
u1=> [ t1, t2, t3, t5 ]
u2=> [ t1, t3, t4, t5 ]
u3=> [ t2, t3,t5 ]

个性化推荐的一般模型

$r=(P^{T}P)h_{p}$

  • $r=rcommendations$
  • $h_{p}$= 某一用户的历史动作(比如购买动作)

    • $h_{u1}=\begin{bmatrix}1 & 1 & 1 & 0 & 1\end{bmatrix}$
    • $h_{u2}=\begin{bmatrix}1 & 0 & 1 & 1 & 1\end{bmatrix}$
    • 针对某个item的动作在史来情况下是有可能重复的,如果表达???

      $h_{u1}=\begin{bmatrix}1 & 2 & 1 & 0 & 1\end{bmatrix}$ 2代表了购买item2两次

      如果这么表示,那么问题来了,近期的动作和久远的动作,意义是不同的。偶尔受伤买个了拐,是不能根据这个动作就推荐拐的,LLR是不是可以消减这类情况呢?

  • $P$ = 历史所有用户的主动作(主事件)构成的矩阵

    • primary action:主动作在COO模型下才有意义,单一指标推荐,就无所谓主动作了。
    • 行代表矩阵, 列代表items

      $P=\begin{bmatrix}1 & 1 & 1& 0 & 1\\ 1 & 0 & 1 & 1 &1 \\ 0& 1& 1 & 0 & 1\end{bmatrix}$

  • $(P^{T}P)$ = compares column to column using log-likelihood based correlation test

    • $P=\begin{bmatrix}1 & 1 & 1& 0 & 1\\ 1 & 0 & 1 & 1 &1 \\ 0& 1& 1 & 0 & 1\end{bmatrix}$ $P^{T}=\begin{bmatrix}1 & 1 &0 \\ 1& 0 & 1\\ 1& 1 &0 \\ 0&1 & 1\\ 1& 1 &1 \end{bmatrix}$ $P^{T}\cdot P=\begin{bmatrix}- & 1 & 2 & 1 & 2\\ 1& - & 2 &0 &2\\2& 2& - & 1 &3 \\1& 0 & 1 & - &1\\2&2&3&1 & -\end{bmatrix}$ $P^{T}代表矩阵转置$
    • 其中$P^{T}\cdot P$ 中元素$C_{3,5}=3$ 代表有三个用户浏览$t_{3}$ 的用户同时浏览了$t_{5}$

COOCCURRENCE WITH LLR

  • Let's call ($P^{T}P$) an indicator matrix for some primary action like purchase

    • Rows = items, columns = items, element = similarity/correlation score
  • The score is row compared to column using a "similarity" or "correlation" metric
  • Log-likelihood Ratio(LLR对数似然比) finds important/correlating cooccurrences and filters out the rest —a major improvement in quality over simple cooccurrences or other similarity metrics.

    根据两个事件的共现关系计算LLR值,用于衡量两个事件的关联度

    $P^{T}\cdot P=\begin{bmatrix}- & 1 & 2 & 1 & 2\\ 1& - & 1 &1 &1\\2& 1& - & 1 &2 \\1& 1 & 1 & - &1\\2&1&2&1 & -\end{bmatrix}\overset{LLR}{\rightarrow}\begin{bmatrix}-& 1.05 & 3.82 & 1.05 &3.82 \\ 1.05 & - &1.05 &1.05 &1.05 \\ 3.82& 1.05 & - & 1.05&3.82 \\1.05&1.05 &1.05 & - &1.05 \\3.82& 1.05 & 3.82 & 1.05&-\end{bmatrix}$

    注意:我们发现每个用户都有点击广告a4,但a4的LLR值却是0,也就是a4跟任何帖子都没有关联,这看上去很奇怪。但其实这是LLR的特点,LLR对于热门事件有很大的惩罚,简单来说它认为浏览t1和点击广告a4这两个事件共同发生的原因不是因为浏览t1和点击a4有关联,而仅仅只是因为点击a4本身是一个高频发生的事件。
  • Experiments on real-world data show LLR is significantly better than ohter similarity metrics

LLR AND SIMILARITY METRICS PRECISION (MAP@K)

FROM COOCCURRENCE TO RECOMMENDATION

$r=(P^{t}P)h_{p}$

  • This actually means to take the user's history $h_{p}$ and compare it to rows of the cooccurrence matrix $(P^{t}P)$

    $h_{p}$ =P动作历史行为

  • TF-IDF weigthing of cooccurrence would be nice to mitigate the undue influence of popular items
  • Find items nearest to the user's history
  • Sort these by similarity strength and keep only the highest — you have recommendations
  • Sound familair? Find the k-nearest neighbors using cosine and TF-IDF?
  • That's exactly what a search engine does!

USER HISTORY + COOCCURRENCES + SEARCH = RECOMMENDATIONS

$r=(P^{t}P)h_{p}$

  • The final calculation uses $h_{p}$ as the query on the Cooccurrence matrix $(P^{T}P)$ , returns a ranked set of items
  • Query is a "similarity" query, not relational or key based fetch
  • Uses Search Engine as Cosine-based K-Nearest Neighbor(KNN) Engine with norms and TF-IDF weighting
  • Highly optimized for serving these queries in realtime
  • Serveral (Solr,Elasticsearch) have High Availability , massively scalable clustered auto-sharding features like the best of NoSQL DBs

UR的突破性思想

  • 几乎所有的协同过滤推荐仅仅根据一个偏好指标计算所得:

    $r=(P^{t}P)h_{p}$

  • 基于 CCO 的协同过滤推荐可以表示为:

    $r=(P^{T}P)h_{p}+(P^{T}V)h_{v}+(P^{T}C)h_{c}+…$

    • $(P^{T}P)$ =P与P的关联矩阵 $ (P^{T}V)$ =P与V的关联矩阵
    • $(P^{T}V)h_{v}+(P^{T}C)h_{c}$ 代表了CROSS-OCCURRENCE
    • $h_{p}$ =P动作历史行为 $h_{v}$ =V动作历史行为
  • 基于COO推荐,只要我们能够想到的用户指标都可以提升推荐效果—购买行为,观看行为,类别偏好,位置偏好,设备偏好,用户性别...

CORRELATED CROSS-OCCURRENCE: SO WHAT?

  • Comparting the history of the primary action to other actions finds actions that lead to the one you want to recommend
  • Given strong data about user preferences on a general population we can also use

    • items clicked
    • terms searched
    • categories viewed
    • items shared
    • people followed
    • items disliked (yes dislikes may predict likes)
    • location
    • device perference,设备偏好
    • gender
    • age bracket,年龄段, people in the 10~20 age bracket
  • Virtually any anything we know about the population can be tested for correlation and used to predict a particular users preferences

CORRELATED CROSS-OCCURRENCE; ADDING CONTENT MODELS

  • Collaborative Topic Filtering

    • Use Latent Dirichlet Allocation(LDA) to model topics directly from the textual content
    • Calculate based on Word2Vec type word vectors instead of bag-of-words analysis to boost quality
    • Create cross-occurrence indicators from topics the user has preferred
    • Repeat periodically
  • Entity Preferences:

    • Use a Named Entity Recognition(NER) system to find entities in textual content
    • Create cross-occurrence indicators for these entities
  • Entities and Topics are long lived and richly describle user interests, these are very good for use in the Universal Recommender

THE UNIVERSAL RECOMMENDER ADDING CONTENT-BASED RECS

Indicators can also be based on content similarity

$r=(TT^{t})h_{t}+I\cdot L$

$(TT^{t})$ is a calculation that compares every 2 documents to each other and finds the most similar—based upon content alone

INDICATOR TYPES

  • Cooccurences

    • Find the best indicator of a user preference for the item type to be recommended: examples are "buy", "read", "video_watch", "share", "follow", "like"
  • Cross-occurrence

    • Item metadata as "user" preference, for example : treat item category as a user category-preferences
    • Calculated from user actions on any data that may give information about user— category-preferences, search terms, gender, location
    • Create with Mahout-Samsara SimilarityAnalysis.cooccurences
  • Content or metadata

    • Content text, tags, categories, description text , anything describing an item
    • Create with Mahout-Samsara SimilarityAnalysis.rowSimilarity
  • Intrinsic

    • Popularity rank, geo-location, anyting describing an item
    • Some may be derived from usage data like popularity rank , or hotness
    • Is a known or specially calculated property of the item

THE UNIVERSAL RECOMMENDER AKA THE WHOLE ENCHILADA

"Universal" means one query on all indicators at once

$r=(P^{T}P)h_{p}+(P^{T}V)h_{v}+(P^{T}C)h_{c}+…(TT^{T}h_{t})+I\cdot L$

Unified query:

  • purchase-correlator: users-history-of-purchase
  • view-correlator: user-history-of-views
  • category-correlator: user-history-of-categories-viewed
  • tags-correlator: user-history-of-purchases
  • geo-location-correlator: user-location
  • ...

Once indicators are indexed as search fields this entire equation is a single query

Fast!

THE UNIVERSAL RECOMMENDER: BETTER USER COVERAGE

  • Any number of user actions — entire user clickstream
  • Metadata—from user proflie or items
  • Context— on-site, time, location
  • Content— unstructured text or semi-structured categorical
  • Mixes any number of "indicators" to increase quality or tune to specific context
  • Solution to the "cold-start" problem—items with too short a lifespan or new users with no history

    how to solve ??
  • Can recommend to new users using realtime history
  • Can use new interaction data from any user in realtime
  • 95% implemented in Universal Recommender

    v0.3.0—most current release

POLISH THE APPLE

  • Dithering for auto-optimize via explore-exploit:

    Randomize some returned recs, if they are acted upon they become part of the new training data and are more likely to be recommended in the future

  • Visibility control:

    • Don't show dups, blacklist items already shown
    • Filter items the user has already seen
  • Zero-downtime Deployment: deploy prediction server once the hot-swap new index when ready
  • Generate some intrinsic indicators like hot, populay— helps solve the "cold-start" problem
  • Asymmetric train vs query—query with most recent user data, train on all historical data

基于PredictionIO的UR推荐架构

参考

  1. http://ssc.io/wp-content/uploads/2011/12/rec11-schelter.pdf
  2. http://actionml.com/docs/ur
  3. http://hejunhao.me/archives/1083
查看原文

赞 0 收藏 0 评论 0

认证与成就

  • 获得 0 次点赞
  • 获得 0 枚徽章 获得 0 枚金徽章, 获得 0 枚银徽章, 获得 0 枚铜徽章

擅长技能
编辑

开源项目 & 著作
编辑

(゚∀゚ )
暂时没有

注册于 2012-10-21
个人主页被 145 人浏览