01 电商数仓(架构设计、用户行为数据生成脚本)
电商数仓(架构设计、用户行为数据生成脚本)
写在前面: 本文是我在学习电商数仓项目的过程中,对相关知识点的记录,总结。
文章目录
- 电商数仓(架构设计、用户行为数据生成脚本)
- 1. 数据仓库的概念
- 2. 项目需求及架构设计
- 2.1 项目需求
- 2.2 项目框架
- 2.2.1 技术选型
- 2.2.2 系统数据流程设计
- 2.2.3 框架版本选型
- 2.2.4 服务器选型及资源规划
- 3. 数据生成模块
- 3.1 埋点数据基本格式
- 3.2 事件日志数据
- 3.3 数据生成脚本
- 3.3.1 创建 Maven 工程
- 3.3.2 导入 Bean
- 3.3.3 主函数
- 3.3.4 配置日志打印 Logback
- 3.3.5 打包
1. 数据仓库的概念
数据仓库,英文名称为
Data Warehouse
,可简写为DW
或DWH
。数据仓库,是为企业所有级别的决策制定过程,提供所有类型数据支持的战略集合。它是单个数据存储,出于分析性报告和决策支持目的而创建。 为需要业务智能的企业,提供指导业务流程改进、监视时间、成本、质量以及控制。摘自百度百科。
2. 项目需求及架构设计
2.1 项目需求
- 数据采集平台搭建。
- 实现用户行为数仓的分层搭建。
- 实现业务数据仓库的分层搭建。
- 针对数仓中的数据进行报表分析。
2.2 项目框架
2.2.1 技术选型
- 数据采集传输:
Flume
、Kafka
、Sqoop
。 - 数据存储:
HDFS
、MySQL
。 - 数据计算:
Hive
、Tez
。
2.2.2 系统数据流程设计
2.2.3 框架版本选型
产品 | 版本 |
---|---|
Hadoop | 2.7.2 |
Flume | 1.7.0 |
Kafka | 0.11.0.2 |
Hive | 1.2.1 |
Sqoop | 1.4.6 |
Zookeeper | 3.4.10 |
MySQL | 5.6.24 |
Java | 1.8 |
Azkaban | 2.5.0 |
2.2.4 服务器选型及资源规划
我这里使用的是三台
Linux
虚拟机(CentOS 6.8
) :分别为Hadoop101
、Hadoop102
、Hadoop103
。资源规划:
服务名称 子服务 Hadoop101 Hadoop102 Hadoop103 HDFS NameNode √ DataNode √ √ √ SecondaryNameNode √ Yarn NodeManager √ √ √ ResourceManager √ Zookeeper Zookeeper Server √ √ √ Flume(采集数据) Flume √ √ Kafka Kafka √ √ √ Flume(消费Kafka) Flume √ Hive Hive √ MySQL MySQL √ Sqoop Sqoop √ Azkaban AzkabanWebServer √ AzkabanExecutorServer √
3. 数据生成模块
3.1 埋点数据基本格式
公共字段: 基本所有安卓手机都包含的字段。
业务字段: 埋点上报的字段,有具体的业务类型。
示例:
// 字段解释 {"ap":"xxxxx",//项目数据来源 app pc "cm": { //公共字段"mid": "", // (String) 设备唯一标识"uid": "", // (String) 用户标识"vc": "1", // (String) versionCode,程序版本号"vn": "1.0", // (String) versionName,程序版本名"l": "zh", // (String) 系统语言"sr": "", // (String) 渠道号,应用从哪个渠道来的。"os": "7.1.1", // (String) Android系统版本"ar": "CN", // (String) 区域"md": "BBB100-1", // (String) 手机型号"ba": "blackberry", // (String) 手机品牌"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": "abc@gmail.com", "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 事件日志数据
事件名称 | 事件代表字段 |
---|---|
商品列表页 | loading |
商品点击 | display |
商品详情页 | newsdetail |
广告 | ad |
消息通知 | notification |
用户前台活跃 | active_foreground |
用户后台活跃 | active_background |
评论 | comment |
收藏 | favorites |
点赞 | praise |
错误摘要 | errorBrief |
错误详情 | errorDetail |
启动 | start |
3.3 数据生成脚本
3.3.1 创建 Maven 工程
创建项目:
log-collector
。创建包:
com.guli.appclient
。在包
com.guli.appclient
中,创建一个类AppMain
。导入依赖:
<!--版本号统一--> <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><!-- 注意:com.guli.appclient.AppMain 要与自己建的全类名一致 --><mainClass>com.guli.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>
3.3.2 导入 Bean
创建包:
com.guli.bean
导入如下
Bean
对象:公共字段
Bean
package com.guli.bean;/*** 公共日志*/ public class AppBase{private String mid; // (String) 设备唯一标识private String uid; // (String) 用户uidprivate 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) sdkVersionprivate String g; // (String) gmailprivate 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;} }
启动日志
Bean
package com.guli.bean;/*** 启动日志*/ public class AppStart extends AppBase {private String entry;//入口: push=1,widget=2,icon=3,notification=4, lockscreen_widget =5private String open_ad_type;//开屏广告类型: 开屏原生广告=1, 开屏插屏广告=2private String action;//状态:成功=1 失败=2private 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;} }
错误日志
Bean
package com.guli.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;} }
事件日志
Bean
之商品点击package com.guli.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;} }
事件日志
bean
之商品详情页package com.guli.bean;/*** 商品详情*/ public class AppNewsDetail {private String entry;//页面入口来源:应用首页=1、push=2、详情页相关推荐=3private String action;//动作:开始加载=1,加载成功=2(pv),加载失败=3, 退出页面=4private 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;} }
事件日志
bean
之商品列表页package com.guli.bean;/*** 商品列表*/ public class AppLoading {private String action;//动作:开始加载=1,加载成功=2,加载失败=3private String loading_time;//加载时长:计算下拉开始到接口返回数据的时间,(开始加载报0,加载成功或加载失败才上报时间)private String loading_way;//加载类型:1-读取缓存,2-从接口拉新数据 (加载成功才上报加载类型)private String extend1;//扩展字段 Extend1private String extend2;//扩展字段 Extend2private 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;} }
事件日志
bean
之广告package com.guli.bean;/*** 广告*/ public class AppAd {private String entry;//入口:商品列表页=1 应用首页=2 商品详情页=3private String action;//动作:请求广告=1 取缓存广告=2 广告位展示=3 广告展示=4 广告点击=5private String content;//状态:成功=1 失败=2private String detail;//失败码(没有则上报空)private String source;//广告来源:admob=1 facebook=2 ADX(百度)=3 VK(俄罗斯)=4private String behavior;//用户行为: 主动获取广告=1 被动获取广告=2private String newstype;//Type: 1- 图文 2-图集 3-段子 4-GIF 5-视频 6-调查 7-纯文 8-视频+图文 9-GIF+图文 0-其他private String show_style;//内容样式:无图(纯文字)=6 一张大图=1 三站小图+文=4 一张小图=2 一张大图两张小图+文=3 图集+文 = 5//一张大图+文=11 GIF大图+文=12 视频(大图)+文 = 13//来源于详情页相关推荐的商品,上报样式都为0(因为都是左文右图)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 getContent() {return content;}public void setContent(String content) {this.content = content;}public String getDetail() {return detail;}public void setDetail(String detail) {this.detail = detail;}public String getSource() {return source;}public void setSource(String source) {this.source = source;}public String getBehavior() {return behavior;}public void setBehavior(String behavior) {this.behavior = behavior;}public String getNewstype() {return newstype;}public void setNewstype(String newstype) {this.newstype = newstype;}public String getShow_style() {return show_style;}public void setShow_style(String show_style) {this.show_style = show_style;} }
事件日志
bean
之消息通知package com.guli.bean;/*** 消息通知日志*/ public class AppNotification {private String action;//动作:通知产生=1,通知弹出=2,通知点击=3,常驻通知展示(不重复上报,一天之内只报一次)=4private String type;//通知id:预警通知=1,天气预报(早=2,晚=3),常驻=4private 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;} }
事件日志
bean
之用户前台活跃package com.guli.bean;/*** 用户前台活跃*/ public class AppActive_foreground {private String push_id;//推送的消息的id,如果不是从推送消息打开,传空private String access;//1.push 2.icon 3.其他public String getPush_id() {return push_id;}public void setPush_id(String push_id) {this.push_id = push_id;}public String getAccess() {return access;}public void setAccess(String access) {this.access = access;} }
事件日志
bean
之用户后台活跃package com.guli.bean;/*** 用户后台活跃*/ public class AppActive_background {private String active_source;//1=upgrade,2=download(下载),3=plugin_upgradepublic String getActive_source() {return active_source;}public void setActive_source(String active_source) {this.active_source = active_source;} }
事件日志
bean
之用户评论package com.guli.bean;/*** 评论*/ public class AppComment {private int comment_id;//评论表private int userid;//用户idprivate int p_comment_id;//父级评论id(为0则是一级评论,不为0则是回复)private String content;//评论内容private String addtime;//创建时间private int other_id;//评论的相关idprivate 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;} }
事件日志
bean
之用户收藏package com.guli.bean;/*** 收藏*/ public class AppFavorites {private int id;//主键private int course_id;//商品idprivate int userid;//用户IDprivate 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;} }
事件日志
bean
之用户点赞package com.guli.bean;/*** 点赞*/ public class AppPraise {private int id; //主键idprivate int userid;//用户idprivate int target_id;//点赞的对象idprivate 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.3.3 主函数
在 AppMain
类中添加如下代码:
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.guli.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();// 设备idprivate static int s_mid = 0;// 用户idprivate static int s_uid = 0;// 商品idprivate static int s_goodsid = 0;public static void main(String[] args) {// 参数一:控制发送每条的延时时间,默认是0Long 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(generatbeforeground());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();//设备idappBase.setMid(s_mid + "");s_mid++;// 用户idappBase.setUid(s_uid + "");s_uid++;// 程序版本号 5,6等appBase.setVc("" + rand.nextInt(20));//程序版本名 v1.1.1appBase.setVn("1." + rand.nextInt(4) + "." + rand.nextInt(10));// 安卓系统版本appBase.setOs("8." + rand.nextInt(3) + "." + rand.nextInt(10));// 语言 es,en,ptint flag = rand.nextInt(3);switch (flag) {case (0):appBase.setL("es");break;case (1):appBase.setL("en");break;case (2):appBase.setL("pt");break;}// 渠道号 从哪个渠道来的appBase.setSr(getRandomChar(1));// 区域flag = rand.nextInt(2);switch (flag) {case 0:appBase.setAr("BR");case 1:appBase.setAr("MX");}// 手机品牌 ba ,手机型号 md,就取2位数字了flag = rand.nextInt(3);switch (flag) {case 0:appBase.setBa("Sumsung");appBase.setMd("sumsung-" + rand.nextInt(20));break;case 1:appBase.setBa("Huawei");appBase.setMd("Huawei-" + rand.nextInt(20));break;case 2:appBase.setBa("HTC");appBase.setMd("HTC-" + rand.nextInt(20));break;}// 嵌入sdk的版本appBase.setSv("V2." + rand.nextInt(10) + "." + rand.nextInt(10));// gmailappBase.setG(getRandomCharAndNumr(8) + "@gmail.com");// 屏幕宽高 hwflag = rand.nextInt(4);switch (flag) {case 0:appBase.setHw("640*960");break;case 1:appBase.setHw("640*1136");break;case 2:appBase.setHw("750*1134");break;case 3:appBase.setHw("1080*1920");break;}// 客户端产生日志时间long millis = System.currentTimeMillis();appBase.setT("" + (millis - rand.nextInt(99999999)));// 手机网络模式 3G,4G,WIFIflag = rand.nextInt(3);switch (flag) {case 0:appBase.setNw("3G");break;case 1:appBase.setNw("4G");break;case 2:appBase.setNw("WIFI");break;}// 拉丁美洲 西经34°46′至西经117°09;北纬32°42′至南纬53°54′// 经度appBase.setLn((-34 - rand.nextInt(83) - rand.nextInt(60) / 10.0) + "");// 纬度appBase.setLa((32 - rand.nextInt(85) - rand.nextInt(60) / 10.0) + "");return (JSONObject) JSON.toJSON(appBase);}/*** 商品展示事件*/private static JSONObject generateDisplay() {AppDisplay appDisplay = new AppDisplay();boolean boolFlag = rand.nextInt(10) < 7;// 动作:曝光商品=1,点击商品=2,if (boolFlag) {appDisplay.setAction("1");} else {appDisplay.setAction("2");}// 商品idString goodsId = s_goodsid + "";s_goodsid++;appDisplay.setGoodsid(goodsId);// 顺序 设置成6条吧int flag = rand.nextInt(6);appDisplay.setPlace("" + flag);// 曝光类型flag = 1 + rand.nextInt(2);appDisplay.setExtend1("" + flag);// 分类flag = 1 + rand.nextInt(100);appDisplay.setCategory("" + flag);JSONObject jsonObject = (JSONObject) JSON.toJSON(appDisplay);return packEventJson("display", jsonObject);}/*** 商品详情页*/private static JSONObject generateNewsDetail() {AppNewsDetail appNewsDetail = new AppNewsDetail();// 页面入口来源int flag = 1 + rand.nextInt(3);appNewsDetail.setEntry(flag + "");// 动作appNewsDetail.setAction("" + (rand.nextInt(4) + 1));// 商品idappNewsDetail.setGoodsid(s_goodsid + "");// 商品来源类型flag = 1 + rand.nextInt(3);appNewsDetail.setShowtype(flag + "");// 商品样式flag = rand.nextInt(6);appNewsDetail.setShowtype("" + flag);// 页面停留时长flag = rand.nextInt(10) * rand.nextInt(7);appNewsDetail.setNews_staytime(flag + "");// 加载时长flag = rand.nextInt(10) * rand.nextInt(7);appNewsDetail.setLoading_time(flag + "");// 加载失败码flag = rand.nextInt(10);switch (flag) {case 1:appNewsDetail.setType1("102");break;case 2:appNewsDetail.setType1("201");break;case 3:appNewsDetail.setType1("325");break;case 4:appNewsDetail.setType1("433");break;case 5:appNewsDetail.setType1("542");break;default:appNewsDetail.setType1("");break;}// 分类flag = 1 + rand.nextInt(100);appNewsDetail.setCategory("" + flag);JSONObject eventJson = (JSONObject) JSON.toJSON(appNewsDetail);return packEventJson("newsdetail", eventJson);}/*** 商品列表*/private static JSONObject generateNewList() {AppLoading appLoading = new AppLoading();// 动作int flag = rand.nextInt(3) + 1;appLoading.setAction(flag + "");// 加载时长flag = rand.nextInt(10) * rand.nextInt(7);appLoading.setLoading_time(flag + "");// 失败码flag = rand.nextInt(10);switch (flag) {case 1:appLoading.setType1("102");break;case 2:appLoading.setType1("201");break;case 3:appLoading.setType1("325");break;case 4:appLoading.setType1("433");break;case 5:appLoading.setType1("542");break;default:appLoading.setType1("");break;}// 页面 加载类型flag = 1 + rand.nextInt(2);appLoading.setLoading_way("" + flag);// 扩展字段1appLoading.setExtend1("");// 扩展字段2appLoading.setExtend2("");// 用户加载类型flag = 1 + rand.nextInt(3);appLoading.setType("" + flag);JSONObject jsonObject = (JSONObject) JSON.toJSON(appLoading);return packEventJson("loading", jsonObject);}/*** 广告相关字段*/private static JSONObject generateAd() {AppAd appAd = new AppAd();// 入口int flag = rand.nextInt(3) + 1;appAd.setEntry(flag + "");// 动作flag = rand.nextInt(5) + 1;appAd.setAction(flag + "");// 状态flag = rand.nextInt(10) > 6 ? 2 : 1;appAd.setContent(flag + "");// 失败码flag = rand.nextInt(10);switch (flag) {case 1:appAd.setDetail("102");break;case 2:appAd.setDetail("201");break;case 3:appAd.setDetail("325");break;case 4:appAd.setDetail("433");break;case 5:appAd.setDetail("542");break;default:appAd.setDetail("");break;}// 广告来源flag = rand.nextInt(4) + 1;appAd.setSource(flag + "");// 用户行为flag = rand.nextInt(2) + 1;appAd.setBehavior(flag + "");// 商品类型flag = rand.nextInt(10);appAd.setNewstype("" + flag);// 展示样式flag = rand.nextInt(6);appAd.setShow_style("" + flag);JSONObject jsonObject = (JSONObject) JSON.toJSON(appAd);return packEventJson("ad", jsonObject);}/*** 启动日志*/private static AppStart generateStart() {AppStart appStart = new AppStart();//设备idappStart.setMid(s_mid + "");s_mid++;// 用户idappStart.setUid(s_uid + "");s_uid++;// 程序版本号 5,6等appStart.setVc("" + rand.nextInt(20));//程序版本名 v1.1.1appStart.setVn("1." + rand.nextInt(4) + "." + rand.nextInt(10));// 安卓系统版本appStart.setOs("8." + rand.nextInt(3) + "." + rand.nextInt(10));//设置日志类型appStart.setEn("start");// 语言 es,en,ptint flag = rand.nextInt(3);switch (flag) {case (0):appStart.setL("es");break;case (1):appStart.setL("en");break;case (2):appStart.setL("pt");break;}// 渠道号 从哪个渠道来的appStart.setSr(getRandomChar(1));// 区域flag = rand.nextInt(2);switch (flag) {case 0:appStart.setAr("BR");case 1:appStart.setAr("MX");}// 手机品牌 ba ,手机型号 md,就取2位数字了flag = rand.nextInt(3);switch (flag) {case 0:appStart.setBa("Sumsung");appStart.setMd("sumsung-" + rand.nextInt(20));break;case 1:appStart.setBa("Huawei");appStart.setMd("Huawei-" + rand.nextInt(20));break;case 2:appStart.setBa("HTC");appStart.setMd("HTC-" + rand.nextInt(20));break;}// 嵌入sdk的版本appStart.setSv("V2." + rand.nextInt(10) + "." + rand.nextInt(10));// gmailappStart.setG(getRandomCharAndNumr(8) + "@gmail.com");// 屏幕宽高 hwflag = rand.nextInt(4);switch (flag) {case 0:appStart.setHw("640*960");break;case 1:appStart.setHw("640*1136");break;case 2:appStart.setHw("750*1134");break;case 3:appStart.setHw("1080*1920");break;}// 客户端产生日志时间long millis = System.currentTimeMillis();appStart.setT("" + (millis - rand.nextInt(99999999)));// 手机网络模式 3G,4G,WIFIflag = rand.nextInt(3);switch (flag) {case 0:appStart.setNw("3G");break;case 1:appStart.setNw("4G");break;case 2:appStart.setNw("WIFI");break;}// 拉丁美洲 西经34°46′至西经117°09;北纬32°42′至南纬53°54′// 经度appStart.setLn((-34 - rand.nextInt(83) - rand.nextInt(60) / 10.0) + "");// 纬度appStart.setLa((32 - rand.nextInt(85) - rand.nextInt(60) / 10.0) + "");// 入口flag = rand.nextInt(5) + 1;appStart.setEntry(flag + "");// 开屏广告类型flag = rand.nextInt(2) + 1;appStart.setOpen_ad_type(flag + "");// 状态flag = rand.nextInt(10) > 8 ? 2 : 1;appStart.setAction(flag + "");// 加载时长appStart.setLoading_time(rand.nextInt(20) + "");// 失败码flag = rand.nextInt(10);switch (flag) {case 1:appStart.setDetail("102");break;case 2:appStart.setDetail("201");break;case 3:appStart.setDetail("325");break;case 4:appStart.setDetail("433");break;case 5:appStart.setDetail("542");break;default:appStart.setDetail("");break;}// 扩展字段appStart.setExtend1("");return appStart;}/*** 消息通知*/private static JSONObject generateNotification() {AppNotification appNotification = new AppNotification();int flag = rand.nextInt(4) + 1;// 动作appNotification.setAction(flag + "");// 通知idflag = rand.nextInt(4) + 1;appNotification.setType(flag + "");// 客户端弹时间appNotification.setAp_time((System.currentTimeMillis() - rand.nextInt(99999999)) + "");// 备用字段appNotification.setContent("");JSONObject jsonObject = (JSONObject) JSON.toJSON(appNotification);return packEventJson("notification", jsonObject);}/*** 前台活跃*/private static JSONObject generatbeforeground() {AppActive_foreground appActive_foreground = new AppActive_foreground();// 推送消息的idint flag = rand.nextInt(2);switch (flag) {case 1:appActive_foreground.setAccess(flag + "");break;default:appActive_foreground.setAccess("");break;}// 1.push 2.icon 3.其他flag = rand.nextInt(3) + 1;appActive_foreground.setPush_id(flag + "");JSONObject jsonObject = (JSONObject) JSON.toJSON(appActive_foreground);return packEventJson("active_foreground", jsonObject);}/*** 后台活跃*/private static JSONObject generateBackground() {AppActive_background appActive_background = new AppActive_background();// 启动源int flag = rand.nextInt(3) + 1;appActive_background.setActive_source(flag + "");JSONObject jsonObject = (JSONObject) JSON.toJSON(appActive_background);return packEventJson("active_background", jsonObject);}/*** 错误日志数据*/private static JSONObject generateError() {AppErrorLog appErrorLog = new AppErrorLog();String[] errorBriefs = {"at cn.lift.dfdf.web.AbstractBaseController.validInbound(AbstractBaseController.java:72)", "at cn.lift.appIn.control.CommandUtil.getInfo(CommandUtil.java:67)"}; //错误摘要String[] errorDetails = {"java.lang.NullPointerException\\n " + "at cn.lift.appIn.web.AbstractBaseController.validInbound(AbstractBaseController.java:72)\\n " + "at cn.lift.dfdf.web.AbstractBaseController.validInbound", "at cn.lift.dfdfdf.control.CommandUtil.getInfo(CommandUtil.java:67)\\n " + "at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)\\n" + " at java.lang.reflect.Method.invoke(Method.java:606)\\n"}; //错误详情//错误摘要appErrorLog.setErrorBrief(errorBriefs[rand.nextInt(errorBriefs.length)]);//错误详情appErrorLog.setErrorDetail(errorDetails[rand.nextInt(errorDetails.length)]);JSONObject jsonObject = (JSONObject) JSON.toJSON(appErrorLog);return packEventJson("error", jsonObject);}/*** 为各个事件类型的公共字段(时间、事件类型、Json数据)拼接*/private static JSONObject packEventJson(String eventName, JSONObject jsonObject) {JSONObject eventJson = new JSONObject();eventJson.put("ett", (System.currentTimeMillis() - rand.nextInt(99999999)) + "");eventJson.put("en", eventName);eventJson.put("kv", jsonObject);return eventJson;}/*** 获取随机字母组合** @param length 字符串长度*/private static String getRandomChar(Integer length) {StringBuilder str = new StringBuilder();Random random = new Random();for (int i = 0; i < length; i++) {// 字符串str.append((char) (65 + random.nextInt(26)));// 取得大写字母}return str.toString();}/*** 获取随机字母数字组合** @param length 字符串长度*/private static String getRandomCharAndNumr(Integer length) {StringBuilder str = new StringBuilder();Random random = new Random();for (int i = 0; i < length; i++) {boolean b = random.nextBoolean();if (b) { // 字符串// int choice = random.nextBoolean() ? 65 : 97; 取得65大写字母还是97小写字母str.append((char) (65 + random.nextInt(26)));// 取得大写字母} else { // 数字str.append(String.valueOf(random.nextInt(10)));}}return str.toString();}/*** 收藏*/private static JSONObject generateFavorites() {AppFavorites favorites = new AppFavorites();favorites.setCourse_id(rand.nextInt(10));favorites.setUserid(rand.nextInt(10));favorites.setAdd_time((System.currentTimeMillis() - rand.nextInt(99999999)) + "");JSONObject jsonObject = (JSONObject) JSON.toJSON(favorites);return packEventJson("favorites", jsonObject);}/*** 点赞*/private static JSONObject generatePraise() {AppPraise praise = new AppPraise();praise.setId(rand.nextInt(10));praise.setUserid(rand.nextInt(10));praise.setTarget_id(rand.nextInt(10));praise.setType(rand.nextInt(4) + 1);praise.setAdd_time((System.currentTimeMillis() - rand.nextInt(99999999)) + "");JSONObject jsonObject = (JSONObject) JSON.toJSON(praise);return packEventJson("praise", jsonObject);}/*** 评论*/private static JSONObject generateComment() {AppComment comment = new AppComment();comment.setComment_id(rand.nextInt(10));comment.setUserid(rand.nextInt(10));comment.setP_comment_id(rand.nextInt(5));comment.setContent(getCONTENT());comment.setAddtime((System.currentTimeMillis() - rand.nextInt(99999999)) + "");comment.setOther_id(rand.nextInt(10));comment.setPraise_count(rand.nextInt(1000));comment.setReply_count(rand.nextInt(200));JSONObject jsonObject = (JSONObject) JSON.toJSON(comment);return packEventJson("comment", jsonObject);}/*** 生成单个汉字*/private static char getRandomChar() {String str = "";int hightPos; //int lowPos;Random random = new Random();//随机生成汉子的两个字节hightPos = (176 + Math.abs(random.nextInt(39)));lowPos = (161 + Math.abs(random.nextInt(93)));byte[] b = new byte[2];b[0] = (Integer.valueOf(hightPos)).byteValue();b[1] = (Integer.valueOf(lowPos)).byteValue();try {str = new String(b, "GBK");} catch (UnsupportedEncodingException e) {e.printStackTrace();System.out.println("错误");}return str.charAt(0);}/*** 拼接成多个汉字*/private static String getCONTENT() {StringBuilder str = new StringBuilder();for (int i = 0; i < rand.nextInt(100); i++) {str.append(getRandomChar());}return str.toString();}
}
3.3.4 配置日志打印 Logback
Logback
主要用于在磁盘和控制台打印日志。
Logback
具体使用:
在
resources
文件夹下创建logback.xml
文件。在
logback.xml
文件中填写如下配置<?xml version="1.0" encoding="UTF-8"?> <configuration debug="false"><!--定义日志文件的存储地址 勿在 LogBack 的配置中使用相对路径 --><property name="LOG_HOME" value="/tmp/logs/" /><!-- 控制台输出 --><appender name="STDOUT"class="ch.qos.logback.core.ConsoleAppender"><encoderclass="ch.qos.logback.classic.encoder.PatternLayoutEncoder"><!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符 --><pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern></encoder></appender><!-- 按照每天生成日志文件。存储事件日志 --><appender name="FILE"class="ch.qos.logback.core.rolling.RollingFileAppender"><!-- <File>${LOG_HOME}/app.log</File>设置日志不超过${log.max.size}时的保存路径,注意,如果是web项目会保存到Tomcat的bin目录 下 --> <rollingPolicyclass="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"><!--日志文件输出的文件名 --><FileNamePattern>${LOG_HOME}/app-%d{yyyy-MM-dd}.log</FileNamePattern><!--日志文件保留天数 --><MaxHistory>30</MaxHistory></rollingPolicy><encoderclass="ch.qos.logback.classic.encoder.PatternLayoutEncoder"><pattern>%msg%n</pattern></encoder><!--日志文件最大的大小 --><triggeringPolicyclass="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy"><MaxFileSize>10MB</MaxFileSize></triggeringPolicy></appender><!--异步打印日志--><appender name ="ASYNC_FILE" class= "ch.qos.logback.classic.AsyncAppender"><!-- 不丢失日志.默认的,如果队列的80%已满,则会丢弃TRACT、DEBUG、INFO级别的日志 --><discardingThreshold >0</discardingThreshold><!-- 更改默认的队列的深度,该值会影响性能.默认值为256 --><queueSize>512</queueSize><!-- 添加附加的appender,最多只能添加一个 --><appender-ref ref = "FILE"/></appender><!-- 日志输出级别 --><root level="INFO"><appender-ref ref="STDOUT" /><appender-ref ref="ASYNC_FILE" /><appender-ref ref="error" /></root> </configuration>
3.3.5 打包
- 采用
Maven
对程序打包 - 采用带依赖的
jar
包,包含了程序运行需要的所有依赖。
01 电商数仓(架构设计、用户行为数据生成脚本)相关推荐
- 数据仓库之电商数仓-- 1、用户行为数据采集
目录 一.数据仓库概念 二.项目需求及架构设计 2.1 项目需求分析 2.2 项目框架 2.2.1 技术选型 2.2.2 系统数据流程设计 2.2.3 框架版本选型 2.2.4 服务器选型 2.2.5 ...
- 电商数仓DWD层用户行为日志解析
文章目录 前言 一.页面埋点日志.启动日志结构 二.日志解析的流程 2.1 启动日志表解析(包括注意事项) 2.1.1 解析思路 2.1.2 建表语句 2.1.3 数据导入 2.1.4 注意事项 2. ...
- 电商数仓笔记2_用户行为采集(数据采集模块)
电商数仓 一.数据采集模块 1.集群所有进程查看脚本 2.Hadoop安装 (1)项目经验之HDFS存储多目录 (2)集群数据均衡 (3)项目经验之支持LZO压缩配置 (4)项目经验之LZO创建索引 ...
- 【尚硅谷】电商数仓V4.0丨大数据数据仓库项目实战【学习记录】第二节
这里写目录标题 注意 电商数据仓库系统 第6章 数仓搭建-DWD层 6.1.5 动作日志表装载中定义UDTF函数 6.2.6 优惠券领用事实表(累积型快照事实表) 6.2.9 订单事实表(累积型快照事 ...
- 数据仓库之电商数仓-- 5、即席查询Kylin
目录 一.Kylin 1.1 Kylin简介 1.1.1 Kylin定义 1.1.2 Kylin相关术语 1.1.3Kylin架构 1.1.4 Kylin特点 1.2 Kylin安装 1.2.1 Ky ...
- 数据仓库之电商数仓-- 4、可视化报表Superset
目录 一.Superset入门 1.1 Superset概述 1.2 Superset应用场景 二.Superset安装及使用 2.1 安装Python环境 2.1.1 安装Miniconda 2.1 ...
- 数据仓库之电商数仓-- 3.4、电商数据仓库系统(ADS层)
目录 九.数仓搭建-ADS层 9.1 建表说明 9.2 访客主题 9.2.1 访客统计 9.2.2 路径分析 9.3 用户主题 9.3.1 用户统计 9.3.2 用户变动统计 9.3.3 用户行为漏斗 ...
- 数据仓库之电商数仓-- 3.3、电商数据仓库系统(DWT层)
目录 八.数仓搭建-DWT层 8.1 访客主题 8.2 用户主题 8.3 商品主题 8.4 优惠券主题 8.5 活动主题 8.6 地区主题 8.7 DWT层首日数据导入脚本 8.8 DWT层每日数据导 ...
- 数据仓库之电商数仓-- 3.2、电商数据仓库系统(DWS层)
目录 七.数仓搭建-DWS层 7.1 系统函数 7.1.1 nvl函数 7.1.2 日期处理函数 7.1.3 复杂数据类型定义 7.2 DWS层 7.2.1 访客主题 7.2.2 用户主题 7.2.3 ...
最新文章
- 排序算法系列:插入排序算法
- ffmpeg推流时与服务器断开后的自动重连功能的实现
- 【Linux】一步一步学Linux——split命令(59)
- 高效管理ASP.NET的JavaScript库
- linux查找指定修改时间的文件夹,linux 查找某个日期以后修改过哪些文件 shell脚本...
- pip3 安装pycrypto 时报错
- 数据推动变革 PMC创新存储方案应对挑战
- 【PC工具】更新win10关闭更新工具Windows Update Blocker
- Nginx代理高德API(无法地图选点)
- emc re 整改 超标_EMC测试及整改对策.ppt
- vnc报错 PID file /home/root/.vnc/localhost.pid not readable after start.
- 域渗透非约束委派Spooler
- 天津市儿童计算机编程课,天津2021少儿编程(少儿机器人编程是什么)
- uniapp小程序 触底刷新(onReachBottom)加载分页
- MySQL 数据库之 MMM 高可用架构构建
- 鲁泰纺织:在行业整合中稳健前行
- 虹科分享 | 盘点世界杯有趣小知识!带你感受体育赛事可视化的快乐!
- win10彻底关闭电脑的自动更新
- 在vscode编辑器里使用leetcode插件刷题
- 卷积、自相关函数、功率谱密度