Hive 拉链表实践

Hive 拉链表实践Hive拉链表实践

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE稳定放心使用

背景

拉链表是一种数据模型,主要是针对数据仓库设计中表存储数据的方式而定义的;顾名思义,所谓拉链表,就是记录历史。记录一个事务从开始一直到当前状态的所有变化的信息。

拉链表可以避免按每一天存储所有记录造成的海量存储问题,同时也是处理缓慢变化数据(SCD2)的一种常见方式。

应用场景

现假设有如下场景:一个企业拥有5000万会员信息,每天有20万会员资料变更,需要在数仓中记录会员表的历史变化以备分析使用,即每天都要保留一个快照供查询,反映历史数据的情况。

在此场景中,需要反映5000万会员的历史变化,如果保留快照,存储两年就需要2X365X5000W条数据存储空间,数据量为365亿,如果存储更长时间,则无法估计需要的存储空间。而利用拉链算法存储,每日只向历史表中添加新增和变化的数据,每日不过20万条,存储4年也只需要3亿存储空间。

实现步骤

在拉链表中,每一条数据都有一个生效日期(effective_date)和失效日期(expire_date)。假设在一个用户表中,在2019年11月8日新增了两个用户,如下表所示,则这两条记录的生效时间为当天,由于到2019年11月8日为止,这两条就还没有被修改过,所以失效时间为一个给定的比较大的值,比如:3000-12-31  

member_id phoneno create_time update_time
10001 13300000001 2019-11-08 3000-12-31
10002 13500000002 2019-11-08 3000-12-31

第二天(2019-11-09),用户10001被删除了,用户10002的电话号码被修改成13600000002.为了保留历史状态,用户10001的失效时间被修改为2019-11-09,用户10002则变成了两条记录,如下表所示: 

member_id phoneno create_time update_time
10001 13300000001 2019-11-08 2019-11-09
10002 13500000002 2019-11-08 2019-11-09
10002 13600000002 2019-11-09 3000-12-31

第三天(2019-11-10),又新增了用户10003,则用户表数据如小表所示: 

member_id phoneno create_time update_time
10001 13300000001 2019-11-08 2019-11-09
10002 13500000002 2019-11-08 2019-11-09
10002 13600000002 2019-11-09 3000-12-31
10003 13300000006 2019-11-10 3000-12-31

如果要查询最新的数据,那么只要查询失效时间为3000-12-31的数据即可,如果要查11月8号的历史数据,则筛选生效时间<= 2019-11-08并且失效时间>2019-11-08的数据即可。如果查询11月9号的数据,那么筛选条件则是生效时间<=2019-11-09并且失效时间>2019-11-09

表结构

  • MySQL源member表

CREATE TABLE member(
            member_id VARCHAR ( 64 ),
            phoneno VARCHAR ( 20 ),
            create_time datetime,
            update_time datetime );

  • ODS层增量表member_delta,每天一个分区

CREATE TABLE member_delta
          (member_id string,
            phoneno string,
            create_time string,
            update_time string)
PARTITIONED BY (DAY string);
  • 临时表

CREATE TABLE member_his_tmp
          (member_id string,
            phoneno string,
            effective_date date,
            expire_date date
            );
  • DW层历史拉链表

CREATE TABLE member_his
          (member_id string,
            phoneno string,
            effective_date date,
            expire_date date);

Demo数据准备

2019-11-08的数据为: 

member_id phoneno create_time update_time
10001 13500000001 2019-11-08 14:47:55 2019-11-08 14:47:55
10002 13500000002 2019-11-08 14:48:33 2019-11-08 14:48:33
10003 13500000003 2019-11-08 14:48:53 2019-11-08 14:48:53
10004 13500000004 2019-11-08 14:49:02 2019-11-08 14:49:02

2019-11-09的数据为:其中蓝色代表新增数据,红色代表修改的数据

member_id phoneno create_time update_time
10001 13500000001 2019-11-08 14:47:55 2019-11-08 14:47:55
10002 13600000002 2019-11-08 14:48:33 2019-11-09 14:48:33
10003 13500000003 2019-11-08 14:48:53 2019-11-08 14:48:53
10004 13500000004 2019-11-08 14:49:02 2019-11-08 14:49:02
10005 13500000005 2019-11-09 08:54:03 2019-11-09 08:54:03
10006 13500000006 2019-11-09 09:54:25 2019-11-09 09:54:25

