电商数仓项目----笔记六(数仓ODS层)
ODS层的设计要点如下:
(1)ODS层的表结构设计依托于从业务系统同步过来的数据结构。
(2)ODS层要保存全部历史数据,故其压缩格式应选择压缩比较高的,此处选择gzip。
(3)ODS层表名的命名规范为:ods_表名_单分区增量全量标识(inc/full)。
同样的,需要将用户行为数据表和业务数据表放到ODS层。
日志表
DROP TABLE IF EXISTS ods_log_inc;
CREATE EXTERNAL TABLE ods_log_inc
(`common` STRUCT<ar :STRING,ba :STRING,ch :STRING,is_new :STRING,md :STRING,mid :STRING,os :STRING,uid :STRING,vc:STRING> COMMENT '公共信息',`page` STRUCT<during_time :STRING,item :STRING,item_type :STRING,last_page_id :STRING,page_id:STRING,source_type :STRING> COMMENT '页面信息',`actions` ARRAY<STRUCT<action_id:STRING,item:STRING,item_type:STRING,ts:BIGINT>> COMMENT '动作信息',`displays` ARRAY<STRUCT<display_type :STRING,item :STRING,item_type :STRING,`order` :STRING,pos_id:STRING>> COMMENT '曝光信息',`start` STRUCT<entry :STRING,loading_time :BIGINT,open_ad_id :BIGINT,open_ad_ms :BIGINT,open_ad_skip_ms:BIGINT> COMMENT '启动信息',`err` STRUCT<error_code:BIGINT,msg:STRING> COMMENT '错误信息',`ts` BIGINT COMMENT '时间戳'
) COMMENT '活动信息表'PARTITIONED BY (`dt` STRING)ROW FORMAT SERDE 'org.apache.hadoop.hive.serde2.JsonSerDe'LOCATION '/warehouse/gmall/ods/ods_log_inc/';
创建一个外部表(防止误操作):
common、page、actions、displays、start、err、ts是表的列名;STRUCT是一种复合数据类型,用于表示多个字段的组合。例如,common列使用STRUCT类型,其中包含了多个字段;ARRAY是一种用于表示数组的数据类型。例如,actions和displays列使用ARRAY类型,分别包含了多个结构化的元素。PARTITIONED BY指定了表的分区列,这里使用dt列作为分区列。ROW FORMAT SERDE指定了数据的序列化和反序列化方式,这里使用JsonSerDe。LOCATION指定了外部表的存储位置
但是为什么创建这几个类? 因为当初咱们的日志格式是这样的:
页面日志:
{"common": { -- 环境信息"ar": "15", -- 省份ID"ba": "iPhone", -- 手机品牌"ch": "Appstore", -- 渠道"is_new": "1", -- 是否首日使用,首次使用的当日,该字段值为1,过了24:00,该字段置为0。"md": "iPhone 8", -- 手机型号"mid": "YXfhjAYH6As2z9Iq", -- 设备id"os": "iOS 13.2.9", -- 操作系统"sid": "3981c171-558a-437c-be10-da6d2553c517" -- 会话id"uid": "485", -- 会员id"vc": "v2.1.134" -- app版本号},"actions": [{ -- 动作(事件)"action_id": "favor_add", -- 动作id"item": "3", -- 目标id"item_type": "sku_id", -- 目标类型"ts": 1585744376605 -- 动作时间戳}],"displays": [{ -- 曝光"displayType": "query", -- 曝光类型"item": "3", -- 曝光对象id"item_type": "sku_id", -- 曝光对象类型"order": 1, -- 出现顺序"pos_id": 2 -- 曝光位置"pos_seq": 1 -- 曝光序列号(同一坑位多个对象的编号)},{"displayType": "promotion","item": "6","item_type": "sku_id","order": 2,"pos_id": 1"pos_seq": 1},{"displayType": "promotion","item": "9","item_type": "sku_id","order": 3,"pos_id": 3"pos_seq": 1},{"displayType": "recommend","item": "6","item_type": "sku_id","order": 4,"pos_id": 2"pos_seq": 1},{"displayType": "query ","item": "6","item_type": "sku_id","order": 5,"pos_id": 1"pos_seq": 1}],"page": { -- 页面信息"during_time": 7648, -- 持续时间毫秒"item": "3", -- 目标id"item_type": "sku_id", -- 目标类型"last_page_id": "login", -- 上页ID"page_id": "good_detail", -- 页面ID"from_pos_id":999, -- 来源坑位ID
"from_pos_seq":999, -- 来源坑位序列号
"refer_id":"2", -- 外部营销渠道ID"sourceType": "promotion" -- 来源类型}, "err": { --错误"error_code": "1234", --错误码"msg": "***********" --错误信息}, "ts": 1585744374423 --跳入时间戳
}
JSON格式,最外层JSON对象的属性作为表的字段。重点是属性是什么类型?
第一个common对象,用map或者struct都行,因为个数确定,用struct更好;
第二个action,有中括号,用数组array<struct>因为里面的数组元素类型不统一ARRAY<STRUCT<action_id:STRING,item:STRING,item_type:STRING,ts:BIGINT>> ;
同理,第三个action也大同小异....
启动日志:
{"common": {"ar": "370000","ba": "Honor","ch": "wandoujia","is_new": "1","md": "Honor 20s","mid": "eQF5boERMJFOujcp",
"os": "Android 11.0",
"sid":"a1068e7a-e25b-45dc-9b9a-5a55ae83fc81""uid": "76","vc": "v2.1.134"},"start": {
"entry": "icon", --icon手机图标 notice 通知 install 安装后启动"loading_time": 18803, --启动加载时间"open_ad_id": 7, --广告页ID"open_ad_ms": 3449, -- 广告总共播放时间"open_ad_skip_ms": 1989 -- 用户跳过广告时点},
"err":{ --错误
"error_code": "1234", --错误码"msg": "***********" --错误信息
},"ts": 1585744304000
}
这些这里面common,ts什么都是一样的,只有start不一样,start也是结构体。
数据装载
load data inpath '/origin_data/gmall/log/topic_log/2020-06-14' into table ods_log_inc partition(dt='2020-06-14');
每日数据装载脚本
(1)在hadoop102的/home/atguigu/bin目录下创建hdfs_to_ods_log.sh
#!/bin/bash# 定义变量方便修改
APP=gmall# 如果是输入的日期按照取输入日期;如果没输入日期取当前时间的前一天
if [ -n "$1" ] ;thendo_date=$1
elsedo_date=`date -d "-1 day" +%F`
fiecho ================== 日志日期为 $do_date ==================
sql="
load data inpath '/origin_data/$APP/log/topic_log/$do_date' into table ${APP}.ods_log_inc partition(dt='$do_date');
"
hive -e "$sql"
这个脚本我们需要传入一个日期参数。首先,定义APP一个外部变量gmall,if [ -n "$1" ]是判定传入的第一个参数是否为空,如果不为空,则将传入的参数赋给do_date,否则,do_date赋为今天的日期减一天;
随后拼接sql语句,load data数据装载语句,inpath 后面跟着的是数据存放的路径,into后面跟着我们新创建的ODS层的表名;
拼接完sql语句,hive -e "$sql"相当于执行sql语句。Bash脚本特有的执行sql语句的语法。
业务表
这里表较多,全量和增量各取一张表做个简单说明:
活动信息表(全量表):
DROP TABLE IF EXISTS ods_activity_info_full;
CREATE EXTERNAL TABLE ods_activity_info_full
(`id` STRING COMMENT '活动id',`activity_name` STRING COMMENT '活动名称',`activity_type` STRING COMMENT '活动类型',`activity_desc` STRING COMMENT '活动描述',`start_time` STRING COMMENT '开始时间',`end_time` STRING COMMENT '结束时间',`create_time` STRING COMMENT '创建时间'
) COMMENT '活动信息表'PARTITIONED BY (`dt` STRING)ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t'NULL DEFINED AS ''LOCATION '/warehouse/gmall/ods/ods_activity_info_full/';
我们当时全量表数据的同步是靠DataX同步过来的,传输过来的是Tsv格式,我们要尽量保持格式不变。
这是当时的活动信息表的样式:

