1. 程式人生 > >大資料專案之電商數倉一(使用者行為採集)

大資料專案之電商數倉一(使用者行為採集)

一、資料倉庫概念

資料倉庫(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