大数据项目之电商数据仓库系统(二)

第4章 数仓搭建-DWD层

1)对用户行为数据解析。

2)对核心数据进行判空过滤。

3)对业务数据采用维度模型重新建模。

4.1 DWD层(用户行为日志解析)

4.1.1 日志格式回顾

(1)页面埋点日志

(2)启动日志

4.1.2 get_json_object函数使用

1)数据

[{"name":"大郎","sex":"男","age":"25"},{"name":"西门庆","sex":"男","age":"47"}]

2)取出第一个json对象

hive (gmall)>

select get_json_object('[{"name":"大郎","sex":"男","age":"25"},{"name":"西门庆","sex":"男","age":"47"}]','$[0]');

结果是:{"name":"大郎","sex":"男","age":"25"}

3)取出第一个json的age字段的值

hive (gmall)>

SELECT get_json_object('[{"name":"大郎","sex":"男","age":"25"},{"name":"西门庆","sex":"男","age":"47"}]',"$[0].age");

结果是:25

4.1.3 启动日志表

启动日志解析思路:启动日志表中每行数据对应一个启动记录,一个启动记录应该包含日志中的公共信息和启动信息。先将所有包含start字段的日志过滤出来,然后使用get_json_object函数解析每个字段。

1)建表语句

hive (gmall)>

drop table if exists dwd_start_log;

CREATE EXTERNAL TABLE dwd_start_log(

    `area_code` string COMMENT '地区编码',

    `brand` string COMMENT '手机品牌',

    `channel` string COMMENT '渠道',

    `model` string COMMENT '手机型号',

    `mid_id` string COMMENT '设备id',

    `os` string COMMENT '操作系统',

    `user_id` string COMMENT '会员id',

    `version_code` string COMMENT 'app版本号',

    `entry` string COMMENT ' icon手机图标  notice 通知   install 安装后启动',

    `loading_time` bigint COMMENT '启动加载时间',

    `open_ad_id` string COMMENT '广告页ID ',

    `open_ad_ms` bigint COMMENT '广告总共播放时间',

    `open_ad_skip_ms` bigint COMMENT '用户跳过广告时点',

    `ts` bigint COMMENT '时间'

) COMMENT '启动日志表'

PARTITIONED BY (dt string) -- 按照时间创建分区

stored as parquet -- 采用parquet列式存储

LOCATION '/warehouse/gmall/dwd/dwd_start_log' -- 指定在HDFS上存储位置

TBLPROPERTIES('parquet.compression'='lzo') -- 采用LZO压缩

;

说明:数据采用parquet存储方式,是可以支持切片的,不需要再对数据创建索引。如果单纯的text方式存储数据,需要采用支持切片的,lzop压缩方式并创建索引。

2)数据导入

hive (gmall)>

SET hive.input.format=org.apache.hadoop.hive.ql.io.HiveInputFormat;

insert overwrite table dwd_start_log partition(dt='2020-06-14')

select

    get_json_object(line,'$.common.ar'),

    get_json_object(line,'$.common.ba'),

    get_json_object(line,'$.common.ch'),

    get_json_object(line,'$.common.md'),

    get_json_object(line,'$.common.mid'),

    get_json_object(line,'$.common.os'),

    get_json_object(line,'$.common.uid'),

    get_json_object(line,'$.common.vc'),

    get_json_object(line,'$.start.entry'),

    get_json_object(line,'$.start.loading_time'),

    get_json_object(line,'$.start.open_ad_id'),

    get_json_object(line,'$.start.open_ad_ms'),

    get_json_object(line,'$.start.open_ad_skip_ms'),

    get_json_object(line,'$.ts')

from ods_log

where dt='2020-06-14'

and get_json_object(line,'$.start') is not null;

3)查看数据

hive (gmall)>

select * from dwd_start_log where dt='2020-06-14' limit 2;

4)Hive读取索引文件问题

(1)两种方式,分别查询数据有多少行

hive (gmall)> select * from ods_log;

Time taken: 0.706 seconds, Fetched: 2955 row(s)

hive (gmall)> select count(*) from ods_log;