这段代码用于创建一个外部表 ods_activity_info_full。该表包含了多个列,其中每个列都有对应的数据类型和注释。
id、activity_name、activity_type、activity_desc、start_time、end_time、create_time是表的列名。STRING是表示字符串类型的数据类型。COMMENT用于为列添加注释,描述列的含义。PARTITIONED BY指定了表的分区列,这里使用dt列作为分区列。ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t'指定了行格式,数据以制表符分隔。NULL DEFINED AS ''指定了空值的表示方式,这里将空值定义为空字符串。LOCATION指定了外部表的存储位置。
购物车表(增量表):
DROP TABLE IF EXISTS ods_cart_info_inc;
CREATE EXTERNAL TABLE ods_cart_info_inc
(`type` STRING COMMENT '变动类型',`ts` BIGINT COMMENT '变动时间',`data` STRUCT<id :STRING,user_id :STRING,sku_id :STRING,cart_price :DECIMAL(16, 2),sku_num :BIGINT,img_url :STRING,sku_name:STRING,is_checked :STRING,create_time :STRING,operate_time :STRING,is_ordered :STRING,order_time:STRING,source_type :STRING,source_id :STRING> COMMENT '数据',`old` MAP<STRING,STRING> COMMENT '旧值'
) COMMENT '购物车增量表'PARTITIONED BY (`dt` STRING)ROW FORMAT SERDE 'org.apache.hadoop.hive.serde2.JsonSerDe'LOCATION '/warehouse/gmall/ods/ods_cart_info_inc/';
我们当时全量表数据的同步是靠maxwell同步过来的,传输过来的是JSON格式。JSON:最外层JSON对象的属性作为表的字段。而且我们设计的表要考虑到下面三种不同的操作。但是里面的字段并不是全要的,比如database字段,对我们的统计分析没用,table也没用。Type有用,因为它可以帮我们区分三种不同的操作。xid和commit也用不上,因此我们分析比对只需要type,ts,date,old四个字段;
type:String,ts:timastamp,date:用结构体,old:map格式(不确定是几个)。

