大資料專案之電商數倉一(使用者行為採集)
一、資料倉庫概念
資料倉庫(Data Warehouse)
是為企業所有決策制定過程,提供所有系統資料支援的戰略集合。
二、專案需求及架構設計
2.1 專案需求分析
1、專案需求
1)使用者行為資料採集平臺搭建
2)業務資料採集平臺搭建
3)資料倉庫維度建模
4)分析:使用者、流量、會員、商品、銷售、地區、活動等電商核心主題,統計的報表指標近100。
5)採用即席查詢工具,隨時進行指標分析
6)對叢集效能進行監控,發生異常需要報警
7)元資料管理
8)質量監控
2.2 專案框架
2.2.1 技術選型
技術選型主要需要考慮的因素:資料量大小、業務需求、行業內經驗、技術成熟度、開發維護成本、總成本預算
資料採集傳輸:Flume、Kafka、Sqoop、Logstash、DataX、
資料儲存:Mysql、HDFS、HBase、Redis、MongoDB
資料計算:Hive、Tez、Spark、Flink、Storm
資料查詢:Presto、Druid、Impala、Kylin
資料視覺化:Echarts、Superset、QuickBI、DataV
任務排程:Azkaban、Oozie
叢集監控:Zabbix
元資料管理:Atlas
資料質量監控:Griffin
2.2.2 系統資料流程設計
2.2.3 框架版本選型
2.2.4 伺服器選型
伺服器是選擇物理機還是雲主機?
1)物理機:
128G記憶體,20核物理CPU,40執行緒,8THDD和2TSSD硬碟,戴爾品牌單臺報價4萬出頭。一般物理機壽命5年左右。
2)雲主機:
以阿里云為例,和上面大致相同配置,每年5萬。
2.2.5 叢集資源規劃設計
1、叢集規模
1)如何確認叢集規模?(按每臺伺服器8T磁碟,128G記憶體)
(1)按每天日活躍使用者100萬,每人一天平均100條:100萬*100條 = 1億條
(2)每條日誌1K左右,每天1億條:100000000 / 1024 /1024 = 約100G
(3)半年內不擴容伺服器來算:100G * 180 天 = 約18T
(4)儲存3個副本:18T * 3 = 54T
(5)預留20%~30%Buffer=54T/0.7=77T
(6)需要約8T*10臺伺服器
2)如果要考慮數倉分層?資料採用壓縮?需要重新計算
2、叢集伺服器規劃
服務名稱 |
子服務 |
伺服器 hadoop102 |
伺服器 hadoop103 |
伺服器 hadoop104 |
HDFS |
NameNode |
√ |
|
|
DataNode |
√ |
√ |
√ |
|
SecondaryNameNode |
|
|
√ |
|
Yarn |
NodeManager |
√ |
√ |
√ |
Resourcemanager |
|
√ |
|
|
Zookeeper |
Zookeeper Server |
√ |
√ |
√ |
Flume(採集日誌) |
Flume |
√ |
√ |
|
Kafka |
Kafka |
√ |
√ |
√ |
Flume(消費Kafka) |
Flume |
|
|
√ |
Hive |
Hive |
√ |
|
|
MySQL |
MySQL |
√ |
|
|
Sqoop |
Sqoop |
√ |
|
|
Presto |
Coordinator |
√ |
|
|
Worker |
|
√ |
√ |
|
Azkaban |
AzkabanWebServer |
√ |
|
|
AzkabanExecutorServer |
√ |
|
|
|
Druid |
Druid |
√ |
√ |
√ |
Kylin |
|
√ |
|
|
Hbase |
HMaster |
√ |
|
|
HRegionServer |
√ |
√ |
√ |
|
Superset |
|
√ |
|
|
Atlas |
|
√ |
|
|
Solr |
Jar |
√ |
|
|
Griffin |
|
√ |
|
|
服務數總計 |
|
19 |
9 |
9 |
三、資料生成模組
3.1 埋點資料基本格式
公共欄位:基本所有安卓手機都包含的欄位
業務欄位:埋點上報的欄位,有具體的業務型別
下面就是一個示例,表示業務欄位的上傳。
{
"ap":"xxxxx",//專案資料來源 app pc
"cm": { //公共欄位
"mid": "", // (String) 裝置唯一標識
"uid": "", // (String) 使用者標識
"vc": "1", // (String) versionCode,程式版本號
"vn": "1.0", // (String) versionName,程式版本名
"l": "zh", // (String) language系統語言
"sr": "", // (String) 渠道號,應用從哪個渠道來的。
"os": "7.1.1", // (String) Android系統版本
"ar": "CN", // (String) area區域
"md": "BBB100-1", // (String) model手機型號
"ba": "blackberry", // (String) brand手機品牌
"sv": "V2.2.1", // (String) sdkVersion
"g": "", // (String) gmail
"hw": "1620x1080", // (String) heightXwidth,螢幕寬高
"t": "1506047606608", // (String) 客戶端日誌產生時的時間
"nw": "WIFI", // (String) 網路模式
"ln": 0, // (double) lng經度
"la": 0 // (double) lat 緯度
},
"et": [ //事件
{
"ett": "1506047605364", //客戶端事件產生時間
"en": "display", //事件名稱
"kv": { //事件結果,以key-value形式自行定義
"goodsid": "236",
"action": "1",
"extend1": "1",
"place": "2",
"category": "75"
}
}
]
}
示例日誌(伺服器時間戳 | 日誌):
1540934156385|{
"ap": "gmall",
"cm": {
"uid": "1234",
"vc": "2",
"vn": "1.0",
"la": "EN",
"sr": "",
"os": "7.1.1",
"ar": "CN",
"md": "BBB100-1",
"ba": "blackberry",
"sv": "V2.2.1",
"g": "[email protected]",
"hw": "1620x1080",
"t": "1506047606608",
"nw": "WIFI",
"ln": 0
},
"et": [
{
"ett": "1506047605364", //客戶端事件產生時間
"en": "display", //事件名稱
"kv": { //事件結果,以key-value形式自行定義
"goodsid": "236",
"action": "1",
"extend1": "1",
"place": "2",
"category": "75"
}
},{
"ett": "1552352626835",
"en": "active_background",
"kv": {
"active_source": "1"
}
}
]
}
}
下面是各個埋點日誌格式。其中商品點選屬於資訊流的範疇
3.2 事件日誌數
3.2.1 商品列表頁(loading)
事件名稱:loading
標籤 |
含義 |
action |
動作:開始載入=1,載入成功=2,載入失敗=3 |
loading_time |
載入時長:計算下拉開始到介面返回資料的時間,(開始載入報0,載入成功或載入失敗才上報時間) |
loading_way |
載入型別:1-讀取快取,2-從介面拉新資料 |
extend1 |
擴充套件欄位 Extend1 |
extend2 |
擴充套件欄位 Extend2 |
type |
載入型別:自動載入=1,使用者下拽載入=2,底部載入=3(底部條觸發點選底部提示條/點選返回頂部載入) |
type1 |
載入失敗碼:把載入失敗狀態碼報回來(報空為載入成功,沒有失敗) |
3.2.2 商品點選(display)
事件標籤:display
標籤 |
含義 |
|
action |
動作:曝光商品=1,點選商品=2, |
|
goodsid |
商品ID(服務端下發的ID) |
|
place |
順序(第幾條商品,第一條為0,第二條為1,如此類推) |
|
extend1 |
曝光型別:1 - 首次曝光 2-重複曝光 |
|
category |
分類ID(服務端定義的分類ID) |
|
3.2.3 商品詳情頁(newsdetail)
事件標籤:newsdetail
標籤 |
含義 |
|
entry |
頁面入口來源:應用首頁=1、push=2、詳情頁相關推薦=3 |
|
action |
動作:開始載入=1,載入成功=2(pv),載入失敗=3, 退出頁面=4 |
|
goodsid |
商品ID(服務端下發的ID) |
|
show_style |
商品樣式:0、無圖、1、一張大圖、2、兩張圖、3、三張小圖、4、一張小圖、5、一張大圖兩張小圖 |
|
news_staytime |
頁面停留時長:從商品開始載入時開始計算,到使用者關閉頁面所用的時間。若中途用跳轉到其它頁面了,則暫停計時,待回到詳情頁時恢復計時。或中途劃出的時間超過10分鐘,則本次計時作廢,不上報本次資料。如未載入成功退出,則報空。 |
|
loading_time |
載入時長:計算頁面開始載入到介面返回資料的時間 (開始載入報0,載入成功或載入失敗才上報時間) |
|
type1 |
載入失敗碼:把載入失敗狀態碼報回來(報空為載入成功,沒有失敗) |
|
category |
分類ID(服務端定義的分類ID) |
|
3.2.4 廣告(ad)
事件名稱:ad
標籤 |
含義 |
entry |
入口:商品列表頁=1 應用首頁=2 商品詳情頁=3 |
action |
動作: 廣告展示=1 廣告點選=2 |
contentType |
Type: 1 商品 2 營銷活動 |
displayMills |
展示時長 毫秒數 |
itemId |
商品id |
activityId |
營銷活動id |
3.2.5 訊息通知(notification)
事件標籤:notification
標籤 |
含義 |
action |
動作:通知產生=1,通知彈出=2,通知點選=3,常駐通知展示(不重複上報,一天之內只報一次)=4 |
type |
通知id:預警通知=1,天氣預報(早=2,晚=3),常駐=4 |
ap_time |
客戶端彈出時間 |
content |
備用欄位 |
3.2.6 使用者後臺活躍(active_background)
事件標籤: active_background
標籤 |
含義 |
active_source |
1=upgrade,2=download(下載),3=plugin_upgrade |
3.2.7 評論(comment)
描述:評論表
序號 |
欄位名稱 |
欄位描述 |
欄位型別 |
長度 |
允許空 |
預設值 |
1 |
comment_id |
評論表 |
int |
10,0 |
|
|
2 |
userid |
使用者id |
int |
10,0 |
√ |
0 |
3 |
p_comment_id |
父級評論id(為0則是一級評論,不為0則是回覆) |
int |
10,0 |
√ |
|
4 |
content |
評論內容 |
string |
1000 |
√ |
|
5 |
addtime |
建立時間 |
string |
|
√ |
|
6 |
other_id |
評論的相關id |
int |
10,0 |
√ |
|
7 |
praise_count |
點贊數量 |
int |
10,0 |
√ |
0 |
8 |
reply_count |
回覆數量 |
int |
10,0 |
√ |
0 |
3.2.8 收藏(favorites)
描述:收藏
序號 |
欄位名稱 |
欄位描述 |
欄位型別 |
長度 |
允許空 |
預設值 |
1 |
id |
主鍵 |
int |
10,0 |
|
|
2 |
course_id |
商品id |
int |
10,0 |
√ |
0 |
3 |
userid |
使用者ID |
int |
10,0 |
√ |
0 |
4 |
add_time |
建立時間 |
string |
|
√ |
|
3.2.9 點贊(praise)
描述:所有的點贊表
序號 |
欄位名稱 |
欄位描述 |
欄位型別 |
長度 |
允許空 |
預設值 |
1 |
id |
主鍵id |
int |
10,0 |
|
|
2 |
userid |
使用者id |
int |
10,0 |
√ |
|
3 |
target_id |
點讚的物件id |
int |
10,0 |
√ |
|
4 |
type |
點贊型別 1問答點贊 2問答評論點贊 3 文章點贊數4 評論點贊 |
int |
10,0 |
√ |
|
5 |
add_time |
新增時間 |
string |
|
√ |
|
3.2.10 錯誤日誌
errorBrief |
錯誤摘要 |
errorDetail |
錯誤詳情 |
3.3 啟動日誌資料
事件標籤: start
標籤 |
含義 |
entry |
入口: push=1,widget=2,icon=3,notification=4, lockscreen_widget =5 |
open_ad_type |
開屏廣告型別: 開屏原生廣告=1, 開屏插屏廣告=2 |
action |
狀態:成功=1 失敗=2 |
loading_time |
載入時長:計算下拉開始到介面返回資料的時間,(開始載入報0,載入成功或載入失敗才上報時間) |
detail |
失敗碼(沒有則上報空) |
extend1 |
失敗的message(沒有則上報空) |
en |
日誌型別start |
{
"action":"1",
"ar":"MX",
"ba":"HTC",
"detail":"",
"en":"start",
"entry":"2",
"extend1":"",
"g":"[email protected]",
"hw":"640*960",
"l":"en",
"la":"20.4",
"ln":"-99.3",
"loading_time":"2",
"md":"HTC-2",
"mid":"995",
"nw":"4G",
"open_ad_type":"2",
"os":"8.1.2",
"sr":"B",
"sv":"V2.0.6",
"t":"1561472502444",
"uid":"995",
"vc":"10",
"vn":"1.3.4"
}
3.4 資料生成指令碼
3.1.1 建立Mavne工程
1)建立 log-collector
GroupId : com.test
Project name : log-collector
2)建立一個包名:com.test.appclient
3)在com.test.appclient包下建立一個類,AppMain。
4)在pom.xml檔案中新增如下內容
<!--版本號統一--> <properties> <slf4j.version>1.7.20</slf4j.version> <logback.version>1.0.7</logback.version> </properties> <dependencies> <!--阿里巴巴開源json解析框架--> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.51</version> </dependency> <!--日誌生成框架--> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-core</artifactId> <version>${logback.version}</version> </dependency> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> <version>${logback.version}</version> </dependency> </dependencies> <!--編譯打包外掛--> <build> <plugins> <plugin> <artifactId>maven-compiler-plugin</artifactId> <version>2.3.2</version> <configuration> <source>1.8</source> <target>1.8</target> </configuration> </plugin> <plugin> <artifactId>maven-assembly-plugin </artifactId> <configuration> <descriptorRefs> <descriptorRef>jar-with-dependencies</descriptorRef> </descriptorRefs> <archive> <manifest> <mainClass>com.test.appclient.AppMain</mainClass> </manifest> </archive> </configuration> <executions> <execution> <id>make-assembly</id> <phase>package</phase> <goals> <goal>single</goal> </goals> </execution> </executions> </plugin> </plugins> </build>
注意:com.test.appclient.AppMain要和自己建的全類名一致。
3.1.2 公共欄位Bean
1)建立包名:com.test.bean
2)在com.test.bean包下依次建立如下bean物件
package com.test.bean; /** * 公共日誌 */ public class AppBase{ private String mid; // (String) 裝置唯一標識 private String uid; // (String) 使用者uid private String vc; // (String) versionCode,程式版本號 private String vn; // (String) versionName,程式版本名 private String l; // (String) 系統語言 private String sr; // (String) 渠道號,應用從哪個渠道來的。 private String os; // (String) Android系統版本 private String ar; // (String) 區域 private String md; // (String) 手機型號 private String ba; // (String) 手機品牌 private String sv; // (String) sdkVersion private String g; // (String) gmail private String hw; // (String) heightXwidth,螢幕寬高 private String t; // (String) 客戶端日誌產生時的時間 private String nw; // (String) 網路模式 private String ln; // (double) lng經度 private String la; // (double) lat 緯度 public String getMid() { return mid; } public void setMid(String mid) { this.mid = mid; } public String getUid() { return uid; } public void setUid(String uid) { this.uid = uid; } public String getVc() { return vc; } public void setVc(String vc) { this.vc = vc; } public String getVn() { return vn; } public void setVn(String vn) { this.vn = vn; } public String getL() { return l; } public void setL(String l) { this.l = l; } public String getSr() { return sr; } public void setSr(String sr) { this.sr = sr; } public String getOs() { return os; } public void setOs(String os) { this.os = os; } public String getAr() { return ar; } public void setAr(String ar) { this.ar = ar; } public String getMd() { return md; } public void setMd(String md) { this.md = md; } public String getBa() { return ba; } public void setBa(String ba) { this.ba = ba; } public String getSv() { return sv; } public void setSv(String sv) { this.sv = sv; } public String getG() { return g; } public void setG(String g) { this.g = g; } public String getHw() { return hw; } public void setHw(String hw) { this.hw = hw; } public String getT() { return t; } public void setT(String t) { this.t = t; } public String getNw() { return nw; } public void setNw(String nw) { this.nw = nw; } public String getLn() { return ln; } public void setLn(String ln) { this.ln = ln; } public String getLa() { return la; } public void setLa(String la) { this.la = la; } }
3.1.3 啟動日誌Bean
package com.test.bean; /** * 啟動日誌 */ public class AppStart extends AppBase { private String entry;//入口: push=1,widget=2,icon=3,notification=4, lockscreen_widget =5 private String open_ad_type;//開屏廣告型別: 開屏原生廣告=1, 開屏插屏廣告=2 private String action;//狀態:成功=1 失敗=2 private String loading_time;//載入時長:計算下拉開始到介面返回資料的時間,(開始載入報0,載入成功或載入失敗才上報時間) private String detail;//失敗碼(沒有則上報空) private String extend1;//失敗的message(沒有則上報空) private String en;//啟動日誌型別標記 public String getEntry() { return entry; } public void setEntry(String entry) { this.entry = entry; } public String getOpen_ad_type() { return open_ad_type; } public void setOpen_ad_type(String open_ad_type) { this.open_ad_type = open_ad_type; } public String getAction() { return action; } public void setAction(String action) { this.action = action; } public String getLoading_time() { return loading_time; } public void setLoading_time(String loading_time) { this.loading_time = loading_time; } public String getDetail() { return detail; } public void setDetail(String detail) { this.detail = detail; } public String getExtend1() { return extend1; } public void setExtend1(String extend1) { this.extend1 = extend1; } public String getEn() { return en; } public void setEn(String en) { this.en = en; } }
3.1.4 錯誤日誌Bean
package com.test.bean; /** * 錯誤日誌 */ public class AppErrorLog { private String errorBrief; //錯誤摘要 private String errorDetail; //錯誤詳情 public String getErrorBrief() { return errorBrief; } public void setErrorBrief(String errorBrief) { this.errorBrief = errorBrief; } public String getErrorDetail() { return errorDetail; } public void setErrorDetail(String errorDetail) { this.errorDetail = errorDetail; } }
3.1.5 事件日誌Bean之商品詳情
package com.test.bean; /** * 商品詳情 */ public class AppNewsDetail { private String entry;//頁面入口來源:應用首頁=1、push=2、詳情頁相關推薦=3 private String action;//動作:開始載入=1,載入成功=2(pv),載入失敗=3, 退出頁面=4 private String goodsid;//商品ID(服務端下發的ID) private String showtype;//商品樣式:0、無圖1、一張大圖2、兩張圖3、三張小圖4、一張小圖5、一張大圖兩張小圖 來源於詳情頁相關推薦的商品,上報樣式都為0(因為都是左文右圖) private String news_staytime;//頁面停留時長:從商品開始載入時開始計算,到使用者關閉頁面所用的時間。若中途用跳轉到其它頁面了,則暫停計時,待回到詳情頁時恢復計時。或中途劃出的時間超過10分鐘,則本次計時作廢,不上報本次資料。如未載入成功退出,則報空。 private String loading_time;//載入時長:計算頁面開始載入到介面返回資料的時間 (開始載入報0,載入成功或載入失敗才上報時間) private String type1;//載入失敗碼:把載入失敗狀態碼報回來(報空為載入成功,沒有失敗) private String category;//分類ID(服務端定義的分類ID) public String getEntry() { return entry; } public void setEntry(String entry) { this.entry = entry; } public String getAction() { return action; } public void setAction(String action) { this.action = action; } public String getGoodsid() { return goodsid; } public void setGoodsid(String goodsid) { this.goodsid = goodsid; } public String getShowtype() { return showtype; } public void setShowtype(String showtype) { this.showtype = showtype; } public String getNews_staytime() { return news_staytime; } public void setNews_staytime(String news_staytime) { this.news_staytime = news_staytime; } public String getLoading_time() { return loading_time; } public void setLoading_time(String loading_time) { this.loading_time = loading_time; } public String getType1() { return type1; } public void setType1(String type1) { this.type1 = type1; } public String getCategory() { return category; } public void setCategory(String category) { this.category = category; } }
3.1.6 事件日誌Bean之商品列表
package com.test.bean; /** * 商品列表 */ public class AppLoading { private String action;//動作:開始載入=1,載入成功=2,載入失敗=3 private String loading_time;//載入時長:計算下拉開始到介面返回資料的時間,(開始載入報0,載入成功或載入失敗才上報時間) private String loading_way;//載入型別:1-讀取快取,2-從介面拉新資料 (載入成功才上報載入型別) private String extend1;//擴充套件欄位 Extend1 private String extend2;//擴充套件欄位 Extend2 private String type;//載入型別:自動載入=1,使用者下拽載入=2,底部載入=3(底部條觸發點選底部提示條/點選返回頂部載入) private String type1;//載入失敗碼:把載入失敗狀態碼報回來(報空為載入成功,沒有失敗) public String getAction() { return action; } public void setAction(String action) { this.action = action; } public String getLoading_time() { return loading_time; } public void setLoading_time(String loading_time) { this.loading_time = loading_time; } public String getLoading_way() { return loading_way; } public void setLoading_way(String loading_way) { this.loading_way = loading_way; } public String getExtend1() { return extend1; } public void setExtend1(String extend1) { this.extend1 = extend1; } public String getExtend2() { return extend2; } public void setExtend2(String extend2) { this.extend2 = extend2; } public String getType() { return type; } public void setType(String type) { this.type = type; } public String getType1() { return type1; } public void setType1(String type1) { this.type1 = type1; } }
3.1.7 事件日誌Bean之廣告
package com.test.bean; /** * 廣告 */ public class AppAd { private String entry;//入口:商品列表頁=1 應用首頁=2 商品詳情頁=3 private String action;//動作: 廣告展示=1 廣告點選=2 private String contentType;//Type: 1 商品 2 營銷活動 private String displayMills;//展示時長 毫秒數 private String itemId; //商品id private String activityId; //營銷活動id public String getEntry() { return entry; } public void setEntry(String entry) { this.entry = entry; } public String getAction() { return action; } public void setAction(String action) { this.action = action; } public String getActivityId() { return activityId; } public void setActivityId(String activityId) { this.activityId = activityId; } public String getContentType() { return contentType; } public void setContentType(String contentType) { this.contentType = contentType; } public String getDisplayMills() { return displayMills; } public void setDisplayMills(String displayMills) { this.displayMills = displayMills; } public String getItemId() { return itemId; } public void setItemId(String itemId) { this.itemId = itemId; } }
3.1.8 事件日誌Bean之商品點選
package com.test.bean; /** * 商品點選日誌 */ public class AppDisplay { private String action;//動作:曝光商品=1,點選商品=2, private String goodsid;//商品ID(服務端下發的ID) private String place;//順序(第幾條商品,第一條為0,第二條為1,如此類推) private String extend1;//曝光型別:1 - 首次曝光 2-重複曝光(沒有使用) private String category;//分類ID(服務端定義的分類ID) public String getAction() { return action; } public void setAction(String action) { this.action = action; } public String getGoodsid() { return goodsid; } public void setGoodsid(String goodsid) { this.goodsid = goodsid; } public String getPlace() { return place; } public void setPlace(String place) { this.place = place; } public String getExtend1() { return extend1; } public void setExtend1(String extend1) { this.extend1 = extend1; } public String getCategory() { return category; } public void setCategory(String category) { this.category = category; } }
3.1.9 事件日誌Bean之訊息通知
package com.test.bean; /** * 訊息通知日誌 */ public class AppNotification { private String action;//動作:通知產生=1,通知彈出=2,通知點選=3,常駐通知展示(不重複上報,一天之內只報一次)=4 private String type;//通知id:預警通知=1,天氣預報(早=2,晚=3),常駐=4 private String ap_time;//客戶端彈出時間 private String content;//備用欄位 public String getAction() { return action; } public void setAction(String action) { this.action = action; } public String getType() { return type; } public void setType(String type) { this.type = type; } public String getAp_time() { return ap_time; } public void setAp_time(String ap_time) { this.ap_time = ap_time; } public String getContent() { return content; } public void setContent(String content) { this.content = content; } }
3.1.10 事件日誌Bean之使用者後臺活躍
package com.test.bean; /** * 使用者後臺活躍 */ public class AppActive_background { private String active_source;//1=upgrade,2=download(下載),3=plugin_upgrade public String getActive_source() { return active_source; } public void setActive_source(String active_source) { this.active_source = active_source; } }
3.1.11 事件日誌Bean之使用者評論
package com.test.bean; /** * 評論 */ public class AppComment { private int comment_id;//評論表 private int userid;//使用者id private int p_comment_id;//父級評論id(為0則是一級評論,不為0則是回覆) private String content;//評論內容 private String addtime;//建立時間 private int other_id;//評論的相關id private int praise_count;//點贊數量 private int reply_count;//回覆數量 public int getComment_id() { return comment_id; } public void setComment_id(int comment_id) { this.comment_id = comment_id; } public int getUserid() { return userid; } public void setUserid(int userid) { this.userid = userid; } public int getP_comment_id() { return p_comment_id; } public void setP_comment_id(int p_comment_id) { this.p_comment_id = p_comment_id; } public String getContent() { return content; } public void setContent(String content) { this.content = content; } public String getAddtime() { return addtime; } public void setAddtime(String addtime) { this.addtime = addtime; } public int getOther_id() { return other_id; } public void setOther_id(int other_id) { this.other_id = other_id; } public int getPraise_count() { return praise_count; } public void setPraise_count(int praise_count) { this.praise_count = praise_count; } public int getReply_count() { return reply_count; } public void setReply_count(int reply_count) { this.reply_count = reply_count; } }
3.1.12 事件日誌Bean之使用者收藏
package com.test.bean; /** * 收藏 */ public class AppFavorites { private int id;//主鍵 private int course_id;//商品id private int userid;//使用者ID private String add_time;//建立時間 public int getId() { return id; } public void setId(int id) { this.id = id; } public int getCourse_id() { return course_id; } public void setCourse_id(int course_id) { this.course_id = course_id; } public int getUserid() { return userid; } public void setUserid(int userid) { this.userid = userid; } public String getAdd_time() { return add_time; } public void setAdd_time(String add_time) { this.add_time = add_time; } }
3.1.13 事件日誌Bean之使用者點贊
package com.test.bean; /** * 點贊 */ public class AppPraise { private int id; //主鍵id private int userid;//使用者id private int target_id;//點讚的物件id private int type;//點贊型別 1問答點贊 2問答評論點贊 3 文章點贊數4 評論點贊 private String add_time;//新增時間 public int getId() { return id; } public void setId(int id) { this.id = id; } public int getUserid() { return userid; } public void setUserid(int userid) { this.userid = userid; } public int getTarget_id() { return target_id; } public void setTarget_id(int target_id) { this.target_id = target_id; } public int getType() { return type; } public void setType(int type) { this.type = type; } public String getAdd_time() { return add_time; } public void setAdd_time(String add_time) { this.add_time = add_time; } }
3.1.14 主函式
在AppMain類中新增如下內容:
package com.test.appclient; import java.io.UnsupportedEncodingException; import java.util.Random; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; import com.test.bean.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * 日誌行為資料模擬 */ public class AppMain { private final static Logger logger = LoggerFactory.getLogger(AppMain.class); private static Random rand = new Random(); // 裝置id private static int s_mid = 0; // 使用者id private static int s_uid = 0; // 商品id private static int s_goodsid = 0; public static void main(String[] args) { // 引數一:控制傳送每條的延時時間,預設是0 Long delay = args.length > 0 ? Long.parseLong(args[0]) : 0L; // 引數二:迴圈遍歷次數 int loop_len = args.length > 1 ? Integer.parseInt(args[1]) : 1000; // 生成資料 generateLog(delay, loop_len); } private static void generateLog(Long delay, int loop_len) { for (int i = 0; i < loop_len; i++) { int flag = rand.nextInt(2); switch (flag) { case (0): //應用啟動 AppStart appStart = generateStart(); String jsonString = JSON.toJSONString(appStart); //控制檯列印 logger.info(jsonString); break; case (1): JSONObject json = new JSONObject(); json.put("ap", "app"); json.put("cm", generateComFields()); JSONArray eventsArray = new JSONArray(); // 事件日誌 // 商品點選,展示 if (rand.nextBoolean()) { eventsArray.add(generateDisplay()); json.put("et", eventsArray); } // 商品詳情頁 if (rand.nextBoolean()) { eventsArray.add(generateNewsDetail()); json.put("et", eventsArray); } // 商品列表頁 if (rand.nextBoolean()) { eventsArray.add(generateNewList()); json.put("et", eventsArray); } // 廣告 if (rand.nextBoolean()) { eventsArray.add(generateAd()); json.put("et", eventsArray); } // 訊息通知 if (rand.nextBoolean()) { eventsArray.add(generateNotification()); json.put("et", eventsArray); } // 使用者後臺活躍 if (rand.nextBoolean()) { eventsArray.add(generateBackground()); json.put("et", eventsArray); } //故障日誌 if (rand.nextBoolean()) { eventsArray.add(generateError()); json.put("et", eventsArray); } // 使用者評論 if (rand.nextBoolean()) { eventsArray.add(generateComment()); json.put("et", eventsArray); } // 使用者收藏 if (rand.nextBoolean()) { eventsArray.add(generateFavorites()); json.put("et", eventsArray); } // 使用者點贊 if (rand.nextBoolean()) { eventsArray.add(generatePraise()); json.put("et", eventsArray); } //時間 long millis = System.currentTimeMillis(); //控制檯列印 logger.info(millis + "|" + json.toJSONString()); break; } // 延遲 try { Thread.sleep(delay); } catch (InterruptedException e) { e.printStackTrace(); } } } /** * 公共欄位設定 */ private static JSONObject generateComFields() { AppBase appBase = new AppBase(); //裝置id appBase.setMid(s_mid + ""); s_mid++; // 使用者id appBase.setUid(s_uid + ""); s_uid++; // 程式版本號 5,6等 appBase.setVc("" + rand.nextInt(20)); //程式版本名 v1.1.1 appBase.setVn("1." + rand.nextInt(4) + "." + rand.nextInt(10)); // 安卓系統版本 appBase.setOs("8." + rand.nextInt(3) + "." + rand.nextInt(10)); // 語言 es,en,pt int flag = rand.nextInt(3); switch