SCD缓慢变化维,比如一个用户维表,用户属性会变化,但是不会变化很剧烈,可能一年只会变化一两次,也不会所有用户的属性都会有变化,只有少量的数据发生变化,所以叫缓慢变化维。这种问题就是由于维度的变化所造成的。

解决方式:

  • 是否保留历史数据
  • 保留多久历史数据
  • 历史状态如何与事实表关联

SCD1 保留最新状态

注册日期 用户编号 手机号码
2019-01-01 0001 111111
2019-01-01 0002 222222
2019-01-01 0003 333333
2019-01-01 0004 444444
注册日期 用户编号 手机号码 备注
2019-01-01 0001 111111 111111
2019-01-01 0002 233333 (由22222变成23333)
2019-01-01 0003 333333  
2019-01-01 0004 433333 (由44444变成43333)
2019-01-02 0005 555555 (2019-01-02新增)

缺点:没有任何历史状态,历史发生的事情无法追溯,企业中不关心历史状态的数据,可以使用SCD1

SCD2 保留所有历史状态

注册日期 用户编号 手机号码
2019-01-01 0001 111111
2019-01-01 0002 222222
2019-01-01 0003 333333
2019-01-01 0004 444444
注册日期 用户编号 手机号码 t_start_date t_end_date
2019-01-01 0001 111111 2019-01-01 9999-12-31
2019-01-01 0002 233333 2019-01-01 9999-12-31
2019-01-01 0003 333333 2019-01-01 2019-01-01
2019-01-01 0003 344444 2019-01-02 9999-12-31
2019-01-01 0004 433333 2019-01-01 9999-12-31
2019-01-02 0005 555555 2019-01-01 9999-12-31

出现问题:同一个用户编号的数据出现多次,与事实表关联时,每个订单就会被关联出多条记录,肯定会出错。

解决办法:加上时间限制条件,订单生成时间在用户表有效期内数据才做关联。

SCD3  只保留了最后一次变化记录,综合了SCD1和SCD2

注册日期 用户编号 手机号码
2019-01-01 0001 111111
2019-01-01 0002 222222
2019-01-01 0003 333333
2019-01-01 0004 444444
注册日期 用户编号 手机号码 先前手机号码
2019-01-01 0001 133333 111111
2019-01-01 0002 233333 222222
2019-01-01 0003 333333  
2019-01-01 0004 444444  

HIVE实现SCD2

如果关注历史状态基本上用SCD2,如果不关注历史状态就用SCD1,SCD3用得比较少。

SCD2

1,代理键:HIVE中如何实现自增ID

2,如何设计有效期时间

代理键的作用:给下表加一个代理ID,对于一个用户来说,如果状态发生3次变化,在这个表里有3条记录,分别有一个不同的ID。用代理键ID解决有效期问题。

除了在维表中有代理ID,在事实表里也会把用户ID用代理ID替换。关联的时候就不会出现数据重复的问题,就不需要根据有效期无能去做统计了。

注册日期 用户编号 手机号码 t_start_date t_end_date
2019-01-01 0001 111111 2019-01-01 9999-12-31
2019-01-01 0002 233333 2019-01-01 9999-12-31
2019-01-01 0003 333333 2019-01-01 2019-01-01
2019-01-01 0003 344444 2019-01-02 9999-12-31
2019-01-01 0004 433333 2019-01-01 9999-12-31
2019-01-02 0005 555555 2019-01-01 9999-12-31

有效期开始时间设计成一个很小的时间,在业务开始之前的时间;

有效期终止时间设计成一个非常大的值,一个固定的值。

Hive中的自增ID

  • 利用row_number()
  • org.apache.hadoop.hive.contrib.udf.UDFRowSequence

利用row_number()

select row_number() over(order by empno), empno from emp;

利用org.apache.hadoop.hive.contrib.udf.UDFRowSequence

hdfs dfs -mkdir /user/hive/lib
hdfs dfs -put ${HIVE_HOME}/lib/hive-contrib-1.2.1.jar /user/hive/lib/

添加Hive函数

hive>create temporary function row_sequence as 'org.apache.hadoop.hive.contrib.udf.UDFSequence';
hive>select row_sequence(), empno from emp limit 10;