2019-11-10的数据:其中蓝色代表新增数据,红色代表修改的数据  

member_id phoneno create_time update_time
10001 13500000001 2019-11-08 14:47:55 2019-11-08 14:47:55
10002 13600000002 2019-11-08 14:48:33 2019-11-09 14:48:33
10003 13500000003 2019-11-08 14:48:53 2019-11-08 14:48:53
10004 13600000004 2019-11-08 14:49:02 2019-11-10 14:49:02
10005 13500000005 2019-11-09 08:54:03 2019-11-09 08:54:03
10006 13500000006 2019-11-09 09:54:25 2019-11-09 09:54:25
10007 13500000007 2019-11-10 17:41:49 2019-11-10 17:41:49

全量初始装载

在启用拉链表时,先对其进行初始装载,比如以2019-11-08为开始时间,那么将MySQL源表全量抽取到ODS层member_delta表的2018-11-08的分区中,然后初始装载DW层的拉链表member_his

INSERT overwrite TABLE member_his
SELECT
  member_id,
  phoneno,
  to_date ( create_time ) AS effective_date,
 '3000-12-31'
FROM
member_delta
WHERE
DAY = '2019-11-08'

查询初始的历史拉链表数据

Hive 拉链表实践

增量抽取数据

每天,从源系统member表中,将前一天的增量数据抽取到ODS层的增量数据表member_delta对应的分区中。这里的增量需要通过member表中的创建时间和修改时间来确定,或者使用sqoop job监控update时间来进行增联抽取。比如,本案例中2019-11-09和2019-11-10为两个分区,分别存储了2019-11-09和2019-11-10日的增量数据。2019-11-09分区的数据为:

Hive 拉链表实践

2019-11-10分区的数据为:

增量刷新历史拉链数据

  • 2019-11-09增量刷新历史拉链表将数据放进临时表

INSERT overwrite TABLE member_his_tmp
SELECT *
FROM
  (
-- 2019-11-09增量数据,代表最新的状态,该数据的生效时间是2019-11-09,过期时间为3000-12-31
-- 这些增量的数据需要被全部加载到历史拉链表中
SELECT member_id,
       phoneno,
       '2019-11-09' effective_date,
                    '3000-12-31' expire_date
   FROM member_delta
   WHERE DAY='2019-11-09'
   UNION ALL 
-- 用当前为生效状态的拉链数据,去left join 增量数据,
-- 如果匹配得上,则表示该数据已发生了更新,
-- 此时,需要将发生更新的数据的过期时间更改为当前时间.
-- 如果匹配不上,则表明该数据没有发生更新,此时过期时间不变
SELECT a.member_id,
       a.phoneno,
       a.effective_date,
       if(b.member_id IS NULL, to_date(a.expire_date), to_date(b.day)) expire_date
   FROM
     (SELECT *
      FROM member_his
      WHERE expire_date='3000-12-31') a
   LEFT JOIN
     (SELECT *
      FROM member_delta
      WHERE DAY='2019-11-09') b ON a.member_id=b.member_id)his

将数据覆盖到历史拉链表

INSERT overwrite TABLE member_his
SELECT *
FROM member_his_tmp

查看历史拉链表

Hive 拉链表实践

  • 2019-11-10增量刷新历史拉链表

将数据放进临时表

INSERT overwrite TABLE member_his_tmp
SELECT *
FROM
(
-- 2019-11-10增量数据,代表最新的状态,该数据的生效时间是2019-11-10,过期时间为3000-12-31
-- 这些增量的数据需要被全部加载到历史拉链表中
SELECT member_id,
      phoneno,
      '2019-11-10' effective_date,
                   '3000-12-31' expire_date
  FROM member_delta
  WHERE DAY='2019-11-10'
  UNION ALL
-- 用当前为生效状态的拉链数据,去left join 增量数据,
-- 如果匹配得上,则表示该数据已发生了更新,
-- 此时,需要将发生更新的数据的过期时间更改为当前时间.
-- 如果匹配不上,则表明该数据没有发生更新,此时过期时间不变
SELECT a.member_id,
      a.phoneno,
      a.effective_date,
      if(b.member_id IS NULL, to_date(a.expire_date), to_date(b.day)) expire_date
  FROM
    (SELECT *
    FROM member_his
    WHERE expire_date='3000-12-31') a
  LEFT JOIN
    (SELECT *
    FROM member_delta
    WHERE DAY='2019-11-10') b ON a.member_id=b.member_id)his

查看历史拉链表

