大数据项目1

埋点日志采集

埋点在本项目中有三大类
App端行为日志
PC web端行为日志
微信小程序端行为日志

需求

日志生成在N台服务器中,现在需要使用flume采集到HDFS

  • 3类日志采集后要分别存储到不同的hdfs路径
  • 日志中的手机号,账号需要脱敏处理(加密)
  • 不同日期的数据要写到不同的文件夹,且分配应以事件时间为依据
  • 因为日志服务器所在子网跟HDFS集群不在同一个网段,需要中转传输
    在这里插入图片描述

上游

a1.sources = r1
a1.channels = c1
a1.sinks = k1 k2


a1.sources.r1.channels = c1
a1.sources.r1.type = TAILDIR
a1.sources.r1.filegroups = g1 g2
a1.sources.r1.filegroups.g1 = /opt/data/logdata/app/event.*
a1.sources.r1.filegroups.g2 = /opt/data/logdata/wx/event.*
a1.sources.r1.headers.g1.datatype = app
a1.sources.r1.headers.g2.datatype = wx
a1.sources.r1.batchSize = 100

a1.sources.r1.interceptors = i1
a1.sources.r1.interceptors.i1.type = cn._51doit.flnm.demo02.FieldEncryptInterceptor$FieldEncryptInterceptorBuilder
a1.sources.r1.interceptors.i1.headerName = timestamp
a1.sources.r1.interceptors.i1.timestamp_field = timeStamp
a1.sources.r1.interceptors.i1.to_encrypt_field = account


a1.channels.c1.type = file
a1.channels.c1.checkpointDir = /opt/data/flumedata/file-channel/checkpoint
a1.channels.c1.dataDirs = /opt/data/flumedata/file-channel/data


a1.sinks.k1.channel = c1
a1.sinks.k1.type = avro
a1.sinks.k1.hostname = linux02
a1.sinks.k1.port = 41414
a1.sinks.k1.batch-size = 100


a1.sinks.k2.channel = c1
a1.sinks.k2.type = avro
a1.sinks.k2.hostname = linux03
a1.sinks.k2.port = 41414
a1.sinks.k2.batch-size = 100

# 定义sink组及其配套的sink处理器
a1.sinkgroups = g1
a1.sinkgroups.g1.sinks = k1 k2
a1.sinkgroups.g1.processor.type = failover
a1.sinkgroups.g1.processor.priority.k1 = 5
a1.sinkgroups.g1.processor.priority.k2 = 1
a1.sinkgroups.g1.processor.maxpenalty = 10000
启动命令
bin/flume-ng agent -c conf/ -f agentsconf/shangyou -n a1 -Dflume.root.logger=INFO,console 

下游

a1.sources = r1
a1.channels = c1
a1.sinks = k1

a1.sources.r1.channels = c1
a1.sources.r1.type = avro
a1.sources.r1.bind = 0.0.0.0
a1.sources.r1.port = 41414
a1.sources.r1.batchSize = 100

a1.channels.c1.type = file
a1.channels.c1.checkpointDir = /opt/data/flumedata/file-channel/checkpoint
a1.channels.c1.dataDirs = /opt/data/flumedata/file-channel/data

a1.sinks.k1.channel = c1
a1.sinks.k1.type = hdfs
a1.sinks.k1.hdfs.path = hdfs://linux01:8020/logdata/%{datatype}/%Y-%m-%d/
a1.sinks.k1.hdfs.filePrefix = DoitEduData
a1.sinks.k1.hdfs.fileSuffix = .log.gz
a1.sinks.k1.hdfs.rollInterval = 600
a1.sinks.k1.hdfs.rollSize = 268435456
a1.sinks.k1.hdfs.rollCount = 0
a1.sinks.k1.hdfs.batchSize = 100
a1.sinks.k1.hdfs.codeC = gzip
a1.sinks.k1.hdfs.fileType = CompressedStream
a1.sinks.k1.hdfs.useLocalTimeStamp = false

