閱讀350 返回首頁    go 阿裏雲 go 技術社區[雲棲]


長周期指標的計算優化方案

1 背景

在電子商務公司(如淘寶),對用戶的數據分析的角度和思路可謂是應有盡有、層出不窮。所以在電商數據倉庫和商業分析場景裏,經常需要計算最近N天訪客數、最近N天的購買用戶數、老客數等等類似的指標。這些指標有一個共同點:都需要根據用戶在電商平台上(或網上店鋪)一段時間積累的數據進行計算(這裏討論的前提是數據都存儲在MaxCompute上)。
一般情況下,這些指標的計算方式就是從日誌明細表中計算就行了,如下代碼計算商品的最近30天訪客數:

select   item_id         --商品id    
     ,count(distinct visitor_id) as ipv_uv_1d_001   
from     用戶訪問商品日誌明細表   
where    ds <= ${bdp.system.bizdate}   
and ds >=to_char(dateadd(to_date(${bdp.system.bizdate},'yyyymmdd'),-29,'dd'),'yyyymmdd')     
 group by item_id

  但是當每天的日誌量很大時,上麵代碼存在一個嚴重的問題,需要的**Map Instance**個數太多,甚至會超過**99999**個Instance個數的限製,Map Task就沒有辦法順利執行,更別說後續的操作了。為什麼Instance個數需要那麼多呢?原因:每天的日誌數據很大,30天的數據量更是驚人。這時候Select 操作需要大量的Map Instance,結果查過了Instance的上限,代碼無法運行

2 目的

  如何計算長周期的指標,又不影響性能?

  1. 多天匯總的問題根源是數據量的問題,如果把數據量給降低了,就可以解決這個問題了。

  2. 減少數據量最直接的辦法是把每天的數據量都給減少,因此需要構建臨時表,對1d的數據進行輕度匯總,這樣就能去掉很多重複數據,減少數據量。

3 方案

  1. 構建中間表,每天匯總一次,比如對於上麵的例子,構建一個item_id+visitor_id粒度的中間表

  2. 計算多天的數據,依賴中間表進行匯總

  例子如下:

   step1:構建item_id+visitior_id粒度的日匯總表,記作A

insert overwrite table mds_itm_vsr_xx(ds='${bizdate}')
select item_id,visitor_id,count(1) as pv
from
    (
     select   item_id,visitor_id
     from     用戶訪問商品日誌明細表    
     where    ds =${bdp.system.bizdate}  
     group by item_id,visitor_id
    )a

  **setp2:對A進行30天匯總**

   select   item_id
            ,count(distinct visitor_id) as uv
            ,sum(pv) as pv
     from      mds_itm_vsr_xx
     where    ds <= '{bizdate}'
     and      ds >= to_char(dateadd(to_date('${bizdate}','yyyymmdd'),-29,'dd'),'yyyymmdd')
     group by item_id

4 影響及思考

  上麵講述的方法,對每天的訪問日誌明細數據進行單天去重,從而減少了數據量,提高了性能。缺點是每次計算多天的數據的時候,都要N個分區的數據,那麼能不能有一種方式,不需要讀取N個分區的數據,而是把N個分區的數據壓縮合並成一個分區的數據,讓一個分區的數據包含曆史數據的信息。業務上是有類似場景的,有如下方式:

1. 增量累計方式計算長周期指標

  例子:求最近1天店鋪商品的老買家數,老買家數的算法定義為:過去一段時間有購買的買家(比如過去30天)。
一般情況下,老買家數計算方式:

select   item_id         --商品id    
       ,buyer_id as old_buyer_id
from     用戶購買商品明細表   
where    ds < ${bdp.system.bizdate}   
and ds >=to_char(dateadd(to_date(${bdp.system.bizdate},'yyyymmdd'),-29,'dd'),'yyyymmdd')     
 group by item_id
        ,buyer_id

  改進思路:
   1. 維護一張店鋪商品和買家購買關係的維表記作表A,記錄買家和店鋪的購買關係,以及第一次購買時間,最近一次購買時間,累計購買件數,累計購買金額等等信息
   2. 每天使用最近1天的支付明細日誌更新表A的相關數據
   3. 計算老買家時,最需要判斷最近一次購買時間是否是30天之內就行了,從而做到最大程度上的數據關係對去重,減少了計算輸入數據量

最後更新:2017-07-18 07:33:01

  上一篇:go  pidstat 工具介紹
  下一篇:go  5個步驟 & 7個提示 | 一份開啟Kaggle競賽征途的初學者指南