1.1数据仓库概念
什么是数据仓库?
数据仓库本身并不“生产”任何数据,同时自身也不需要“消费”任何的数据,数据来源于外部,并且开放给外部应用
目的?
构建面向分析的集成化数据环境,主要职责是做分析,对仓库里面的数据来做分析,数据分析可以支持我们做决策
数据分析特征:
(1)面向主题:数据分析有一定范围,需要选取一定的主题进行分析(比如:我们针对订单分析,那么可能跟我们的商品表关系不大,只需要围绕订单分析)
(2)继承性:集成各个其他方面关联的一些数据,(比如:我们分析订单购买人情况,就涉及到客户的基本信息;数据出现交叉,那么就将数据集成到一起,需要什么选取什么)
(3)非易失性:数据分析,主要分析过去已经发生的数据,都是即成的事实
(4)时变性:随着时间的发展,数的形态也在发生变化,数据的分析的手段也要变化
数据仓库与数据的区别:
数据库:OLTP,联机事务处理,数据库主要的功能就是用来做事务处理,主要负责频繁的增删改查
数据仓库:OLAP,连接分析处理,不需要做事务的保证,主要职责就是做数据的分析,面向分析
首先要明白,数据仓库的出现,并不是要取代数据库。
- 数据库是面向事务的设计,数据仓库是面向主题设计的。
- 数据库一般存储业务数据,数据仓库存储的一般是历史数据。
- 数据库设计是尽量避免冗余,一般针对某一业务应用进行设计,比如一张简单的User表,记录用户名、密码等简单数据即可,符合业务应用,但是不符合分析。数据仓库在设计是有意引入冗余,依照分析需求,分析维度、分析指标进行设计。(所以数据仓库数据出现冗余无所谓,虽然会占用空间,但是数据仓库就是为了存储数据,冗余一些字段无所谓)
- 数据库是为捕获数据而设计,数据仓库是为分析数据而设计。
1.2数据仓库分层
数据仓库标准上可以分为四层:ODS(临时存储层)、PDW(数据仓库层)、MID(数据集市层)、APP(应用层)
ODS层:
为临时存储层,是接口数据的临时存储区域,为后一步的数据处理做准备。一般来说ODS层的数据和源系统的数据是同构的,主要目的是简化后续数据加工处理的工作。从数据粒度上来说ODS层的数据粒度是最细的。ODS层的表通常包括两类,一个用于存储当前需要加载的数据,一个用于存储处理完后的历史数据。历史数据一般保存3-6个月后需要清除,以节省空间。但不同的项目要区别对待,如果源系统的数据量不大,可以保留更长的时间,甚至全量保存;
PDW层:
为数据仓库层,PDW层的数据应该是一致的、准确的、干净的数据,即对源系统数据进行了清洗(去除了杂质)后的数据。这一层的数据一般是遵循数据库第三范式的,其数据粒度通常和ODS的粒度相同。在PDW层会保存BI系统中所有的历史数据,例如保存10年的数据
MID层:
为数据集市层,这层数据是面向主题来组织数据的,通常是星形或雪花结构的数据。从数据粒度来说,这层的数据是轻度汇总级的数据,已经不存在明细数据了。从数据的时间跨度来说,通常是PDW层的一部分,主要的目的是为了满足用户分析的需求,而从分析的角度来说,用户通常只需要分析近几年(如近三年的数据)的即可。从数据的广度来说,仍然覆盖了所有业务数据。
APP层:
为应用层,这层数据是完全为了满足具体的分析需求而构建的数据,也是星形或雪花结构的数据。从数据粒度来说是高度汇总的数据。从数据的广度来说,则并不一定会覆盖所有业务数据,而是MID层数据的一个真子集,从某种意义上来说是MID层数据的一个重复。从极端情况来说,可以为每一张报表在APP层构建一个模型来支持,达到以空间换时间的目的数据仓库的标准分层只是一个建议性质的标准,实际实施时需要根据实际情况确定数据仓库的分层,不同类型的数据也可能采取不同的分层方法。
1.3数据仓库的开发
1.3.1数据开发步骤
- 确定统计那些指标(根据业务需求)
- 需求确定 比如:pv uv topn
- 建模确定表结构create table t1 ( pv int , uv int ,topn string)
- 实现方案确定(将确定的指标封装进去即可,之后通过大量的逻辑运算得到t表即可)
- 数据开发过程
- 表落地
- 写sql语句实现业务逻辑
- 部署代码
- 数据测试
- 试运行和上线
1.3.2案例步骤:
用户画像开发--客户基本属性表
--用户画像-客户基本属性模型表 create database if not exists gdm; create table if not exists gdm.itcast_gdm_user_basic( user_id string ,--用户ID user_name string ,--用户登陆名 user_sex string ,--用户性别 user_birthday string ,--用户生日 user_age bigint ,--用户年龄 hex_phone string ,--手机号 fore_phone string ,--手机前3位 dw_date timestamp ) partitioned by (dt string); #*************************** --客户基本属性模型表BDM层 --一般从mysql直接抽取过来,不做任何处理 create database if not exists bdm; create external table if not exists bdm.itcast_bdm_user( user_id string ,--用户ID user_name string ,--用户登陆名 user_sex string ,--用户性别 user_birthday string ,--用户生日 hex_phone string ,--手机号 ) partitioned by (dt string) row format delimited fields terminated by ','; alter table itcast_bdm_user add partition (dt='2017-01-01') location '/business/itcast_bdm_user/2017-01-01'; --客户基本属性表FDM层 --我们通过对BDM层预处理来构建FDM层,比如年龄:我们在BDM只有个生日,我们可以通过生日得到年龄字段或是对手机号进行切割得到前三位 create database if not exists fdm; create table if not exists fdm.itcast_fdm_user_wide( user_id string ,--用户ID user_name string ,--用户登陆名 user_sex string ,--用户性别 user_birthday string ,--用户生日 user_age bigint ,--用户年龄 hex_phone string ,--手机号 fore_phone string ,--手机前3位 dw_date timestamp ) partitioned by (dt string); --加载数据 insert overwrite table fdm.itcast_fdm_user_wide partition(dt='2017-01-01') select t.user_id, t.user_name, t.user_sex, t.user_birthday, (year(current_date)-(year(birthday))) as age, t.hex_phone, substring(t.hex_phone,3) as fore_phone, from_unixtime(unix_timestamp()) dw_date from bdm.itcast_bdm_user t where dt='2017-01-01'; --用户画像-客户基本属性模型表GDM层 create database if not exists gdm; create table if not exists gdm.itcast_gdm_user_basic( user_id string ,--用户ID user_name string ,--用户登陆名 user_sex string ,--用户性别 user_birthday string ,--用户生日 user_age bigint ,--用户年龄 hex_phone string ,--手机号 fore_phone string ,--手机前3位 dw_date timestamp ) partitioned by (dt string); --加载数据 insert overwrite table gdm.itcast_gdm_user_basic partition(dt='2017-01-01') select t.user_id, t.user_name, t.user_sex, t.user_birthday, t.user_age, t.hex_phone, t.fore_phone, from_unixtime(unix_timestamp()) dw_date from (select * from fdm.itcast_fdm_user_wide where dt='2017-01-01') t;
演示模型表开发脚本: ###################### #名称:客户基本属性模型表 # itcast_gdm_user_basic.sh ###################### #!/bin/sh #获取昨天时间 yesterday=`date -d '-1 day' "+%Y-%m-%d"` #指定跑哪一天数据 if [ $1 ];then yesterday=$1 fi SPARK_SUBMIT_INFO="/export/servers/spark/bin/spark-sql --master spark://node1:7077 --executor-memory 1g --total-executor-cores 2 --conf spark.sql.warehouse.dir=hdfs://node1:9000/user/hive/warehouse" SOURCE_DATA="/root/source_data" SQL_BDM="create database if not exists bdm; create external table if not exists bdm.itcast_bdm_user( user_id string ,--用户ID user_name string ,--用户登陆名 user_sex string ,--用户性别 user_birthday string ,--用户生日 hex_phone string ,--手机号 ) partitioned by (dt string) row format delimited fields terminated by ',' location '/business/bdm/itcast_bdm_user' ; alter table bdm.itcast_bdm_user add partition (dt='$yesterday');" SQL_FDM="create database if not exists fdm; create table if not exists fdm.itcast_fdm_user_wide( user_id string ,--用户ID user_name string ,--用户登陆名 user_sex string ,--用户性别 user_birthday string ,--用户生日 user_age bigint ,--用户年龄 hex_phone string ,--手机号 fore_phone string ,--手机前3位 dw_date timestamp ) partitioned by (dt string);" ##加载数据 LOAD_FDM=" insert overwrite table fdm.itcast_fdm_user_wide partition(dt='$yesterday') select t.user_id, t.user_name, t.user_sex, t.user_birthday, (year(current_date)-(year(birthday))) as age, t.hex_phone, substring(t.hex_phone,3) as fore_phone, from_unixtime(unix_timestamp()) dw_date from bdm.itcast_bdm_user t where dt='$yesterday';" SQL_GDM="create database if not exists gdm; create table if not exists gdm.itcast_gdm_user_basic( user_id string ,--用户ID user_name string ,--用户登陆名 user_sex string ,--用户性别 user_birthday string ,--用户生日 user_age bigint ,--用户年龄 hex_phone string ,--手机号 fore_phone string ,--手机前3位 dw_date timestamp ) partitioned by (dt string);" ##加载数据到GDM LOAD_GDM="insert overwrite table gdm.itcast_gdm_user_basic partition(dt='$yesterday') select t.user_id, t.user_name, t.user_sex, t.user_birthday, t.user_age, t.hex_phone, t.fore_phone, from_unixtime(unix_timestamp()) dw_date from (select * from fdm.itcast_fdm_user_wide where dt='$yesterday') t;" ##创建BDM层表 echo "${SQL_BDM}" $SPARK_SUBMIT_INFO -e "${SQL_BDM}" ##添加数据到BDM hdfs dfs -put $SOURCE_DATA/itcast_bdm_user.txt /business/bdm/itcast_bdm_user/"dt=$yesterday" ##创建FDM层表 echo "${SQL_FDM}" $SPARK_SUBMIT_INFO -e "${SQL_FDM}" ##导入数据到FDM echo "${LOAD_FDM}" $SPARK_SUBMIT_INFO -e "${LOAD_FDM}" ##创建GDM层表 echo "${SQL_GDM}" $SPARK_SUBMIT_INFO -e "${SQL_GDM}" ##导入GDM数据 echo "${LOAD_GDM}" $SPARK_SUBMIT_INFO -e "${LOAD_GDM}"