拦截器jia包代码

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.flume.Context;
import org.apache.flume.Event;
import org.apache.flume.interceptor.Interceptor;

import java.io.UnsupportedEncodingException;
import java.util.List;

/**
 * @author 涛哥
 * @nick_name "deep as the sea"
 * @contact qq:657270652 wx:doit_edu
 * @site www.doitedu.cn
 * @date 2021-01-11
 * @desc 项目字段加密及时间戳提取拦截器
 */
public class FieldEncryptInterceptor implements Interceptor {

    String timestamp_field;
    String to_encrypt_field;
    String headerName;

    public FieldEncryptInterceptor(String timestamp_field, String to_encrypt_field, String headerName) {

        this.timestamp_field = timestamp_field;
        this.to_encrypt_field = to_encrypt_field;
        this.headerName = headerName;

    }

    public void initialize() {

    }

    public Event intercept(Event event) {

        // 根据要加密的字段,从event中提取原值(用json解析)
        try {
            String line = new String(event.getBody());
            JSONObject jsonObject = JSON.parseObject(line);

            String toEncryptField = jsonObject.getString(to_encrypt_field);
            String timeStampField = jsonObject.getString(timestamp_field);

            // 加密
            if (StringUtils.isNotBlank(toEncryptField)) {
                String encrypted = DigestUtils.md5Hex(toEncryptField);

                // 将加密后的值替换掉原值
                jsonObject.put(to_encrypt_field, encrypted);

                // 转回json,并放回event
                String res = jsonObject.toJSONString();
                event.setBody(res.getBytes("UTF-8"));
            }

            // 放入时间戳到header中
            event.getHeaders().put(headerName, timeStampField);

        } catch (Exception e) {

            event.getHeaders().put("datatype", "malformed");

            e.printStackTrace();
        }


        return event;
    }

    public List<Event> intercept(List<Event> list) {
        for (Event event : list) {
            intercept(event);
        }

        return list;
    }

    public void close() {

    }


    public static class FieldEncryptInterceptorBuilder implements Interceptor.Builder {
        String timestamp_field;
        String to_encrypt_field;
        String headerName;

        public Interceptor build() {

            return new FieldEncryptInterceptor(timestamp_field, to_encrypt_field, headerName);
        }

        public void configure(Context context) {
            timestamp_field = context.getString("timestamp_field");
            headerName = context.getString("headerName");
            to_encrypt_field = context.getString("to_encrypt_field");


        }
    }
}

项目背景(为什么要有大数据)

某些APP上线后,由于业务模式新尹,市场需求大,经过一段时间的精心运营后,逐渐积累起了上千万,用户,以及三四百万的日活量,app的业务能和产品.数量也急速膨胀,随着规模的增长,逐渐凸显出大量问题.

  • 营销分析断层:市场销售成本居高不下,投放拉新的效果追踪出现断层,无法追各渠道实际化率,难以准确分析ROI
  • 用户运营不精准:"千人一面"的全量用户营销,投入产量难以把控,不精准的粗犷方式难以真正提升存量用户的长期活跃度
  • 全局运营指标监控不实时:有运营的BI系统,但运营指标监控不及时,未形成核心的指标预警机制,决策滞后
    公司急需告别这种粗放的,严重依赖人力的运营情况,继续建设一套强大的数据运营平台,用于驱动营销渠道效果评估,用于精细化运营改进,产品功能及用户体验优化,老板看板辅助管理决策,产品个性化推荐改造,用户标签体系构建等应用市场
    从各方面为公司的进一步发展提供有力的数据支撑

需求总览:行为事件域分析

