Kylin 精確去重在用戶行爲分析中的妙用

做者:史少鋒,Apache Kylin committer & PMC,2019/10/11html

 

在上次文章《如何在 1 秒內作到大數據精準去重》中,咱們介紹了 Apache Kylin 爲何要支持大數據集上的精確去重,以及基於 Bitmap 的精確去重原理等。看到今天的文章標題,你確定要問,精確去重跟用戶行爲分析又能有什麼關係呢?原來啊,Kylin 採用 Bitmap 完整記錄了每一個維度組合下的用戶集合,利用 Bitmap 提供的或(or)運算方法來高效精準地回答了各類條件下的去重用戶數。其實 Bitmap 除了支持或(or)運算外,還支持與(and)運算。所以,稍加擴展,Kylin 就能夠基於 Bitmap 的中間結果,輕鬆實現諸如留存、漏斗等大量使用交集運算的分析,從而很是方便地運用在用戶行爲、用戶畫像等領域中。能夠說精確去重功能有着一石兩鳥的價值,本文將爲您介紹如何使用 Kylin 來實現精準的用戶行爲分析。前端

 

示例

先從一個簡單的例子提及吧。如今有一個 app 的用戶訪問記錄表 access_log,它包含三個字段:DT (訪問日期),User ID(用戶標示)和 Page(訪問頁):apache

DT User ID Page
20190101 100 index.html
20190101 101 search.html
20190101 102 detail.html
20190102 100 index.html
20190102 102 detail.html
20190102 103 index.html
20190103 101 index.html

△ 表 1:樣例數據原始表編程

在 Kylin 裏建立一個模型,選擇 DT 和 Page 作維度,User ID 作維度;數組

而後建立一個 Cube,使用 DT 和 page 作維度,定義 count (distinct user_id) 度量且使用 Bitmap 爲數據類型(關於 Kylin 的使用,參考 Apache Kylin 官網教程)。數據結構

這個 Cube 構建完成後,對於只包含 DT 維度的 Cuboid,它的數據結構以下:併發

DT User IDs (Bitmap)
20190101 [100,101,102]
20190102 [100,102,103]
20190103 [101,102,103,104]

△ 表 2:樣例 Cube 1app

注:上面的用戶集合「User IDs」用的是易於閱讀的數組格式,在實際存儲中使用 Bitmap(位圖)格式,也就是一組 0 或 1 的 bit 數組,如 [100,101,102] 就在第 100-102 位放 1,其它位放 0 表明。所以,Bitmap 不但很是省空間,並且很是適合計算機作交併集運算。函數

若是要計算某天或某幾天的 UV,SQL 以下:高併發

select dt, count(distinct user_id) from access_log where dt >= '20190101' and dt <= "20190103" group by dt

根據查詢 Bitmap 的 Cardinality(基數),獲取到 UV 值:

Date Count distinct User ID
20190101 3
20190102 3
20190103 4

△ 表 3:樣例查詢結果 1

 

留存分析

對於 App 的運營者來講,留存分析是一種常見的分析手段,經常使用於提高用戶留存率,它的主要目標是找到影響用戶留存的關鍵因素。由於獲取用戶是有必定成本的,若是新獲取的用戶大部分都留不住,那麼拉新的投入產出比就會很低。一般會分析日留存、周留存和月留存。

以日留存爲例,要計算第一天訪問的用戶中,有多少在次日、第三天繼續訪問了 app。若是使用 HiveQL或 Spark SQL 來計算第一天和次日的留存用戶數,寫法大體以下:

SELECT count(distinct first_day.USER_ID) FROM
  (select distinct USER_ID as USER_ID from access_log where DT = '20190101') as first_day 
    INNER JOIN
  (select distinct USER_ID as USER_ID from access_log where DT = '20190102') as second_day 
  ON first_day.USER_ID = second_day.USER_ID

能夠看出,使用 Hive/Spark 計算留存用戶,須要先寫多個子查詢,分別計算出各日的用戶集合,而後經過 inner join 的方式實現交集計算,最後在外層再作 count(distinct)運算。在數據量很大的時候,這樣的多個子查詢的join會很是慢且容易內存溢出。

 

使用 Kylin 計算日/周/月留存

你們能夠看到,其實拿這幾日訪問用戶的 bitmap,相互作與(and)操做,就能夠高效地獲得留存數字,如「第一天」and「次日」訪問的用戶;這樣跟第一天的訪問用戶數作個比較,就能夠計算出次日留存率等。