2959

(2)两次查询结果不一致。

原因是select * from ods_log不执行MR操作,默认采用的是ods_log建表语句中指定的DeprecatedLzoTextInputFormat,能够识别lzo.index为索引文件。

select count(*) from ods_log执行MR操作,默认采用的是CombineHiveInputFormat,不能识别lzo.index为索引文件,将索引文件当做普通文件处理。更严重的是,这会导致LZO文件无法切片。

hive (gmall)> set hive.input.format;

hive.input.format=org.apache.hadoop.hive.ql.io.CombineHiveInputFormat

解决办法:修改CombineHiveInputFormat为HiveInputFormat

(3)再次测试

hive (gmall)>

SET hive.input.format=org.apache.hadoop.hive.ql.io.HiveInputFormat;

hive (gmall)> select * from ods_log;

Time taken: 0.706 seconds, Fetched: 2955 row(s)

hive (gmall)> select count(*) from ods_log;

2955

4.1.4 页面日志表

页面日志解析思路:页面日志表中每行数据对应一个页面访问记录,一个页面访问记录应该包含日志中的公共信息和页面信息。先将所有包含page字段的日志过滤出来,然后使用get_json_object函数解析每个字段。

1)建表语句

hive (gmall)>

drop table if exists dwd_page_log;

CREATE EXTERNAL TABLE dwd_page_log(

    `area_code` string COMMENT '地区编码',

    `brand` string COMMENT '手机品牌',

    `channel` string COMMENT '渠道',

    `model` string COMMENT '手机型号',

    `mid_id` string COMMENT '设备id',

    `os` string COMMENT '操作系统',

    `user_id` string COMMENT '会员id',

    `version_code` string COMMENT 'app版本号',

    `during_time` bigint COMMENT '持续时间毫秒',

    `page_item` string COMMENT '目标id ',

    `page_item_type` string COMMENT '目标类型',

    `last_page_id` string COMMENT '上页类型',

    `page_id` string COMMENT '页面ID ',

    `source_type` string COMMENT '来源类型',

    `ts` bigint

) COMMENT '页面日志表'

PARTITIONED BY (dt string)

stored as parquet

LOCATION '/warehouse/gmall/dwd/dwd_page_log'

TBLPROPERTIES('parquet.compression'='lzo');

2)数据导入

hive (gmall)>

SET hive.input.format=org.apache.hadoop.hive.ql.io.HiveInputFormat;

insert overwrite table dwd_page_log partition(dt='2020-06-14')

select

    get_json_object(line,'$.common.ar'),

    get_json_object(line,'$.common.ba'),

    get_json_object(line,'$.common.ch'),

    get_json_object(line,'$.common.md'),

    get_json_object(line,'$.common.mid'),

    get_json_object(line,'$.common.os'),

    get_json_object(line,'$.common.uid'),

    get_json_object(line,'$.common.vc'),

    get_json_object(line,'$.page.during_time'),

    get_json_object(line,'$.page.item'),

    get_json_object(line,'$.page.item_type'),

    get_json_object(line,'$.page.last_page_id'),

    get_json_object(line,'$.page.page_id'),

    get_json_object(line,'$.page.sourceType'),

    get_json_object(line,'$.ts')

from ods_log

where dt='2020-06-14'

and get_json_object(line,'$.page') is not null;

3)查看数据

hive (gmall)>

select * from dwd_page_log where dt='2020-06-14' limit 2;

4.1.5 动作日志表

动作日志解析思路:动作日志表中每行数据对应用户的一个动作记录,一个动作记录应当包含公共信息、页面信息以及动作信息。先将包含action字段的日志过滤出来,然后通过UDTF函数,将action数组“炸开”(类似于explode函数的效果),然后使用get_json_object函数解析每个字段。

1)建表语句

hive (gmall)>

drop table if exists dwd_action_log;