基础统计分析

  • 整体概况:从产品的整体的使用情况出发,对产品的整体使用情况有基础了解
  • 用户获取:从获客渠道和版本的方向出发,根据不同渠道,不同的版本生成一些可以了解渠道优略的指标,可以清晰的观察每个渠道的流量,转化等情况
  • 活跃与留存:从用户的访问和粘性出发,可以观察出产品在用户访问,回访等方面的趋势变化,清楚的了解用户对产品的粘性和沉浸程度
  • 事件转化;根据选择的事件和属性,生成该事件的发生次数,人数,分布等数据指标,可以了解整体的用户转化以及收益相关的数据情况
  • 用户特征:根据地理位置.性别操作系统当一些基础属性,将进行分组,方便了解用户的分布占比情况

基础统计分析指标概览

整体概况
产品整体的使用情况,包括用户量、访问情况、留存等帮助对产品整体指标有一个大致的了解
累计用户量:产品上线至今的累计用户量
每日新增用户量
每日的全部访问人数、次数
每日的全部访问的人均次数/时长/深度
新老用户访问占比
每日新老用户的分布情况
新用户/全部用户的7日留存:起始和后续事件都为用户进行页面访问
各页面的访问次数分布:基于pageview事件中的页面标题属性进行分组
访问终端(app /pc web /微信小程序 /H5)分布:按照访问的操作系统分组

用户获取

渠道访问
每个渠道的用户的使用情况,包括渠道中新用户的占比、留存等,了解产品在获客层面上的优势与不足;其中App的渠道数据,会根据iOS,Android进行细分
新增用户量:全部新用户数量,包括自然流量和渠道流量
渠道新增用户量:仅计算渠道流量新增用户数
各渠道新用户人均访问时长
异常流量:App 异常流量,定义为打开5秒内即进行关闭操作的访问行为
版本数据
App 每个版本的使用情况,帮助了解在产品升级的过程中,是否在活跃和留存方面有所改善

版本访问流量
人均访问时长
各版本留存:各版本的用户7日留存
活跃与留存
访问流量
产品的每日访问数据,指标集中在新老用户的访问行为上,提供访问次数、时长、次数分布、访问时段高峰等指标,帮助了解新老用户在使用产品时的一些行为特征

访问用户数
新老用户访问占比
新老用户人均使用时长
新老用户启动/访问次数
每日/每周启动时段
用户每日访问产品的时段分布
用户每周访问产品的星期分布
用户留存
提供用户7日,次日,次周,次月留存的数据,帮助了解新老用户的使用粘性

7日留存/流失
次日留存/流失
次周留存/流失
次月留存/流失
事件转化
事件转化
各类关键事件(如收藏,分享,转发,加购等),发生次数、人数以及分布情况

新老用户事件发生次数/人数/人均次数
事件次数的分布
收益类事件转化
用户自定义收益类事件,神策会自动生成该事件的发生次数、人数以及分布情况,会根据您选择的数值类型属性,计算该数值的总值、人均值以及次均值

新老用户收益事件发生次数/人数/人均次数
新老用户收益事件
用户特征
访问省份分布
访问城市分布
访问性别分布
访问操作系统分布
新老用户占比

技术选型

数据采集:flume
存储平台:hdfs
基础设施:hive
运算引擎:mapreduce/spark
资源调度:yarn
任务调度:azkaban/oozie
元数据管理:atlas(或自研系统)
OLAP引擎:kylin/presto (或clickhouse)
前端界面:superset(或自研javaweb系统)

分层设计

分层原因
数据仓库中的数据表,往往是分层管理、分层计算的;
所谓分层,具体来说,就是将大量的数据表按照一定规则和定义来进行逻辑划分;

ADS层: 应用服务层
DWS层:数仓服务(service/summary)层(轻度聚合)
DWD层:数仓明细层
ODS层:操作数据(最原始的数据)层 – 贴源层
DIM层:存储维表
ODS层:对应着外部数据源ETL到数仓体系之后的表!
DWD层:数仓明细层;一般是对ODS层的表按主题进行加工和划分;本层中表记录的还是明细数据;
DWS层:数仓服务层;
ADS层: 应用层,主要是一些结果报表!
分层的意义:数据管理更明晰!运算复用度更高!需求开发更快捷!便于解耦底层业务(数据)变化!