爲了便於在 SQL 中作「與」操做,Kylin 提供了一個自定義函數:「intersect_count」(詳見文末「參考」文章【2】)。顧名思義,就是作交集之後的結果數。該函數用法以下:

intersect_count(columnToCount, columnToFilter, filterValueList)
其中:
`columnToCount` 要作計數的列,也就是bitmap存儲的列,這裏就是「user_id「
`columnToFilter` 作交集計算的列,若是是把多個不一樣日期的bitmap來作交集,那麼這列就是日期;
`filterValueList` 作交集計算的bitmap的key值,須要是一個數組。

例以下面的 SQL 查詢了’20190101′ 與 ‘20190102’這兩天的交集用戶數:

select intersect_count(user_id, dt, array['20190101', '20190102'])
from access_log
where dt in ('20190101', '20190102')

能夠看出,使用 Kylin,一個 intersect_count 函數就能夠完成多日用戶集合的交集計算。這裏where條件中也進行了日期的篩查,爲的是減小從底層存儲加載的數據。顯然,相比於Hive 和 Spark SQL,Kylin 的用法更加簡單明瞭,並且基於預計算的 Bitmap 作交集,比現場 join 效率高不少,能夠作到秒級響應。

經過 Kylin 還能夠很方便地在一條 SQL 中查詢多日的 UV 及留存,避免反覆查詢,如:

select city, version,
intersect_count(user_id, dt, array['20161014']) as first_day_uv,
intersect_count(user_id, dt, array['20161015']) as second_day_uv,
intersect_count(user_id, dt, array['20161016']) as third_day_uv,
intersect_count(user_id, dt, array['20161014', '20161015']) as retention_oneday,
intersect_count(user_id, dt, array['20161014', '20161016']) as retention_twoday
from access_log
where dt in ('2016104', '20161015', '20161016')
group by city, version
order by city, version

同理,若是 Cube 中有周、月作維度,那麼這裏把日期換成周、月就能夠很方便地計算周留存、月留存了。

 

使用 Kylin 進行漏斗分析

漏斗分析,又叫轉化漏斗,就是將一個特定過程的多個步驟間的轉化狀況,以漏斗的形式展現出來,經過圖形直觀地發現流失最嚴重的環節,從而有針對性地去進行優化。

△ 表1:漏斗分析

能夠看出,漏斗分析中也要用到交集運算,例如:有多少訪問了首頁的用戶,進入到了產品詳細頁?看了產品詳情頁的,有多少用戶將它加入到了購物車?產品運營人員很是關心這些指標,由於它表明了用戶在使用中每一步的轉化關係;若是某一個路徑上的轉化率較低,意味着潛在的問題和風險,須要及時介入。

之前面的示例數據爲例,若是咱們將 Page 做爲一個維度,User ID 作 count distinct 度量,構建成 Cube 後獲得這樣的用戶訪問統計(示例):

Page User IDs (Bitmap)
index.html [100,101,102,103,104]
search.html [100,102,103]
detail.html [101,103]

△ 表4:樣例 Cube 2

這樣經過切換 Page 的值來作交集,咱們就能夠很容易地計算出它們之間的漏斗轉化率,如:

select 
intersect_count(user_id, page, array['index.html']) as first_step_uv,
intersect_count(user_id, page, array['search.html']) as second_step_uv,
intersect_count(user_id, dt, array['detail.html']) as third_step_uv,
intersect_count(user_id, dt, array['index.html', 'search.html']) as retention_one_two,
intersect_count(user_id, dt, array['search.html','detail.html']) as retention_two_three
from access_log
where dt in ('2016104', '20161015', '20161016')

結果:

5, 3, 2, 3, 2

如此行爲漏斗的轉化率也就很容易獲得了:

Page 關聯用戶數(轉化率)
index.html 4(100%)
index.html  -> search.html 3 (3/4=75%)
search.html -> detail.html 2 (2/3=66%)

△ 表 5:樣例行爲漏斗結果

固然這是一個很簡單的例子,實際會複雜不少;這裏的 Page(頁面)能夠換成埋點值或其它維度,從而更加細緻地分析各類行爲之間的關聯關係。

 

多維度滑動的留存分析

