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)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • 安卓基础(十五)[通俗易懂]

    安卓基础(十五)

    2022年1月28日
    40
  • Python3对多股票的投资组合进行分析「建议收藏」

    Python3对多股票的投资组合进行分析「建议收藏」目录概述:一、股票数据准备1、股票选择2、获取每支股票的收盘价3、计算股票的日收益率二、投资组合的收益计算1、给定权重的投资组合2、等权重的投资组合3、市值加权的投资组合三、投资组合的相关性分析1、投资组合的相关矩阵2、投资组合的协方差矩阵3、投资组合的标准差四、探索股票的最优投资组合1、使用蒙特卡洛模拟Markowitz模型2、投资…

    2022年9月1日
    6
  • python快速排序法实现

    python快速排序法实现基本思想是:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。一趟快速排序的算法是:1)设置两个变量i、j,排序开始的时候:i=0,j=N-1;2)以第一个数组元素作为关键数据,赋值给key,即key=A[0];3

    2025年6月18日
    4
  • 管理大数据存储的十大技巧「建议收藏」

    管理大数据存储的十大技巧「建议收藏」数据本地化是为了确保大数据集存储在计算节点附近便于分析。对于Hadoop,这意味着管理数据节点,向MapReduce提供存储以便充分执行分析。它实用有效但也出现了大数据存储集群的独立操作问题。以下十项是Hadoop环境中管理大数据存储技巧。在1990年,每一台应用服务器都倾向拥有直连式系统(DAS)。SAN的构建则是为了更大的规模和更高的效率提供共享的池存储。Hadoop已经逆转了这一趋势回归DA…

    2022年5月28日
    38
  • 利用PowerShell复制SQLServer账户的所有权限

    利用PowerShell复制SQLServer账户的所有权限

    2021年11月28日
    38
  • MacOS:Shell工具-Royal TSX

    MacOS:Shell工具-Royal TSX第一次使用 Mac 下的 Shell 软件 把使用过程做一个简单的记录 希望能帮到需要的朋友 Mac 下的 Shell 软件也有挺多 经过比较 在机器数量较小的情况下自用的免费软件 我选择了 RoyalTSX 一 官方的使用说明文档首先贴出下图是官方的使用说明文档作为参考 官方说明文档永远是最准确的资料 笔者的安装过程也是根据官方文档进行

    2025年6月5日
    3

发表回复

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

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