郑昀 基于刘金鑫文档 最后更新于2014/12/1

关键词:recsys、推荐评测、Evaluation of Recommender System、piwik、flume、kafka、storm、redis、mysql

本文档适用人员:研发
 
推荐系统可不仅仅是围着推荐算法打转
  先明确一下,我们属于工业领域。很多在学术论文里行之有效的新特奇算法,在工业界是行不通的。当年我们做语义聚合时,分词、聚类、相似性计算、实体词识别、情感分析等领域最终还都采用了工业界十几年前乃至于几十年前就流行的成熟算法。如果算法不能决定命运,那什么是关键呢?
  算法+规则库+人工干预(整理语料、标识、调参数等),大都是脏活儿累活儿。
  或者叫,特征+算法+人工干预,用特征缩小数据范围或降维。
  我在2009年曾经写道
在语义的世界里,可以近似地说:万事万物都是特征提取。 你只要找到特征,事情就好办。……
……你期望毕其功于一役吗?自然语言处理的真实应用里是很难有什么场景找到一个通吃特征的。都是一层一层特征叠加的。 
一层特征去掉一部分垃圾数据。如此反复,终成正果。注意方法论。
  梁斌在2012年微博说道:
统计粗且糙,乃大锤。规则细而精,乃小锤。先大场后细棋。
  规则库怎么来的?得建设一些方便观测的外围系统,才能发现特征、建立规则、调整参数、观察效果。所以与此类似,做了推荐服务后,就需要推荐效果评测了。
 
推荐评测应用场景
  电商推荐场景下有非常明确的指标:
  1. 推荐位展示次数商品投放次数
  2. 推荐位展示点击率商品投放点击率
  3. 最重要的是下单转化率成单转化率(或叫支付转化率)这两个硬指标。
  那么推荐评测系统应具备的功能有:
  1. 实时(至少是近乎实时)统计几个展示性指标
    • 区分网站端和移动客户端的推荐展示效果
    • 进一步区分不同客户端,如 iOS 和 Android
  2. 数据概览
  3. 按推荐位类型或推荐算法归纳各种指标
    • 看了又看
    • 浏览过该商品的用户购买了
    • 您可能对以下商品感兴趣(猜你喜欢)
    • 商品周边商品(注:只能是本地生活服务类商品)
    • 签到弹窗推荐
    • 商品附近门店
    • 门店周边美食
    • 附近吃喝玩乐
    • ……
  4. 常见的评测推荐效果的两种实验方法
    1. 离线试验:
      • 做法:从日志系统中取得用户的行为数据,然后将数据集分成训练数据和测试数据,比如80%的训练数据和20%的测试数据(还可以交叉验证),然后在训练数据集上训练用户的兴趣模型,在测试集上进行测试
      • 优点:它不需要实际用户的交互
      • 缺点:离线实验只能评测一个很狭窄的数据集切面,主要是关于算法预测或者评估的准确性
      • 目的:提前过滤掉性能较差的算法
    2. AB测试:
      • 做法:通过一定的规则把用户随机分成几组,并对不同组的用户采用不同的推荐算法,这样的话能够比较公平地获得不同算法在实际在线时的一些性能指标
  5. 推荐服务接口测试界面
    • 暴露出来,让我们手工就可以提交,看看效果
 
推荐评测技术选型
  说到实时日志聚合和处理,还得是 flume+kafka+storm,所以技术选型是:
  Piwik+Flume+Kafka+Storm+Redis+MySQL
 