添加Hive永久函数

hive>create function row_sequence as 'org.apache.hadoop.hive.contrib.udf.UDFSequence' using jar 'hdfs:///user/hive/lib/hive-contrib-1.2.1.jar';

准备数据

1,张三,US,CA
2,李四,US,CB
3,王五,CA,BB
4,赵六,CA,BC
5,老刘,AA,AA

创建用户表

-- 可以建成分区表 ,使用文本文件存储格式,因为后面用load加载数据,parquet格式的不支持

drop table if exists ods_user_update;

create table ods_user_update (
user_id INT,
name STRING,
cty STRING,
st STRING
)
COMMENT '每日用户更新表'
ROW FORMAT DELIMITED FIELDS TERMINATED BY ',' LINES TERMINATED BY '\n'

建立用户维度表

-- 建立维度表 ,数据不能从外部文件加载,只能从一个hive表加载
create database test; use test; drop table if exists dim_user; CREATE TABLE dim_user (
surr_user_id bigint,
user_id INT,
name STRING,
cty STRING,
st STRING,
version INT,
ver_start_date DATE,
ver_end_date DATE)
COMMENT '每日维度表'
ROW FORMAT DELIMITED FIELDS TERMINATED BY ',' LINES TERMINATED BY '\n'
STORED AS parquet
;

加载初始数据

-- parquet 的表不支持load 数据加载方式

load data local inpath '/root/test/user.txt' overwrite into table ods_user_update;

用户维度表加载初始数据

INSERT  INTO dim_user
SELECT
ROW_NUMBER() OVER (ORDER BY ods_user_update.user_id) + t2.sk_max,
ods_user_update.*,
1,
CAST('1900-01-01' AS DATE),
CAST('2200-01-01' AS DATE)
from ods_user_update CROSS JOIN (SELECT COALESCE(MAX(surr_user_id),0) sk_max FROM dim_user) t2;

更新维度表的数据

SET hivevar:pre_date = DATE_ADD(CURRENT_DATE(),-1);
SET hivevar:max_date = CAST('2200-01-01' AS DATE); load data local inpath '/root/test/user_update.txt' overwrite into table ods_user_update; INSERT OVERWRITE TABLE dim_user
SELECT * FROM
(
SELECT A.surr_user_id,
A.user_id,A.name,a.cty,a.st,a.version,
A.ver_start_date,
CASE
WHEN B.user_id IS NOT NULL and A.ver_end_date = ${hivevar:max_date} then ${hivevar:pre_date}
ELSE cast(A.ver_end_date as string)
END AS ver_end_date
FROM dim_user AS A LEFT JOIN ods_user_update AS B
ON A.user_id = B.user_id
UNION
select ROW_NUMBER() OVER (ORDER BY C.user_id) + D.sk_max,
c.user_id,c.name,c.cty,C.st,
0,
${hivevar:pre_date} AS ver_start_date,
${hivevar:max_date} AS ver_end_date
from ods_user_update as C cross join (SELECT COALESCE(MAX(surr_user_id),0) sk_max FROM dim_user) D
) AS T
;

