开发者社区> 问答> 正文
0
0
分享

MaxCompute最佳实践:长周期指标的计算优化方案



实验背景


电子商务公司(如淘宝)对用户数据分析的角度和思路可谓是应有尽有、层出不穷,所以在电商数据仓库和商业分析场景中,经常需要计算最近 N 天的访客数、购买用户数、老客数等类似的指标。
这些指标有一个共同点:都需要根据用户在电商平台上(或网上店铺)一段时间积累的数据进行计算(这里讨论的前提是数据都存储在 MaxCompute 上)。
一般情况下,这些指标的计算方式就是从日志明细表中计算就行了,如下代码计算商品最近 30 天的访客数:

  1. select   item_id         --商品id    
  2.      ,count(distinct visitor_id) as ipv_uv_1d_001  
  3. from     用户访问商品日志明细表  
  4. where    ds <= ${bdp.system.bizdate}  
  5. and ds >=to_char(dateadd(to_date(${bdp.system.bizdate},'yyyymmdd'),-29,'dd'),'yyyymmdd')    
  6. group by item_id;

当每天的日志量很大时,上面代码存在一个严重的问题,需要的 Map Instance 个数太多,甚至会超过 99999 个 Instance 个数的限制,Map Task 就没有办法顺利执行,更别说后续的操作了。
为什么 Instance 个数需要那么多呢?是因为每天的日志数据很大,30 天的数据量更是惊人。此时 Select 操作需要大量的 Map Instance,结果超过了 Instance 的上限,导致代码无法运行。

实验目的


如何计算长周期的指标,又不影响性能呢?通常有以下两种思路:

  • 多天汇总的问题根源是数据量的问题,如果把数据量给降低了,便可解决此问题。

  • 减少数据量最直接的办法是把每天的数据量都给减少,因此需要构建临时表,对 1d 的数据进行轻度汇总,这样便可去掉很多重复数据,减少数据量。


实验方案



操作步骤


  1. 构建中间表,每天汇总一次。
    比如对于上面的例子,可以构建一个 item_id+visitor_id 粒度的中间表。即构建item_id+visitior_id 粒度的日汇总表,记作 A。如下所示:insert overwrite table mds_itm_vsr_xx(ds='${bdp.system.bizdate} ')
  2. select item_id,visitor_id,count(1) as pv
  3. from
  4.   select   item_id,visitor_id
  5.   from     用户访问商品日志明细表    
  6.   where    ds =${bdp.system.bizdate}  
  7.   group by item_id,visitor_id
  8. )a;

计算多天的数据,依赖中间表进行汇总。
对 A 进行 30 天的汇总,如下所示:
  1. select   item_id
  2.          ,count(distinct visitor_id) as uv
  3.          ,sum(pv) as pv
  4.   from      mds_itm_vsr_xx
  5.   where    ds <= '${bdp.system.bizdate} '
  6.   and      ds >= to_char(dateadd(to_date('${bdp.system.bizdate} ','yyyymmdd'),-29,'dd'),'yyyymmdd')
  7.   group by item_id;


影响及思考


上面讲述的方法,对每天的访问日志明细数据进行单天去重,从而减少了数据量,提高了性能。缺点是每次计算多天的数据的时候,都需要读取 N 个分区的数据。
那么是否有一种方式,不需要读取 N 个分区的数据,而是把 N 个分区的数据压缩合并成一个分区的数据,让一个分区的数据包含历史数据的信息呢?
业务上是有类似场景的,可以通过 增量累计方式计算长周期指标

场景示例


求最近 1 天店铺商品的老买家数。老买家数的算法定义为:过去一段时间有购买的买家(比如过去 30 天)。
一般情况下,老买家数计算方式如下所示:
  1. select   item_id         --商品id    
  2.        ,buyer_id as old_buyer_id
  3. from     用户购买商品明细表  
  4. where    ds < ${bdp.system.bizdate}  
  5. and ds >=to_char(dateadd(to_date(${bdp.system.bizdate},'yyyymmdd'),-29,'dd'),'yyyymmdd')    
  6. group by item_id
  7.         ,buyer_id;

改进思路

  • 维护一张店铺商品和买家购买关系的维表记作表 A,记录买家和店铺的购买关系,以及第一次购买时间,最近一次购买时间,累计购买件数,累计购买金额等信息。

  • 每天使用最近 1 天的支付明细日志更新表 A 的相关数据。

  • 计算老买家时,最需要判断最近一次购买时间是否是 30天 之内就行了,从而做到最大程度上的数据关系对去重,减少了计算输入数据量。

展开
收起
行者武松 2017-10-24 14:41:03 2118 0
举报
飞天免费试用计划
领取免费云资源,开启云上实践第一步
云原生大数据计算服务MaxCompute
500CU*H 100GB 3个月
额度3个月内有效
日志服务 SLS
月写入数据量 50GB 1个月
额度1个月内有效
云原生大数据计算服务 MaxCompute
5000CU*H 100GB 3个月
额度3个月内有效
0 条回答
写回答
取消 提交回答
问答排行榜
最热
最新

相关电子书

更多
Data+AI时代大数据平台应该如何建设 立即下载
大数据AI一体化的解读 立即下载
极氪大数据 Serverless 应用实践 立即下载
AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等