CREATE EXTERNAL TABLE dwd_action_log(

    `area_code` string COMMENT '地区编码',

    `brand` string COMMENT '手机品牌',

    `channel` string COMMENT '渠道',

    `model` string COMMENT '手机型号',

    `mid_id` string COMMENT '设备id',

    `os` string COMMENT '操作系统',

    `user_id` string COMMENT '会员id',

    `version_code` string COMMENT 'app版本号',

    `during_time` bigint COMMENT '持续时间毫秒',

    `page_item` string COMMENT '目标id ',

    `page_item_type` string COMMENT '目标类型',

    `last_page_id` string COMMENT '上页类型',

    `page_id` string COMMENT '页面id ',

    `source_type` string COMMENT '来源类型',

    `action_id` string COMMENT '动作id',

    `item` string COMMENT '目标id ',

    `item_type` string COMMENT '目标类型',

    `ts` bigint COMMENT '时间'

) COMMENT '动作日志表'

PARTITIONED BY (dt string)

stored as parquet

LOCATION '/warehouse/gmall/dwd/dwd_action_log'

TBLPROPERTIES('parquet.compression'='lzo');

2)创建UDTF函数——设计思路

3)创建UDTF函数——编写代码

(1)创建一个maven工程:hivefunction

(2)创建包名:com.atguigu.hive.udtf

(3)引入如下依赖

                org.apache.hive        hive-exec        3.1.2    

(4)编码

package com.atguigu.hive.udtf;

import org.apache.hadoop.hive.ql.exec.UDFArgumentException;

import org.apache.hadoop.hive.ql.metadata.HiveException;

import org.apache.hadoop.hive.ql.udf.generic.GenericUDTF;

import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspector;

import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspectorFactory;

import org.apache.hadoop.hive.serde2.objectinspector.StructObjectInspector;

import org.apache.hadoop.hive.serde2.objectinspector.primitive.PrimitiveObjectInspectorFactory;

import org.json.JSONArray;

import java.util.ArrayList;

import java.util.List;

public class ExplodeJSONArray extends GenericUDTF {

    @Override

    public StructObjectInspector initialize(StructObjectInspector argOIs) throws UDFArgumentException {

        // 1 参数合法性检查

        if (argOIs.getAllStructFieldRefs().size() != 1){

            throw new UDFArgumentException("ExplodeJSONArray 只需要一个参数");

        }

        // 2 第一个参数必须为string

        if(!"string".equals(argOIs.getAllStructFieldRefs().get(0).getFieldObjectInspector().getTypeName())){

            throw new UDFArgumentException("json_array_to_struct_array的第1个参数应为string类型");

        }

        // 3 定义返回值名称和类型

        List fieldNames = new ArrayList();

        List fieldOIs = new ArrayList();

        fieldNames.add("items");

        fieldOIs.add(PrimitiveObjectInspectorFactory.javaStringObjectInspector);

        return ObjectInspectorFactory.getStandardStructObjectInspector(fieldNames, fieldOIs);

    }

    public void process(Object[] objects) throws HiveException {

        // 1 获取传入的数据

        String jsonArray = objects[0].toString();

        // 2 将string转换为json数组

        JSONArray actions = new JSONArray(jsonArray);

        

        // 3 循环一次,取出数组中的一个json,并写出

        for (int i = 0; i < actions.length(); i++) {

            String[] result = new String[1];

            result[0] = actions.getString(i);

            forward(result);

        }

    }

    public void close() throws HiveException {

    }

}

4)创建函数

(1)打包

(2)将hivefunction-1.0-SNAPSHOT.jar上传到hadoop102的/opt/module,然后再将该jar包上传到HDFS的/user/hive/jars路径下

[atguigu@hadoop102 module]$ hadoop fs -mkdir -p /user/hive/jars

[atguigu@hadoop102 module]$ hadoop fs -put hivefunction-1.0-SNAPSHOT.jar /user/hive/jars

(3)创建永久函数与开发好的java class关联

hive (gmall)>

create function explode_json_array as 'com.atguigu.hive.udtf.ExplodeJSONArray' using jar 'hdfs://hadoop102:8020/user/hive/jars/hivefunction-1.0-SNAPSHOT.jar';

(4)注意:如果修改了自定义函数重新生成jar包怎么处理?只需要替换HDFS路径上的旧jar包,然后重启Hive客户端即可。