推荐评测数据流转流程
  1. 数据上报:——Piwik
    1. 主站本身部署了 开源流量统计系统 Piwik,所以在网页的各种推荐位上按规则埋点即可
      • 实例:“浏览过该商品的用户还购买了”推荐栏第一位商品的a元素增加了wwe属性:wwe="t:goods,w:rec,id:ae45c145d1045c9d51c270c066018685,rec:101_01_103"
    2. 浏览器完全加载完成后, Piwik JavaScript 会向服务器端发送埋点数据
    3. Piwik 服务器端收到后,写磁盘日志文件
  2. 数据采集:——Flume
    1. Piwik 集群的每一台服务器上都部署了 Flume Agent
    2. agent 会向 推荐数据收集 Flume 集群 推送日志,譬如配置为每增加一行日志就推送,或每5分钟推送一次
    3. 手机客户端的埋点日志则存放在无线服务器端的 MySQL 中,所以我们用脚本每分钟读取一次数据,放到 flume 的监控目录下
  3. 数据接入:——Kafka
    1. 由于数据采集速度和数据处理速度不一定匹配,因此添加一个消息中间件 Linkedin Kafka 作为缓冲
    2. 数据流转方式为 Flume Source-->Flume Channel-->Flume Sink,那么我们写一个 Kafka Sink 作为消息生产者,将 sink 从 channel 里接收到的日志数据发送给消息消费者
  4. 流式计算:——Storm
    1. Storm 负责对采集到的数据进行实时计算
    2. Storm Spout 负责从外部系统不间断地读取数据,并组装成 tuple 发射出去,tuple 被发射后在 Topology 中传播
    3. 所以我们要写一个 Kafka Spout 作为消息消费者拉日志数据
    4. 再写些 Storm Bolt 处理数据
      • ,一个Topology的结构示意图
  5. 数据输出:——Redis
    1. Storm Bolt 实时分析数据之后,将统计结果写入 Redis
  6. 数据统计:——MySQL
    1. 评测系统实时数据直接从 Redis 中读取,并查询主站数据库追踪成单情况,同步到 MySQL 中,作为报表展示数据源
  简而言之,数据按如下方式流转:
  1. piwik javascript
  2. piwik servers
  3. flume agent
  4. 自定义 kafka sink
  5. 自定义 kafka spout
  6. 自定义 storm bolt
  7. redis
  8. 评测系统计算
  9. mysql
  10. 评测系统报表展示
 
Flume+Kafka+Storm常见问题
  虽然我们的实时流量统计和推荐评测系统均采用了 flume+kafka+storm 方案,但要注意这个方案也有一些小坑。下面摘录一些第三方的结论
  • 如果配置为每新增一条日志就采集,那么 flume 到 kafka 的实时数据可能会由于单条过快,造成 storm spout 消费 kafka 消息速率跟不上。延时可以是数据发射到 stream 中后进行 hbase 的计算操作引起的(注:hbase 的性能确实堪忧,不适合这种实时数据处理,尤其是加了较多索引之后);
    • 可参考的一个数据:storm 单条流水线的处理能力大约为 20000 tupe/s (每个tuple大小为1000字节);
    • tuple 过多,会由于 kafka 的 message 需要 new String() 进行获取,会报 gc 的异常;
    • tuple 在 stream 中的大量堆积,造成超时自动回调 fail() 的函数;
    • 可以进行多 tuple 结构的优化,把多个 log 打包成一个 tuple
    • 就一般情况而言,单条发射能扛得住
 
