数仓--DW--Hadoop数仓实践Case-15-无事实的事实表

无事实的事实表概述

  • 在多维数据仓库建模中, 有一种事实表叫做“无事实的事实表”。 普通事实表中, 通常会保存若干维度外键和多个数字型度量, 度量是事实表的关键所在。 然而在无事实的事实表中没有这些度量值, 只有多个维度外键。 表面上看, 无事实的事实表是没有意义的, 因为作为事实表, 毕竟最重要的就是度量。 但在数据仓库中, 这类事实表有其特殊用途。 无事实的事实表通常用来跟踪某种事件或者说明某些活动的范围
  • 无事实的事实表可以用来跟踪事件的发生。
    • 例如, 在给定的某一天中发生的学生参加课程的事件, 可能没有可记录的数字化事实, 但该事实行带有一个包含日期、 学生、 教师、 地点、 课程等定义良好的外键。利用无事实的事实表可以按各种维度计数上课这个事件。
    • 再比如学生注册事件, 学校需要对学生按学期进行跟踪。 维度表包括学期维度、 课程维度、 系维度、 学生维度、 注册专业维度和取得学分维度等, 而事实表由这些维度的主键组成, 事实只有注册数, 并且恒为1, 因此没有必要用单独一列来表示。 这样的事实表主要用于回答各种情况下的注册数。
  • 无事实的事实表还可以用来说明某些活动的范围, 常被用于回答“什么未发生”这样的问题。
    • 例如: 促销范围事实表。 通常销售事实表可以回答如促销商品的销售情况, 可是无法回答的一个重要问题是: 处于促销状态但尚未销售的产品包括哪些? 销售事实表所记录的仅仅是实际卖出的产品。 事实表行中不包括由于没有销售行为而销售数量为零的行, 因为如果将包含零值的产品都加到事实表中, 那么事实表将变得非常巨大。 这时, 通过建立促销范围事实表, 将商场需要促销的商品单独建立事实表保存, 然后通过这个促销范围事实表和销售事实表即可得出哪些促销商品没有销售出去。
    • 为确定当前促销的产品中哪些尚未卖出, 需要两步过程: 首先, 查询促销无事实的事实表, 确定给定时间内促销的产品。 然后从销售事实表中确定哪些产品已经卖出去了。 答案就是上述两个列表的差集。 这样的促销范围事实表只是用来说明促销活动的范围, 其中没有任何事实度量。 可能有读者会想, 建立一个单独的促销商品维度表能否达到同样的效果呢? 促销无事实的事实表包含多个维度的主键, 可以是日期、 产品、 商店、 促销等, 将这些键作为促销商品的属性是不合适的, 因为每个维度都有自己的属性集合。
  • 促销无事实的事实表看起来与销售事实表相似。 然而, 它们的粒度存在显著差别。 假设促销是以一周为持续期, 在促销范围事实表中, 将为每周每个商店中促销的产品加载一行, 无论产品是否卖出。 该事实表能够确保看到被促销定义的键之间的关系, 而与其他事件, 如产品销售无关。
  • 下面以销售订单数据仓库为例,说明如何处理源数据中没有度量的需求。 我们将建立一个无事实的事实表, 用来统计每天发布的新产品数量。 产品源数据不包含产品数量信息, 如果系统需要得到历史某一天新增产品的数量, 很显然不能简单地从数据仓库中得到。 这时就要用到无事实的事实表技术。 使用此技术可以通过持续跟踪产品发布事件来计算产品的数量。 可以创建一个只有产品(计什么数) 和日期(什么时候计数) 维度代理键的事实表。 之所以叫做无事实的事实表是因为表本身并没有数字型度量值。 这里定义的新增产品是指在某一给定日期, 源产品表中新插入的产品记录, 不包括由于SCD2新增的产品版本记录。 注意, 单从这个简单需求来看, 也可以通过查询产品维度表获取结果。 这里只为演示无事实的事实表的实现过程。

建立新产品发布的无事实的事实表

  • 在数据仓库模式中新建一个产品发布的无事实的事实表product_count_fact, 该表中只包含两个字段, 分别是引用日期维度表和产品维度表的外键, 同时这两个字段也构成了无事实事实表的逻辑主键。 下图显示了跟踪产品发布数量的数据仓库模式(只显示与无事实的事实表相关的表)。


    无事实的事实表.PNG
  • 执行下面的脚本在数据仓库模式中创建产品发布日期视图及其无事的实事实表。
use dw;
create view
    product_launch_date_dim
(   
    product_launch_date_sk,
    product_launch_date,
    month_name,
    month,
    quarter,
    year
)
as select 
    distinct date_sk,
    date,
    month_name,
    month,
    quarter,
    year
from
    product_dim a, date_dim b
where
    a.effective_date = b.date; 
-- 创建表
create table
product_count_fact (
product_sk int,
product_launch_date_sk int
);
  • 语句说明:
  • 与之前创建的很多日期角色扮演维度不同, 产品发布日期视图只获取产品生效日期, 而不是日期维度里的所有记录。 因此在定义视图的查询语句中关联了产品维度和日期维度两个表。 product_launch_date_dim维度表是日期维度表的子集。
  • 从字段定义上看, 产品维度表中的生效日期明显就是新产品的发布日期。
  • 在本示例中, 无事实的事实表的数据装载没有行级更新需求, 所以该表使用Hive默认的文本存储格式。

装载无事实的事实表

  • 下面的脚本从产品维度表向无事实的事实表装载已有的产品发布信息。 脚本里的insert语句添加所有产品的第一个版本, 即产品的首次发布日期。 这里使用Hive的窗口函数row_number正确地选取了产品发布时的生效日期, 而不是一个SCD2行的生效日期。
-- 装载无事实的事实表
insert overwrite table
    product_count_fact
select
    product_sk,date_sk
from
(
    select
        a.product_sk product_sk,
        b.date_sk date_sk,
        row_number() over (partition by a.product_code order byb.date_sk) rn
from
    product_dim a,date_dim b
where
    a.effective_date = b.date
) t
where
    rn = 1;
  • 语句说明:
  • 子查询中内连接产品维度与日期维度表, 只获取产品发布的日期。
  • 以产品编码分区, 同一个产品编码的多个版本以发布日期排序, row_number()函数为每个版本分配序号, 起别名rn。
  • 外层查询以rn=1作为过滤条件, 得到每个产品及其首次发布日期的代理键。
  • 该语句允许多次执行, 每次覆盖已有数据。
  • 其实利用产品维度表的版本字段, 更简单的写法如下:
-- 采用版本的方式进行开发
insert overwrite table
    product_count_fact
select
    a.product_sk product_sk,
    b.date_sk date_sk
from
    product_dim a,date_dim b
where
    a.effective_date = b.date anda.version = 1;

定期装载

  • 测试脚本之后,需要将脚本按照时间粒度,定时加载到Azkaban调度流中。

你可能感兴趣的:(数仓--DW--Hadoop数仓实践Case-15-无事实的事实表)