5)数据导入

hive (gmall)>

SET hive.input.format=org.apache.hadoop.hive.ql.io.HiveInputFormat;

insert overwrite table dwd_action_log partition(dt='2020-06-14')

select

    get_json_object(line,'$.common.ar'),

    get_json_object(line,'$.common.ba'),

    get_json_object(line,'$.common.ch'),

    get_json_object(line,'$.common.md'),

    get_json_object(line,'$.common.mid'),

    get_json_object(line,'$.common.os'),

    get_json_object(line,'$.common.uid'),

    get_json_object(line,'$.common.vc'),

    get_json_object(line,'$.page.during_time'),

    get_json_object(line,'$.page.item'),

    get_json_object(line,'$.page.item_type'),

    get_json_object(line,'$.page.last_page_id'),

    get_json_object(line,'$.page.page_id'),

    get_json_object(line,'$.page.sourceType'),

    get_json_object(action,'$.action_id'),

    get_json_object(action,'$.item'),

    get_json_object(action,'$.item_type'),

    get_json_object(action,'$.ts')

from ods_log lateral view explode_json_array(get_json_object(line,'$.actions')) tmp as action

where dt='2020-06-14'

and get_json_object(line,'$.actions') is not null;

3)查看数据

hive (gmall)>

select * from dwd_action_log where dt='2020-06-14' limit 2;

4.1.6 曝光日志表

曝光日志解析思路:曝光日志表中每行数据对应一个曝光记录,一个曝光记录应当包含公共信息、页面信息以及曝光信息。先将包含display字段的日志过滤出来,然后通过UDTF函数,将display数组“炸开”(类似于explode函数的效果),然后使用get_json_object函数解析每个字段。

1)建表语句

hive (gmall)>

drop table if exists dwd_display_log;

CREATE EXTERNAL TABLE dwd_display_log(

    `area_code` string COMMENT '地区编码',

    `brand` string COMMENT '手机品牌',

    `channel` string COMMENT '渠道',

    `model` string COMMENT '手机型号',

    `mid_id` string COMMENT '设备id',

    `os` string COMMENT '操作系统',

    `user_id` string COMMENT '会员id',

    `version_code` string COMMENT 'app版本号',

    `during_time` bigint COMMENT 'app版本号',

    `page_item` string COMMENT '目标id ',

    `page_item_type` string COMMENT '目标类型',

    `last_page_id` string COMMENT '上页类型',

    `page_id` string COMMENT '页面ID ',

    `source_type` string COMMENT '来源类型',

    `ts` bigint COMMENT 'app版本号',

    `display_type` string COMMENT '曝光类型',

    `item` string COMMENT '曝光对象id ',

    `item_type` string COMMENT 'app版本号',

    `order` bigint COMMENT '出现顺序'

) COMMENT '曝光日志表'

PARTITIONED BY (dt string)

stored as parquet

LOCATION '/warehouse/gmall/dwd/dwd_display_log'

TBLPROPERTIES('parquet.compression'='lzo');

2)数据导入

hive (gmall)>

SET hive.input.format=org.apache.hadoop.hive.ql.io.HiveInputFormat;

insert overwrite table dwd_display_log partition(dt='2020-06-14')

select

    get_json_object(line,'$.common.ar'),

    get_json_object(line,'$.common.ba'),

    get_json_object(line,'$.common.ch'),

    get_json_object(line,'$.common.md'),

    get_json_object(line,'$.common.mid'),

    get_json_object(line,'$.common.os'),

    get_json_object(line,'$.common.uid'),

    get_json_object(line,'$.common.vc'),

    get_json_object(line,'$.page.during_time'),

    get_json_object(line,'$.page.item'),

    get_json_object(line,'$.page.item_type'),

    get_json_object(line,'$.page.last_page_id'),

    get_json_object(line,'$.page.page_id'),

    get_json_object(line,'$.page.sourceType'),

    get_json_object(line,'$.ts'),

    get_json_object(display,'$.displayType'),

    get_json_object(display,'$.item'),

    get_json_object(display,

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值