HIVE- SCD缓慢变化的更多相关文章

  1. ODI 11g & 12c中缓慢变化维(SCD)的处理机制

    缓慢变化维(Slowly changing Dimensions)指的是维表中的维度字段值会随着时间或业务调整,而在后续的分析中,历史数据仍然要使用旧的维度值,新的数据会使用当前维度值.在数据仓库建设 ...

  2. 缓慢变化维 (Slowly changing dimension)

          维度建模的数据仓库中,有一个概念叫Slowly Changing Dimensions,中文一般翻译成"缓慢变化维",经常被简写为SCD.缓慢变化维的提出是因为在现实世 ...

  3. 缓慢变化维 (Slowly Changing Dimension) 常见的三种类型及原型设计(转)

    开篇介绍 在从 OLTP 业务数据库向 DW 数据仓库抽取数据的过程中,特别是第一次导入之后的每一次增量抽取往往会遇到这样的问题:业务数据库中的一些数据发生了更改,到底要不要将这些变化也反映到数据仓库 ...

  4. DataStage系列教程 (Slowly Changing Dimension)缓慢变化维

    BI中维表的增量更新一般有2种: Type 1:覆盖更改.记录的列值发生变化,直接update成最新记录. Type 2:历史跟踪更改.记录值发生变化,将该记录置为失效,再insert一条新的记录. ...

  5. DIV宽度自动缓慢变化

    <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content ...

  6. 使用CSS3的“transition ”属性控制长宽度的缓慢变化

    有时候我们可能会想要改变某个资源信息的长宽度,比如改变某个div的宽度,而且需要让这个宽度缓慢改变,而不是突然就改变了.这时候你可能会想到使用jquery的animate()函数,不过这个方法既得引用 ...

  7. 如何用SQL语句处理缓慢变化维(渐变维,拉链表)SCD-2?

    假设有一张居民维表,需要记录居民状态的变更历史,根据Kimball建模理论,设计居民维表如下: 另外在ODS中有居民信息的每日快照表(每天都记录一份居民的全量信息):O_USERINFO 如何将ODS ...

  8. 收集hive优化解决方案

    hive的优化问题1.启动一次JOB尽可能多做事,尽量减少job的数量.能重用就重用,要设计好的模型.2.合理设置reduce个数,reduce个数过多,会造成大量小文件问题.3.使用hive.exe ...

  9. 如何实现Qlikview的增量数据加载

    笔者备注: 刚刚接错Qlikview,上网搜集的资料,如何处理增量数据. 1 寻找增量时间戳(1)各种数据库:表的创建时间字段和修改时间字段或者最后的修改时间字段:(2)sql server:可以用找 ...

随机推荐

  1. Direct Line Guidance Odometry论文阅读笔记

    摘要: 本文特色:使用线引导关键点的选择.本文提出这个的论点是:线上的点比图像的其他部分的点更好,而且线上存在更好的关键点.选择线上的点可以筛选过滤掉不太明显的点,从而提高效率. 点和线: 系统使用点 ...

  2. Spring容器初始化的时候如何添加一个定时器?

    昨天遇到这个问题,在项目启动的时候添加一个定时器隔一段时间扫描有没有定时发送的邮件(当然也可以是你自己的业务逻辑),也在网上找了资料,加上自己的修改,终于成功了.所以来做个记录. 1.ServletC ...

  3. Oracle 数据库的组成(instance+database)

    Oracle服务器是一种对象关系数据库管理系统,它为信息管理提供开放.综合.集成的方法. Oracle服务器中有多种进进程.内存结构和文件: Oracle服务器由一个Oracle实例和一个Oracle ...

  4. javascript数组中的方法

    数组中的方法 今天我们来说一下,对数组进行操作的几种方法: //添加 a=[];//空数组   a[0]="我是第一个";   a[2]="我是第三个";    ...

  5. for...of 与 for...in 区别

    一.for...of 1.定义 for...of 语句遍历可迭代对象(包括数组.Set 和 Map 结构.arguments 对象.DOM NodeList 对象.字符串等). 2.语法 for (v ...

  6. 【Linux command reference】

    ubuntu16.04安装中文输入法: https://blog.csdn.net/singleyellow/article/details/77448246 ubuntu16.04 用vi编辑代码, ...

  7. filebeat 简介安装

    Filebeat is a lightweight shipper for forwarding and centralizing log data. Installed as an agent on ...

  8. go——数组(二)

    1.内部实现 在Go语言里,数组是一个长度固定的数据类型,用于存储一段具有相同的类型的元素的连续块. 数组存储的类型可以是内置类型,如整型或字符串,也可以是某种结构类型. 灰格子代表数组里面的元素,每 ...

  9. flask-基础知识

    Flask是一个基于Python开发并且依赖jinja2模板和Werkzeug WSGI服务的一个微型框架,对于Werkzeug本质是Socket服务端,其用于接收http请求并对请求进行预处理,然后 ...

  10. 『NiFi 学习之路』入门 —— 下载、安装与简单使用

    一.概述 "光说不练假把式." 官网上的介绍多少让人迷迷糊糊的,各种高大上的词语仿佛让 NiFi 离我们越来越远. 实践是最好的老师.那就让我们试用一下 NiFi 吧! 二.安装 ...