分层详解

ODS层
数据内容:存放flume采集过来的原始日志
存储格式:以json格式文本文件存储
存储周期:3个月

DWD层
数据内容:对ODS层数据做ETL处理后的扁平化明细数据
存储格式:以orc / parquet文件格式存储
存储周期:6个月

DWS层
数据内容:根据主题分析需求,从DWD中轻度聚合后的数据
存储格式:以ORC/PARQUET文件格式存储
存储周期:1年

ADS层
数据内容:根据业务人员需求,从DWS计算出来的报表
存储格式:以ORC/PARQUET文件格式存储
存储周期:3年

DIM层
存储各种维表

模型设计

ODS层
与原始日志数据保持完全一致
我们有APP端日志,PC端日志,微信小程序端日志,分别对应ODS的三个表
ODS.ACTION_APP_LOG
ODS.ACTION_WEB_LOG
ODS.ACTION_WXAPP_LOG

建表时,一般采用外部表;
表的数据文件格式:跟原始日志文件一致
分区:按天分区(视数据量和计算频度而定,如数据量大且需每小时计算一次,则可按小时粒度分区)

DWD层
建模思想
通常是对ODS层数据进行精细化加工处理
不完全星型模型
事实表中,不是所有维度都按维度主键信息存储(维度退化)

地域维度信息:年月日周等时间维度信息,这些维度信息,基本不会发生任何改变,并且在大部分主题分析场景中,都需要使用,直接在事实表中存储维度值

页面信息:页面类别信息,频道信息,业务活动信息,会员等级信息等,可能发生缓慢变化的维度信息,事实表中遵循经典理论存储维度主键,具体维度值则在主题分析计算时临时关联

事实表
app_event_detail: APP-Event事件明细表
web_event_detail: WEB-Event事件明细表
wxapp_event_detail: 小程序-Event事件明细表
维度表
coupon_info
ad_info
campain_info
lanmu_info
page_info
page_type
pindao_info
promotion_location
huodong_info
miaosha_info
product
product_detail
product_type
shop_info
tuangou_info
user_info

DWS层
建模思想
主题建模
维度建模

最主要思路:按照分析主题,"汇总"各类数据成大宽表
也有一些做法是,将DWS层的表设计成“轻度聚合表”

主要表模型
流量会话聚合天/月表
日新日活维度聚合表
事件会话聚合天/月表
访客连续活跃区间表

新用户留存维度聚合表
运营位维度聚合表
渠道拉新维度聚合表
访客分布维度聚合表

用户事件链聚合表(支撑转化分析,高级留存分析等)
……更多

ODS层详细设计ODS层功能

ODS:操作数据层
主要作用:直接映射操作数据(原始数据),数据备份;
建模方法:与原始数据结构保持完全一致
存储周期:相对来说,存储周期较短;视数据规模,增长速度,以及业务的需求而定;对于埋点日志数据ODS层存储,通常可以选择3个月或者半年;存1年的是土豪公司(或者确有需要,当然,也有可能是数据量很小)

ODS层开发手册

3类日志数据
数据类型 输入路径(HDFS目录) 目标位置(HIVE表)
app端埋点日志 /logdata/app/2020-07-26/ ods.event_app_log 分区:2020/07/26
web端埋点日志 /logdata/web/2020-07-26/ ods.event_web_log 分区:2020/07/26
wx小程序埋点日志 /logdata/wxapp/2020-07-26/ ods.event_wxapp_log 分区:2020/07/26
H5页面埋点日志 /
表明命名规范:层级.主题_数据域_功能_粒度
比如:app事件明细表: dwd.event_app_detail_d

要求:
原始日志格式
普通文本文件,JSON数据格式,导入hive表后,要求可以很方便地select各个字段
分区表
外部表

创建外部表

由于原始数据是普通文本文件,而文件内容是json格式的一条一条记录
在创建hive表结构进行映射时,有两种选择:
1.将数据视为无结构的string
2.将数据按json格式进行映射(这需要外部工具包JsonSerde 的支持)