Hive 拉链表实践

将以上脚本封装成shell调度的脚本

#!/bin/bash

#如果是输入的日期按照取输入日期;如果没输入日期取当前时间的前一天
if [ -n "$1" ] ;then
    do_date=$1
else
    do_date=`date -d "-1 day" +%F`
fi

sql="

INSERT overwrite TABLE member_his_tmp
SELECT *
FROM
  (
-- 2019-11-10增量数据,代表最新的状态,该数据的生效时间是2019-11-10,过期时间为3000-12-31
-- 这些增量的数据需要被全部加载到历史拉链表中
SELECT member_id,
       phoneno,
       '$do_date' effective_date,
       '3000-12-31' expire_date
   FROM member_delta
   WHERE DAY='$do_date'
   UNION ALL
-- 用当前为生效状态的拉链数据,去left join 增量数据,
-- 如果匹配得上,则表示该数据已发生了更新,
-- 此时,需要将发生更新的数据的过期时间更改为当前时间.
-- 如果匹配不上,则表明该数据没有发生更新,此时过期时间不变
SELECT a.member_id,
       a.phoneno,
       a.effective_date,
       if(b.member_id IS NULL, to_date(a.expire_date), to_date(b.day)) expire_date
   FROM
     (SELECT *
      FROM member_his
      WHERE expire_date='3000-12-31') a
   LEFT JOIN
     (SELECT *
      FROM member_delta
      WHERE DAY='$do_date') b ON a.member_id=b.member_id)his;
"

$hive -e "$sql"


版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/184270.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • 如何在云服务器搭建虚拟主机,如何在云服务器搭建虚拟主机

    如何在云服务器搭建虚拟主机,如何在云服务器搭建虚拟主机如何在云服务器搭建虚拟主机内容精选换一换GaussDB(DWS)提供的gsql命令行客户端,它的运行环境是Linux操作系统,在使用gsql客户端远程连接GaussDB(DWS)集群之前,需要准备一个Linux主机用于安装和运行gsql客户端。如果通过公网地址访问集群,也可以将gsql客户端安装在用户自己的Linux主机上,但是该Linux主机必须具有公网地址。为方便起见,弹性云服务器(El…

    2022年6月25日
    45
  • AES加密算法的详细介绍与实现

    AES加密算法的详细介绍与实现AES简介高级加密标准(AES,AdvancedEncryptionStandard)为最常见的对称加密算法(微信小程序加密传输就是用这个加密算法的)。对称加密算法也就是加密和解密用相同的密钥,具体的加密流程如下图:下面简单介绍下各个部分的作用与意义:明文P没有经过加密的数据。密钥K用来加密明文的密码,在对称加密算法中,加密与解密的密钥是相同的。密钥为接收方与发送方协商产生

    2022年6月26日
    20
  • (原创)通过ActivityManager杀死第三方应用方式[通俗易懂]

    (原创)通过ActivityManager杀死第三方应用方式[通俗易懂]ActivityManageram=(ActivityManager)context.getSystemService(Context.ACTIVITY_SERVICE);am.killBackgroundProcesses(responseAppInfo.getPackname());

    2025年9月24日
    4
  • idea通过服务器激活破解方法

    idea通过服务器激活破解方法,https://javaforall.net/100143.html。详细ieda激活码不妨到全栈程序员必看教程网一起来了解一下吧!

    2022年3月15日
    157
  • 课程表app源码_课程表模板excel

    课程表app源码_课程表模板excel快乐的时光过得特别快,很快各位学生党就要迎来新学期了。课程表对学生的意义不言而喻,特别是对作息自理的大学生来说,没课程表不知道要不要上课丝毫不奇怪,这时在手机上装一个课程表App就省事多了。课程表App为数不少,但你听说过能够撩学妹泡妞的课程表App吗?今天介绍的这款课程格子,就有这么个功能。软件名称:课程格子软件版本:3.00官方版软件大小:5.98MB软件授权:免费适用平台:Android实…

    2022年10月4日
    3
  • fastjson 注解(JAVA注解)

    查看@JSONField注解的源码可以了解到它的作用范围是在方法(METHOD)、属性(FIELD)、方法中的参数(PARAMETER)上。1.作用在FIELD(成员变量上)注意:1、若属性是私有的,必须有set*方法。否则无法反序列化。packagecom.zhujie;importcom.alibaba.fastjson.JSONObject;importcom…

    2022年4月10日
    766

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号