这是当时的购物车表的样式:
在hadoop102的/home/atguigu/bin目录下创建hdfs_to_ods_db.sh
编写如下内容:
#!/bin/bashAPP=gmallif [ -n "$2" ] ;thendo_date=$2
else do_date=`date -d '-1 day' +%F`
fiload_data(){sql=""for i in $*; do#判断路径是否存在hadoop fs -test -e /origin_data/$APP/db/${i:4}/$do_date#路径存在方可装载数据if [[ $? = 0 ]]; thensql=$sql"load data inpath '/origin_data/$APP/db/${i:4}/$do_date' OVERWRITE into table ${APP}.$i partition(dt='$do_date');"fidonehive -e "$sql"
}case $1 in"ods_activity_info_full")load_data "ods_activity_info_full";;"ods_activity_rule_full")load_data "ods_activity_rule_full";;"ods_base_category1_full")load_data "ods_base_category1_full";;"ods_base_category2_full")load_data "ods_base_category2_full";;"ods_base_category3_full")load_data "ods_base_category3_full";;"ods_base_dic_full")load_data "ods_base_dic_full";;"ods_base_province_full")load_data "ods_base_province_full";;"ods_base_region_full")load_data "ods_base_region_full";;"ods_base_trademark_full")load_data "ods_base_trademark_full";;"ods_cart_info_full")load_data "ods_cart_info_full";;"ods_coupon_info_full")load_data "ods_coupon_info_full";;"ods_sku_attr_value_full")load_data "ods_sku_attr_value_full";;"ods_sku_info_full")load_data "ods_sku_info_full";;"ods_sku_sale_attr_value_full")load_data "ods_sku_sale_attr_value_full";;"ods_spu_info_full")load_data "ods_spu_info_full";;"ods_cart_info_inc")load_data "ods_cart_info_inc";;"ods_comment_info_inc")load_data "ods_comment_info_inc";;"ods_coupon_use_inc")load_data "ods_coupon_use_inc";;"ods_favor_info_inc")load_data "ods_favor_info_inc";;"ods_order_detail_inc")load_data "ods_order_detail_inc";;"ods_order_detail_activity_inc")load_data "ods_order_detail_activity_inc";;"ods_order_detail_coupon_inc")load_data "ods_order_detail_coupon_inc";;"ods_order_info_inc")load_data "ods_order_info_inc";;"ods_order_refund_info_inc")load_data "ods_order_refund_info_inc";;"ods_order_status_log_inc")load_data "ods_order_status_log_inc";;"ods_payment_info_inc")load_data "ods_payment_info_inc";;"ods_refund_payment_inc")load_data "ods_refund_payment_inc";;"ods_user_info_inc")load_data "ods_user_info_inc";;"all")load_data "ods_activity_info_full" "ods_activity_rule_full" "ods_base_category1_full" "ods_base_category2_full" "ods_base_category3_full" "ods_base_dic_full" "ods_base_province_full" "ods_base_region_full" "ods_base_trademark_full" "ods_cart_info_full" "ods_coupon_info_full" "ods_sku_attr_value_full" "ods_sku_info_full" "ods_sku_sale_attr_value_full" "ods_spu_info_full" "ods_cart_info_inc" "ods_comment_info_inc" "ods_coupon_use_inc" "ods_favor_info_inc" "ods_order_detail_inc" "ods_order_detail_activity_inc" "ods_order_detail_coupon_inc" "ods_order_info_inc" "ods_order_refund_info_inc" "ods_order_status_log_inc" "ods_payment_info_inc" "ods_refund_payment_inc" "ods_user_info_inc";;
esac
此脚本首先定义一个外部变量APP=gmall,随后再判断此脚本的第二个参数是否为空,如果是输入的日期就传入输入日期,如果没输入日期取当前日期的前一天。
后面定义了一个load_data函数,sql赋予一个空字符串, for i in $*这行代码使用 for 循环遍历load_data函数的所有参数,其实就一个参数,也就是表名;
hadoop fs -test -e判断此路径是否存在,/origin_data/$APP/db/${i:4}/$do_date,${i:4}表示从传入的参数的第四个字符后开始读,比如这个"ods_activity_info_full",前面的ods跳过,后面的参数表示表名;
如果路径存在, sql=$sql"load data inpath '/origin_data/$APP/db/${i:4}/$do_date' OVERWRITE into table ${APP}.$i partition(dt='$do_date');"数据装载;
数据装载之后如下所示:

相关文章:
电商数仓项目----笔记六(数仓ODS层)
ODS层的设计要点如下: (1)ODS层的表结构设计依托于从业务系统同步过来的数据结构。 (2)ODS层要保存全部历史数据,故其压缩格式应选择压缩比较高的,此处选择gzip。 (3)…...
rtsp视频在使用unity三维融合播放后的修正
1 rtsp 接入 我们使用unity UE 等三维渲染引擎中使用c编写插件来接入rtsp 视频。同时做融合的时候,和背景的三维颜色要一致,这就要使用视频融合修正技术。包括亮度,对比度,饱和度的修正。在单纯颜色上的修正可以简单使用rgb->…...
【已解决】解决Springboot项目访问本地图片等静态资源无法访问的问题
今天在开发一个招聘系统的时候,有投递简历功能,有投递就会有随之而来的查看简历对吧,我投递过的简历,另存为一个文件夹,就是说本地磁盘(或者服务器)有一个专门存放投递过的简历的文件夹,用于存放PDF&#x…...
运维笔记之centos部署Go-FastDfs
安装Go-FastDfs 当前最新版本为1.4.5,但发布的最新版本为1.4.4 # 下载文件 wget --no-check-certificate https://github.com/sjqzhang/go-fastdfs/releases/download/v1.4.4/fileserver -O fileserver # 赋权限 chmod x fileserver # 运行 ./fileserver server服…...
C#基础——线程(线程池、线程锁、线程抢占、多线程)
线程 进程(Process)是由操作系统分配资源并执行的一个独立的程序实,属于Windows的概念,进程结束就表示程序关闭了。 线程(Thread)是程序中执行的最小单位。一个线程代表了一个独立的执行流,可…...
C# WPF上位机开发(QT vs WPF)
【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing 163.com】 最近经常收到朋友们的私信,他们对C# WPF开发很感兴趣,但是呢,正当准备学习的时候,又有人告诉他们应…...
2-高可用-负载均衡、反向代理
负载均衡、反向代理 upstream server即上游服务器,指Nginx负载均衡到的处理业务的服务器,也可以称之为real server,即真实处理业务的服务器。 对于负载均衡我们要关心的几个方面如下: 上游服务器配置:使用upstream server配置上…...
STM32 使用ARM仿真器设置
STM32单片机程序下载到单片机芯片中有两种方式,①编译生成HEX,使用程序烧录软件刷到单片机芯片里。②使用ARM仿真器下载程序。使用ARM仿真器的优势是,在工程编译没问题直接在Keil软件里就可以将程序下载到单片机里,并且程序可以在…...
【Java】spring
一、spring spring是一个很大的生态圈,里面有很多技术。 其中最基础的是spring framework,主要的技术 是springboot以及springcloud。 1、spring framework spring framework是spring生态圈中最基础的项目,是其他项目的基础。 1.1、核心…...
C语言中关于操作符的理解
本篇文章只会列出大家在生活中经常使用的操作符 算术操作符 在算数操作符中常用的有,,-,*,/,% ,我们重点讲一讲 / (除) 和 % (模) " / "运算 #include <stdio.h>int main() {int a5/2;fl…...
Flutter本地化(国际化)之App名称
文章目录 Android国际化IOS国际化 Flutter开发的App,如果名称想要跟随着系统的语言自动改变,则必须同时配置Android和IOS原生。 Android国际化 打开android\app\src\main\res\values 创建strings.xml 在values上右键,选择New>Values Res…...
Redis哨兵源码分析
在Redis server启动过程中,实现了实例化和初始化 1、哨兵实例化过程,采用redis sentinel指令实例化还是redis server下的参数实例化--sentinel。 // 检查服务器是否以 Sentinel 模式启动 server.sentinel_mode checkForSentinelMode(argc,argv);/* Re…...
安装Neo4j
jdk1.8对应的neo4j的版本是3.5 自行下载3.5版本的zip文件 地址 解压添加环境变量 变量名:NEO4J_HOME 变量值:D:\neo4j-community-3.5.0 (你自己的地址) PATH添加: %NEO4J_HOME%\bin (如果是挨着的注意前后英…...
华为鸿蒙开发适合哪些人学习?
随着鸿蒙系统的崛起,越来越多的人开始关注鸿蒙开发,并希望成为鸿蒙开发者。然而,鸿蒙开发并不适合所有人,那么哪些人最适合学习鸿蒙开发呢?本文将为您总结鸿蒙开发适合的人群。 一、具备编程基础的人 学习鸿蒙开发需要…...
深信服技术认证“SCSA-S”划重点:命令执行漏洞
为帮助大家更加系统化地学习网络安全知识,以及更高效地通过深信服安全服务认证工程师考核,深信服特别推出“SCSA-S认证备考秘笈”共十期内容,“考试重点”内容框架,帮助大家快速get重点知识~ 划重点来啦 *点击图片放大展示 深信服…...
Flink系列之:Savepoints
Flink系列之:Savepoints 一、Savepoints二、分配算子ID三、Savepoint 状态四、算子五、触发Savepoint六、Savepoint 格式七、触发 Savepoint八、使用 YARN 触发 Savepoint九、使用 Savepoint 停止作业十、从 Savepoint 恢复十一、跳过无法映射的状态恢复十二、Resto…...
使用宝塔面板部署前端项目到服务器
目录 文章目录 前言 一、第一步:创建文件夹 二、第二步:部署前端项目 三、第三步:打开防火墙 文章目录 前言第一步:创建文件夹第二步:部署前端项目第三步:打开防火墙总结 前言 在此之前,我…...
Enge问题解决教程
目录 解决问题的一般步骤: 针对"Enge问题"的具体建议: 以下是一些普遍适用的解决问题的方法: 以下是一些更深入的Enge浏览器问题和解决办法: 浏览器性能问题: 浏览器插件与网站冲突: 浏览…...
使用yarn安装electron时手动选择版本
访问1Password或者其他可以提供随机字符的网站,获取随机密码运行安装命令 操作要点,必须触发Couldnt find any versions for "electron" that matches "*"才算成功 将复制的随机密码粘贴到后面 例如:yarn add --dev elec…...
AIGC:阿里开源大模型通义千问部署与实战
1 引言 通义千问-7B(Qwen-7B)是阿里云研发的通义千问大模型系列的70亿参数规模的模型。Qwen-7B是基于Transformer的大语言模型, 在超大规模的预训练数据上进行训练得到。预训练数据类型多样,覆盖广泛,包括大量网络文本、专业书籍…...
7.4.分块查找
一.分块查找的算法思想: 1.实例: 以上述图片的顺序表为例, 该顺序表的数据元素从整体来看是乱序的,但如果把这些数据元素分成一块一块的小区间, 第一个区间[0,1]索引上的数据元素都是小于等于10的, 第二…...
简易版抽奖活动的设计技术方案
1.前言 本技术方案旨在设计一套完整且可靠的抽奖活动逻辑,确保抽奖活动能够公平、公正、公开地进行,同时满足高并发访问、数据安全存储与高效处理等需求,为用户提供流畅的抽奖体验,助力业务顺利开展。本方案将涵盖抽奖活动的整体架构设计、核心流程逻辑、关键功能实现以及…...
1688商品列表API与其他数据源的对接思路
将1688商品列表API与其他数据源对接时,需结合业务场景设计数据流转链路,重点关注数据格式兼容性、接口调用频率控制及数据一致性维护。以下是具体对接思路及关键技术点: 一、核心对接场景与目标 商品数据同步 场景:将1688商品信息…...
[ICLR 2022]How Much Can CLIP Benefit Vision-and-Language Tasks?
论文网址:pdf 英文是纯手打的!论文原文的summarizing and paraphrasing。可能会出现难以避免的拼写错误和语法错误,若有发现欢迎评论指正!文章偏向于笔记,谨慎食用 目录 1. 心得 2. 论文逐段精读 2.1. Abstract 2…...
cf2117E
原题链接:https://codeforces.com/contest/2117/problem/E 题目背景: 给定两个数组a,b,可以执行多次以下操作:选择 i (1 < i < n - 1),并设置 或,也可以在执行上述操作前执行一次删除任意 和 。求…...
JVM暂停(Stop-The-World,STW)的原因分类及对应排查方案
JVM暂停(Stop-The-World,STW)的完整原因分类及对应排查方案,结合JVM运行机制和常见故障场景整理而成: 一、GC相关暂停 1. 安全点(Safepoint)阻塞 现象:JVM暂停但无GC日志,日志显示No GCs detected。原因:JVM等待所有线程进入安全点(如…...
云原生玩法三问:构建自定义开发环境
云原生玩法三问:构建自定义开发环境 引言 临时运维一个古董项目,无文档,无环境,无交接人,俗称三无。 运行设备的环境老,本地环境版本高,ssh不过去。正好最近对 腾讯出品的云原生 cnb 感兴趣&…...
GruntJS-前端自动化任务运行器从入门到实战
Grunt 完全指南:从入门到实战 一、Grunt 是什么? Grunt是一个基于 Node.js 的前端自动化任务运行器,主要用于自动化执行项目开发中重复性高的任务,例如文件压缩、代码编译、语法检查、单元测试、文件合并等。通过配置简洁的任务…...
STM32HAL库USART源代码解析及应用
STM32HAL库USART源代码解析 前言STM32CubeIDE配置串口USART和UART的选择使用模式参数设置GPIO配置DMA配置中断配置硬件流控制使能生成代码解析和使用方法串口初始化__UART_HandleTypeDef结构体浅析HAL库代码实际使用方法使用轮询方式发送使用轮询方式接收使用中断方式发送使用中…...
文件上传漏洞防御全攻略
要全面防范文件上传漏洞,需构建多层防御体系,结合技术验证、存储隔离与权限控制: 🔒 一、基础防护层 前端校验(仅辅助) 通过JavaScript限制文件后缀名(白名单)和大小,提…...