本项目采用方案2来进行建表映射

hive完整建表语句和解析

--指定表名
create table t3(
id int,
name string
)
--指定分区
PARTITIONED BY (dt string)
--指定分隔符
ROW FORMAT 
SERDE 'org.apache.hadoop.hive.serde2.lazy.LazySimpleSerDe'
WITH SERDEPROPERTIES (   
  'field.delim'=',',   
  'line.delim'='\n'
)
--指定输入输出格式
STORED AS
  INPUTFORMAT 
    'org.apache.hadoop.mapred.TextInputFormat'
  OUTPUTFORMAT 
    'org.apache.hadoop.hive.ql.io.HiveIgnoreKeyTextOutputFormat'
--表属性
TBLPROPERTIES(
  'EXTERNAL'='TRUE',
  'comment'='this is a ods table',
  'orc.compress'='snappy'
)
;

-- ODS层,app埋点日志对应表模型创建
--先删除表防止有这个表明
DROP TABLE IF EXISTS `ods.event_app_log`;
--指定表明和外部表的属性
CREATE EXTERNAL TABLE `ods.event_app_log`(         
  `account` string ,    
  `appid` string ,      
  `appversion` string , 
  `carrier` string ,    
  `deviceid` string ,   
  `devicetype` string , 
  `eventid` string ,    
  `ip` string ,         
  `latitude` double ,   
  `longitude` double ,  
  `nettype` string ,    
  `osname` string ,     
  `osversion` string ,  
  `properties` map<string,string> ,  
  `releasechannel` string ,   
  `resolution` string ,   
  `sessionid` string ,   
  `timestamp` bigint 
)   
--指定分区
PARTITIONED BY (`dt` string)    
--指定分隔符这边是以json格式切割                                  
ROW FORMAT SERDE                                    
  'org.apache.hive.hcatalog.data.JsonSerDe' 
--指定输入输出格式
STORED AS INPUTFORMAT                               
  'org.apache.hadoop.mapred.TextInputFormat'        
OUTPUTFORMAT                                        
  'org.apache.hadoop.hive.ql.io.HiveIgnoreKeyTextOutputFormat'  
--指定输出路径
LOCATION                                            
  'hdfs://linux01:8020/user/hive/warehouse/ods.db/event_app_log'  
--表属性版本号之类的没啥用
TBLPROPERTIES (                                     
  'bucketing_version'='2',                          
  'transient_lastDdlTime'='1610337798'
);

接下来就是具体操作

流程是我们会从别的数据库通过flime导到自己的hdfs中,然后经过自己的hive处理成结构化数据再放回到自己的hdfs上,原来的数据就没了
flime就是上面的上游下游,hive建表就是上面的埋点数据建模然后load一下

load data inpath '/logdata/app/2021-01-10' into table ods.event_app_log partition(dt='2021-01-10');
-- 数据入库
load data inpath '/logdata/app/2021-01-10' into table ods.event_app_log partition(dt='2021-01-10');

-- 如何删除一个表中已存在分区
alter table ods.event_app_log drop partition(dt='2020-01-10');

-- 不适用load,如何添加一个分区到已存在的表中
alter table ods.event_app_log add partition(dt='2020-01-11') location '/abc/ddd/'
-- 入库脚本开发
#!/bin/bash
######################################
#
#  @author :  
#  @date   :  2021-01-11
#  @desc   :  app端埋点日志入库
#  @other  
######################################

export JAVA_HOME=/opt/apps/jdk1.8.0_141/
export HIVE_HOME=/opt/apps/hive-3.1.2/


DT=$(date -d'-1 day' +%Y-%m-%d)

${HIVE_HOME}/bin/hive -e "
load data inpath '/logdata/app/${DT}' into table ods.event_app_log partition(dt='${DT}')
"

if [ $? -eq 0 ]
then
 echo "${DT}app success"
else
 echo "wx failed"
fi
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值