前面的例子中都是單個維度值變化時,使用Kylin的交集函數進行留存和漏斗轉化的計算,是比較容易理解的。現實中有時候須要在多個維度上同時進行滑動分析,例如運營可能會問:第一天訪問「商品明細頁」的用戶,有多少在次日訪問了「付款頁」?那麼 Kylin 是否能夠作到呢?

答案是確定的,雖然 intersect_count 交集函數只接受一個維度值的變化,但咱們能夠巧妙利用 where 作其它維度的篩選,最後的結果交給 SQL 執行器來計算。如:

select 
intersect_count(user_id, dt, array[‘20190101’]),#第一天的UV
intersect_count(user_id, dt, array[‘20190101’, ‘20190102’])  #第一天和次日交集
from access_log
where (dt='20190101’ and page=‘detail.html’) #篩選第一天&訪問明細頁的用戶
  or 
(dt=‘20190102’ and page=‘payment.html’) #篩選次日&訪問付款頁的用戶

這樣的條件是隻須要把 page 和 dt 都作爲維度就能夠了,是否是很簡單?

 

先或再與操做

有時候業務人員在分析問題的時候,會動態調整分析的組合,把一些條件先進行或(or)操做,而後再跟其它條件作與(and)運算。例如,訪問了「搜索頁」和「詳情頁」中任何一個的用戶,有多少訪問了「付款頁」?前二者是一個或的關係,它們的結果須要跟第三個進行與操做。

爲了支持這種特殊的計算,咱們能夠擴展 intersect_count 函數,讓它能夠理解或運算符。下面是一個示例(這裏默認使用了「|」做爲或條件的分隔符,若是維度值中可能包含「|」,需經過配置修改爲其它符號):

select 
intersect_count(user_id, page, array['search.html|detail.html’, 'payment.html']) 
from access_log

在 app 埋點分析中,這也是一個常見的場景。app 開發者爲了往後分析的靈活性,會有意埋了不少不一樣的點:一樣的行爲在不一樣客戶端、版本中的埋點值可能不一樣(稱爲「物理埋點」);但業務人員在分析的時候,須要將這些物理埋點根據須要裝配成「邏輯埋點」。例如,「安卓端登陸」、「蘋果端登陸」和「網頁登陸」這三個埋點值都表明了「登陸」這個行爲,它們或的集合去跟「登陸失敗」作與操做,能夠算出 app 總體登陸失敗率。

過去爲了知足業務的這種靈活分析需求,開發者每每須要調整他們的ETL腳原本改變運算邏輯,週期長、效率低而且很容易出錯;使用 Kylin 後就沒有這些煩惱,用戶能夠靈活組裝查詢條件,剩下的事情交給 Kylin 就能夠了。

注:此功能目前還處於內部預覽階段,還未在社區版正式發佈。

 

用戶畫像分析

用戶畫像分析中須要經過標籤進行用戶的篩選;做爲存儲數字集合的最緊湊數據結構,Bitmap 經常被用在用戶畫像分析中。Kylin 引入 Bitmap 後,也能夠用在用戶畫像的分析。

使用 Kylin 作用戶篩查時,一般須要將標籤從列轉行,將「標籤類型」和「標籤值」做爲維度,將 User ID 做爲 Bitmap 度量進行構建,構建後的 Cube 以下:

標籤類型(tag_type) 標籤值(tag_value) User IDs (Bitmap)
性別 [100,101,102,103,104]
性別
年齡區間 90後 [100,102,103]
年齡區間
收入 10-20萬 [101,103,105,107]
收入 ..

△ 表 6:樣例用戶畫像 Cube

例如如今要分析,性別是男的、年齡是 90 後的、收入在 10-20 萬區間的人有多少;經過 Kylin 這樣查詢便可:

select 
intersect_count(user_id, tag_value, array['男', '90後', '10-20萬']) 
from user_profile
where (tag_type='性別' and tag_value='男') or (tag_type='年齡' and tag_value='90後') or (tag_type='收入' and tag_value='10-20萬')

結果:

2

若是當前標籤篩選後的結果集依然很大,用戶能夠繼續添加更多標籤,直到將用戶數控制到合適的範圍(例如打算定向發放一萬張優惠券)。

 

用戶明細分析

在用標籤篩查後業務人員可能問,可否導出知足這些標籤的用戶集合明細呢,這樣好對他們發券啊?Kylin 是否能在回答用戶數的同時,告訴咱們具體是哪些 User_ID 呢?

答案是確定的,由於 Bitmap 忠實地保存了每一個 User_ID 值(例如使用第 100 個 bit 位表明 ID 爲 100 的用戶是否出現),所以它能夠在須要的時候告訴咱們明細數據。

爲了支持此類查詢,咱們能夠參照 intersect_count 函數,開發另外一個能返回 Bitmap 明細的函數,這裏咱們暫且稱它爲 intersect_value 函數,用法跟 intersect_count 同樣,只是它的返回類型是一個整數數組:

select 
intersect_value(user_id, tag_value, array['男', '90後', '10-20萬']) 
from user_profile
where (tag_type='性別' and tag_value='男') or (tag_type='年齡' and tag_value='90後') or (tag_type='收入' and tag_value='10-20萬')

結果:

[101,103]

有了明細結果,下一步就能夠結合其它數據源如用戶明細表、CRM 系統等作進一步的分析了,這裏就不展開了。

注:此功能目前還處於內部預覽階段,還未在社區版正式發佈。

 

成功案例

Kylin 的精確去重功能和交集函數最初是由美團點評大數據團隊根據自身場景和需求開發並貢獻到開源社區的,並在美團內部獲得大量使用。如今,這些功能正在被愈來愈多的用戶所使用,有的基於 Kylin 再開發一些前端展示,就實現了能知足業務絕大部分需求的一站式用戶行爲分析平臺。

例如滿幫集團,它是原運滿滿和貨車幫合併後的集團,有 8 個手機 app,4 類埋點、上千個埋點值,收集了超過千億條的用戶行爲日誌。過去他們本身開發的分析平臺各方面都不能知足業務需求,束縛了業務的發展;後來滿幫集團遷移到了基於 Kylin 的分析平臺,藉助於 Kylin 的豐富功能,自研了名爲 APPDATA 的一站式分析平臺,極大地知足了業務對於數據分析的需求。

△ 圖2:滿幫 APPDATA 數據流程圖

這是他們基於 Kylin 的日/周/月留存分析報表,對於留存率異常狀況,會經過顏色高亮顯示:

      △ 圖 3:滿幫 APPDATA 日留存樣例

這是他們開發的、讓業務人員能夠自定義行爲的功能,業務人員能夠自由地組合各種埋點,將它們定義稱一個「行爲」(邏輯埋點):

      △ 表 4:滿幫 APPDATA 自定義用戶行爲

隨後,業務人員能夠將一些行爲串成一個行爲漏斗,而後查看漏斗轉化率,背後就是用的 Kylin 交集函數:

      △ 表5:滿幫 APPDATA 自定義行爲漏斗

在這張圖上,業務人員能夠很方便地查看每一步的留存/流失率,對於異常狀況,能夠進一步下鑽到明細作進一步的篩查。關於滿幫使用Kylin的更多信息,請參考文末的「參考」文章【3】。

 

總結

Kylin 爲實現秒級精確去重引入了 Bitmap 作爲用戶集合的存儲結構,經過擴展 SQL 聚合函數,Kylin 還支持對 Bitmap 的交集、先或再與以及查詢明細等操做,能夠很是巧妙地運用在用戶行爲和用戶畫像分析領域,相比於本身開發具備多種優點:

  • 圖形化建模操做,無需編程開發;
  • 存儲和計算基於 Hadoop,能支撐海量用戶數據的加工和存儲;
  • 易於使用,查詢所有使用 SQL;
  • 高性能高併發,大部分查詢在秒級完成;
  • 結果精確;
  • 穩定可靠,已在許多互聯網用戶如美團、滴滴、eBay 生產系統使用多年。

 

想體驗 Kylin 秒級精確去重?

Kylin 官網文檔中有操做指南哦:https://kylin.apache.org/docs/tutorial/create_cube.html

 

參考

【1】史少鋒《如何在 1 秒內作到大數據精準去重》 https://kyligence.io/zh/blog/apache-kylin-count-distinct/

【2】孫業銳 《Retention Or Conversion Rate Analyze in Apache Kylin》https://kylin.apache.org/blog/2016/11/28/intersect-count/

【3】陳雅婕《Kylin 在滿幫集團千億級用戶訪問行爲分析中的應用》https://kyligence.io/zh/resources/kylin_at_manbang_group/

 

瞭解更多大數據資訊,點擊進入Kyligence官網

相關文章
相關標籤/搜索