Kafka Sink 消息生产者代码片段
KafkaSink.java
import kafka.javaapi.producer.Producer;
……
public class KafkaSink extends AbstractSink implements Configurable {
……
 private Producer<String, byte[]> producer;
……
 @Override
 public Status process() throws EventDeliveryException {
  Channel channel = getChannel();
  Transaction tx = channel.getTransaction();
  try {
   tx.begin();
   Event e = channel.take();
   if (e == null) {
    tx.rollback();
    return Status.BACKOFF;
   }
   producer.send(new KeyedMessage<String, byte[]>(topic, e.getBody()));
   tx.commit(); 
   return Status.READY;
  } catch (Exception e) {
 
Kafka Spout 消息消费者代码片段
spout 有多个,我们挑 kafka spout 看下。
KafkaSpout.java
public abstract class KafkaSpout implements IRichSpout {
……
 @Override
 public void activate() {
……
   for (final KafkaStream<byte[], byte[]> stream : streamList) {
    executor.submit(new Runnable() {
     @Override
     public void run() {
      ConsumerIterator<byte[], byte[]> iterator = stream.iterator();
      while (iterator.hasNext()) {
       if (spoutPending.get() <= 0) {
        sleep(1000);
        continue;
       }
       MessageAndMetadata<byte[], byte[]> next = iterator.next();
       byte[] message = next.message();
       List<Object> tuple = null;
       try {
        tuple = generateTuple(message);
       } catch (Exception e) {
        e.printStackTrace();
       }
       if (tuple == null || tuple.size() != outputFieldsLength) {
        continue;
       }
       collector.emit(tuple);
       spoutPending.decrementAndGet();
      }
     }
 
Storm Bolt 代码片段
有多个自定义 bolt,挑一个看下。
EvaluateBolt.java
public class EvaluateBolt extends BaseBasicBolt {
……
 @Override
 public void execute(Tuple input, BasicOutputCollector collector) {
……
  if (LogWebsiteSpout.PAGE_EVENT_BROWSE.equals(event)) {
   if (LogWebsiteSpout.PAGE_TYPE_GOODS.equals(pageType)) {
    incrBaseStatistics(baseKeyMap, BROWSE_ALL, 1);
   } else if (LogWebsiteSpout.PAGE_TYPE_PAY1.equals(pageType)) {
    incrBaseStatistics(baseKeyMap, ORDER_ALL, 1);
   }
   String recDisplay = input.getStringByField(LogWebsiteSpout.FIELD_REC_DISPLAY);
   recDisplayStatistics(recDisplay, time, pageType, baseKeyMap);
  } else if (LogWebsiteSpout.PAGE_EVENT_CLICK.equals(event)) {
   String recType = input.getStringByField(LogWebsiteSpout.FIELD_REC_TYPE);
 

评测指标定义:

  • 投放点击率:推荐浏览量/推荐商品投放量
  • 展现点击率:推荐浏览量/推荐位展现次数
  • 推荐展示率::推荐位展示次数/总浏览量
  • 推荐浏览量:经由推荐产生的浏览量
  • 推荐商品投放量:推荐位投放的推荐商品数量(如:用户浏览A商品,那在浏览或购买推荐位产生的推荐商品为5个,则推荐商品投放量+5)
  • 推荐位展现次数:如果推荐位有推荐商品并展示,计数+1
 
-over-
 
欢迎订阅我的微信订阅号『老兵笔记』,请扫描二维码关注:

#研发解决方案介绍#Recsys-Evaluate(推荐评测)的更多相关文章

  1. #研发解决方案介绍#Tracing(鹰眼)

    郑昀 最后更新于2014/11/12 关键词:GoogleDapper.分布式跟踪.鹰眼.Tracing.HBase.HDFS. 本文档适用人员:研发   分布式系统为什么需要 Tracing?   ...

  2. #研发解决方案介绍#IdCenter(内部统一认证系统)

    郑昀 基于朱传志的设计文档 最后更新于2014/11/13 关键词:LDAP.认证.权限分配.IdCenter. 本文档适用人员:研发   曾经一个IT内部系统配一套帐号体系和授权   线上生产环境里 ...

  3. #研发解决方案介绍#基于StatsD+Graphite的智能监控解决方案

    郑昀 基于李丹和刘奎的文档 创建于2014/12/5 关键词:监控.dashboard.PHP.graphite.statsd.whisper.carbon.grafana.influxdb.Pyth ...

  4. #研发解决方案介绍#基于ES的搜索+筛选+排序解决方案

    郑昀 基于胡耀华和王超的设计文档 最后更新于2014/12/3 关键词:ElasticSearch.Lucene.solr.搜索.facet.高可用.可伸缩.mongodb.SearchHub.商品中 ...

  5. #研发中间件介绍#定时任务调度与管理JobCenter

    郑昀 最后更新于2014/11/11 关键词:定时任务.调度.监控报警.Job.crontab.Java 本文档适用人员:研发员工   没有JobCenter时我们要面对的:   电商业务链条很长,业 ...

  6. #研发中间件介绍#异步消息可靠推送Notify

    郑昀 基于朱传志的设计文档 最后更新于2014/11/11 关键词:异步消息.订阅者集群.可伸缩.Push模式.Pull模式 本文档适用人员:研发   电商系统为什么需要 NotifyServer? ...

  7. 著名ERP厂商的SSO单点登录解决方案介绍一

          SSO英文全称Single Sign On,单点登录.SSO是在多个应用系统中,用户只需要登录一次就可以访问所有相互信任的应用系统.它包括可以将这次主要的登录映射到其他应用中用于同一个用户 ...

  8. #研发解决方案#分布式并行计算调度和管理系统Summoner

    郑昀 创建于2015/11/10 最后更新于2015/11/12 关键词:佣金计算.定时任务.数据抽取.数据清洗.数据计算.Java.Redis.MySQL.Zookeeper.azkaban2.oo ...

  9. IT运维监控解决方案介绍

    现状 •小公司/ 创业团队< 500台服务器规模 开源方案:Zabbix.Nagios.Cacti- 云服务提供商:监控宝.oneAlert等 •BAT级别> 10万台服务器 投 ...

随机推荐

  1. 【C#】带等待窗体的BackgroundWorker

    ---------------201504170911更新--------------- 更新内容:删除bgwUI新增的Start方法,改为通过new修饰符+可选参数的方式同时覆盖基类(Backgro ...

  2. 【C#】分享一个可灵活设置边框的Panel

    ---------------------------更新:2014-05-19--------------------------- 优化了一下逻辑,就是既然可以通过设置BorderSide=Non ...

  3. hibernate----1-N--jointable(人与地址)

    package com.ij34.dao; import java.util.HashMap; import java.util.HashSet; import java.util.Set; impo ...

  4. 优化JavaScripe 提升首页加载速度的几种方案解析

    优化目的: 1. 减少load量. 2. 优化js,加快页面加载速度. 网站中最影响网站打开速度的是什么?我会告诉是网站中的javascript,简称JS.模板中引用的JS文件越多,打开速度越慢,细读 ...

  5. C#异步下载文件--基于http请求

    1.废话不多说,直接上代码: using System; using System.IO; using System.Net; namespace AsyncProgram { class Progr ...

  6. C#的库存管理之旅的别样意义

    我不知道大家对C#的一些基础知识掌握得怎么样了? 但无论怎么样,都应该静心下来去慢慢品味我的总结以及“库存管理”项目需用到的一些知识和技巧.你将会得到你料想不到的收获哦. 知识梳理: 数据类型:boo ...

  7. Linux下Oracle重启问题

    一.切换成oracle用户 $ su - oracle 注意:不要写成“su oracle ”不然是没办法使用下面的命令的. 如下所示:将会报:command not found的错误 二.使用命令 ...

  8. 【javascript激增的思考03】MVVM与Knockout

    前言 今天搞的有点快,因为上午简单研究了下MVC,发现MVC不太适合前端开发,然后之前看几位前端前辈都推荐前端使用MVVM,但是我对其还不甚了解,所以我觉得下午还是应该先看看他是神马先,后面再决定要不 ...

  9. MongoDB,客户端工具备份数据库

    本篇介绍下如何利用客户端工具来进行远程服务器的数据备份到本地. 以客户端工具MongoVUE为例来进行讲解: 1.首先要连接本地服务器以及远程服务器数据库 2.在本地服务器(127.0.0.1)中,右 ...

  10. sharepoint2013的最少下载策略概述(MDS)

    该策略是 SharePoint 2013 中的一种新功能,通过在用户导航到新页面时仅发送差异内容来减少页面加载时间. 最少下载策略 (MDS) 是 SharePoint 2013 中的一种新技术,可减 ...