一、背景
漏斗分析是常見數(shù)據(jù)分析的一種,通過分析用戶在網(wǎng)站的行為,幫助運營人員分析一個多步驟過程中每一步的轉(zhuǎn)化與流失情況矮湘。比如定義一次電商活動(指定時間范圍比如最長30天)中用戶行為:訪問網(wǎng)站 -> 到達商品推薦頁 → 查看商品 → 生成訂單,統(tǒng)計用戶從訪問網(wǎng)站到下訂單完成轉(zhuǎn)化的數(shù)據(jù)就自然地形成了一個漏斗口糕。
通過上述描述得出幾個關(guān)鍵詞:
- 用戶行為有序分析
- 有轉(zhuǎn)化時間范圍(30天)
- 用戶訪問數(shù)(會話數(shù))和用戶數(shù)(去重后的用戶基數(shù))
同時作為分析產(chǎn)品的話缅阳,挑戰(zhàn)點就是如何能夠基于用戶自定義先后訪問順序的情況下秒級分析出各層漏斗的情況。
本文提出一種基于Druid來實現(xiàn)的方案景描,該方案具有滿足需求的前提下實現(xiàn)成本小的優(yōu)點十办。
二、技術(shù)方案
有序漏斗分析問題超棺,本質(zhì)上為了解決在海量數(shù)據(jù)上根據(jù)自定義條件做搜索匹配的問題向族,那么思路的方向如何設(shè)計合理的數(shù)據(jù)存儲結(jié)構(gòu)和更有的匹配查詢方式。
做OLAP數(shù)據(jù)分析思路有兩類
- 基于明細統(tǒng)計查詢的方案:滿足查詢靈活性棠绘,但是大數(shù)據(jù)量下聚合統(tǒng)計分析類查詢性能不佳件相。
- 預(yù)聚合方案:滿足查詢性能要求,但是查詢不靈活氧苍、業(yè)務(wù)需要開發(fā)聚合數(shù)據(jù)邏輯夜矗,方案復(fù)雜(ETL層較重)。
基于Druid的方案:
- 兼顧查詢靈活性與性能让虐、較少的開發(fā)成本紊撕,維度(查詢時組合) + 聚合指標(提前指定)。
- 分布式架構(gòu)(高可用赡突、伸縮性)逛揩,自動rollup預(yù)聚合(業(yè)務(wù)開發(fā)簡單、只需導(dǎo)入原始記錄)+ 高壓縮比 + bitmap倒排索引麸俘。
分析用戶的行為,首先是需要把同一個用戶(user_id)的所有行為整理在一起惧笛,并且考慮到有訪問量的指標从媚,那么還需要基于網(wǎng)頁session會話(session_id)做數(shù)據(jù)聚合。
第一步:數(shù)據(jù)清洗(ETL)
根據(jù)會話ID按訪問時間把所有網(wǎng)頁數(shù)據(jù)聚合在一起患整,數(shù)據(jù)表如下:
host | path_list | session_time | session_id | user_id |
---|---|---|---|---|
www.123.com | /1 /2 /3 | 1525243296 | session_id_xxx1 | user_id_xx1 |
www.abc.com | /a /b /c /d | 1525244296 | session_id_xxx2 | user_id_xx2 |
其中的關(guān)鍵是把所有頁面的path拼接在一起用空格分割拜效,目的是為了做漏斗匹配。這里可能大家會有疑問假如量很大怎么辦各谚?這里有兩個處理:1. 相鄰的兩個路徑若是相同則合并比如用戶同一個頁面刷新上報了兩次/1 /1那么在ETL的時候這里合并為一個/1紧憾;2. 一個session的時長是30分鐘,若是極端情況下一個用戶每秒都是訪問合1800秒昌渤,按平均一個路徑100byte來算也才180kb左右的大小赴穗。
第二步:清洗后的數(shù)據(jù)入Druid供查詢
原始入druid的數(shù)據(jù)就是上述一行session數(shù)據(jù),其中session_time作為時間維度供篩選,host般眉、path_list作為普通維度供查詢過濾了赵,session_id和user_id當做metrc算統(tǒng)計值,session_id因為在ETL的時候已經(jīng)去重了甸赃,所以用longSum統(tǒng)計指標即可柿汛,而user_id則考慮用hyperUnique(Hyperloglog算法)求基數(shù)。
數(shù)據(jù)schema設(shè)計
{
"type" : "index_hadoop",
"spec" : {
"ioConfig" : {
"type" : "hadoop",
"inputSpec" : {
"type" : "static",
"paths" : ""
}
},
"dataSchema" : {
"dataSource" : "",
"granularitySpec" : {
"type" : "uniform",
"segmentGranularity" : {"type":"period","period":"P1D","timeZone":"Asia/Shanghai"},
"queryGranularity" : {"type":"period","period":"P1D","timeZone":"Asia/Shanghai"},
"intervals" : []
},
"parser" : {
"type" : "string",
"parseSpec" : {
"format" : "json",
"dimensionsSpec" : {
"dimensions": [
"host",
"path"
]
},
"timestampSpec" : {
"format" : "auto",
"column" : "time"
}
}
},
"metricsSpec": [
{
"name": "count",
"type": "count"
},
{
"type" : "hyperUnique",
"name" : "qidianid",
"fieldName" : "qidianid",
"round" : true
}
]
},
"tuningConfig" : {
"type" : "hadoop",
"partitionsSpec" : {
"type" : "hashed",
"targetPartitionSize" : 5000000
},
"indexSpec" : {
"bitmap" : { "type" : "roaring"},
"dimensionCompression":"LZ4",
"metricCompression" : "LZ4",
"longEncoding" : "auto"
}
}
}
}
三埠对、具體實踐
查詢語句示例
{
"queryType": "timeseries",
"dataSource": {
"type": "table",
"name": "web_funnel"
},
"intervals": {
"type": "intervals",
"intervals": ["2018-03-19T00:00:00+08:00/2018-04-19T00:00:00+08:00"]
},
"filter": {
"type": "selector",
"dimension": "host",
"value": "qidian.qq.com"
},
"granularity": {"type": "all"},
"aggregations": [
{
"type" : "filtered",
"filter" : {
"type" : "like",
"dimension" : "path",
"pattern": "/%",
"escape": null,
"extractionFn": null
},
"aggregator" : {"type": "longSum", "name": "1", "fieldName": "count"}
},
{
"type" : "filtered",
"filter" : {
"type" : "like",
"dimension" : "path",
"pattern": "/ %/index.html%",
"escape": null,
"extractionFn": null
},
"aggregator" : {"type": "longSum", "name": "2", "fieldName": "count"}
},
{
"type" : "filtered",
"filter" : {
"type" : "like",
"dimension" : "path",
"pattern": "/ %/index.html %/download.html%",
"escape": null,
"extractionFn": null
},
"aggregator" : {"type": "longSum", "name": "3", "fieldName": "count"}
}
],
"context": {"skipEmptyBuckets": true}
}
返回結(jié)果
[{
"timestamp" : "2018-03-18T16:00:00.000Z",
"result" : {
"1" : 434483,
"2" : 21084,
"3" : 1479
}
}]
四络断、實踐效果
測試環(huán)境:
單機:cpu 24 core + 內(nèi)存64gb
查詢延遲:0.5s ~ 2.1s
30天總量(查詢的最長時間范圍,其實時間范圍任選)
原始數(shù)據(jù)量:10,960,000 (千萬級別)
Druid中rollup后數(shù)據(jù)量:1,560,000 (百萬級別)
path基數(shù):1,059,460 (百萬級別)
1天總量(一個segment项玛,查詢的最小粒度)
原始數(shù)據(jù)量:324,850 (十萬級別)
Druid中rollup后數(shù)據(jù)量:56,760 (萬級別)
path基數(shù):55,064 (萬級別)
五貌笨、總結(jié)分析
利用druid做有序漏斗的思路為什么是可行的?為什么其他的存儲引擎不行呢稍计,比如ES躁绸?
熟悉了整套方案后,大家可能會有這方面的疑問臣嚣,那么這里從數(shù)據(jù)分布上來回答這個問題净刮。通常,做搜索匹配可能很容易想到像用ES這樣的搜索架構(gòu)來解決問題硅则,但是這里有幾個特殊點ES不適合
- 同一個session下的path做了合并淹父,而ES快是快在分詞后建立對應(yīng)的索引,而該方案是需要把path拼接在一起做全匹配怎虫,這里沒有用的ES的優(yōu)勢而且ES一個string字段最長大小限制是32kb暑认。
- 在若是用ES來匹配的話,是需要基于全量數(shù)據(jù)做掃描的大审,所以這里性能不行蘸际。而Druid因為會將原始數(shù)據(jù)相同的維度的行做roll up合并,那么實際在druid中存儲的是聚合合并后的數(shù)據(jù)徒扶。通過觀察數(shù)據(jù)分布粮彤,很多用戶其實只訪問了官網(wǎng)首頁后就離開了,相比其他路徑會有數(shù)據(jù)級的差距姜骡,這里也是發(fā)揮Druid數(shù)據(jù)壓縮的優(yōu)勢导坟。同時,Druid只需要在字典里面查詢出滿足條件的bitmap索引后圈澈,即可快速掃描統(tǒng)計出滿足條件的指標數(shù)惫周。
幾點總結(jié):
- 技術(shù)方案無絕對,適合即可康栈。
- 關(guān)注數(shù)據(jù)分布递递。
- 把控方案成本喷橙。