Data Vault(DV)模型是用于企业级的数据仓库建模。由Dan Linstedt在20世纪90年代提出(http://www.danlinstedt.com)。在最近几年,Data Vault模型获得了很多关注,并在BI社区里拥有了一批追随者。
Dan Linstedt将Data Vault模型定义如下:
Data Vault是面向细节的,可追踪历史的,它是一组有连接关系的规范化的表的集合。这些表可以支持一个或多个业务功能,它是一种综合了第三范式(3NF)和星型模型优点的建模方法。其设计理念是要满足企业对灵活性、可扩展性、一致性和对需求的适应性要求,它是一种专为企业级数据仓库量身定制的建模方式。
从上面的定义,可以看出Data Vault既是一种数据建模的方法论,又是构建企业数据仓库的一种具体方法。Data Vault模型由三个模块组成,中心表、链接表、附属表。建模方法论里定义了Data Vault的组成部分和组成部分之间的交互方式。Data Vault的建模方法中还包括了最佳实践,来指导构建企业数据仓库。例如,业务规则应该在数据的下游实现,就是说Data Vault只按照业务数据的原样保存数据,不做任何解释、过滤、清洗、转换。即使从不同数据源来的数据是自行矛盾的(例如同一个客户有不同的地址),Data Vault模型不会遵照任何业务的规则,如“系统A的地址为准”。Data Vault模型会保存两个不同版本的数据,对数据的解释将推迟到整个架构的后一个阶段(数据集市)。
Data Vault模型是由业务键(Hub)、业务关系(Link)、业务描述(Satellite)组成的
源数据库模型(3NF)如下图:
星型模型如下图:
Data Vault模型如下图:
说明:
星型模型(star schema)的事实表采取了完全规范化的第三范式(3NF)模型,而维表采取了第二范式的设计模型。有时也会把维表的设计规范化,就成了所谓的雪花模型(snowflake schema)。
星型模型向Data Vault模型转化:星型模趔的主要构成部分是维表与事实表,在转化为DataVault模型时自然涉及到维表与事实表的分别转化,使之映射为DataVault模型的Hub、Link、Satellite组件。星型模型与DataVault模型表的对应如下表所示。
转换SQL脚本如下:
use dv;
-- 装载客户中心表
insert hub_customer (customer_id,record_source)
select distinct customer_id,'customer_dim' from customer_dim;
-- 装载客户附属表
insert into sat_customer
(
hub_customer_id,
load_dts,
load_end_dts,
record_source,
customer_name,
city_name,
province_name,
cust_post_code,
cust_address,
ship_post_code,
ship_address
)
select t1.hub_customer_id,
t2.effective_date,
t2.expiry_date,
'hub_customer,customer_dim',
t2.customer_name,
t2.city_name,
t2.province_name,
t2.cust_post_code,
t2.cust_address,
t2.ship_post_code,
t2.ship_address
from hub_customer t1,customer_dim t2
where t1.customer_id=t2.customer_id;
-- 装载产品分类中心表
insert hub_product_catagory (product_catagory_id,record_source)
select distinct product_category_id,'product_dim' from product_dim;
-- 装载产品中心表
insert hub_product (product_id,record_source)
select distinct product_id,'product_dim' from product_dim;
-- 装载产品分类_产品链接表
insert into link_product_catagory (hub_product_id,hub_product_catagory_id,record_source)
select distinct t1.hub_product_id,t2.hub_product_catagory_id,'hub_product,product_dim,hub_product_catagory'
from hub_product t1,hub_product_catagory t2,product_dim t3
where t1.product_id = t3.product_id and t2.product_catagory_id = t3.product_category_id;
-- 装载产品分类附属表
insert into sat_product_catagory
(hub_product_catagory_id,
load_dts,
load_end_dts,
record_source,
product_catagory_name)
select
t1.hub_product_catagory_id,
t2.start_date,
t2.end_date,
'hub_product_catagory,product_dim' record_source,
t2.cname
from
hub_product_catagory t1,
(select
t1.cid cid,
t1.cname cname,
t1.start_date start_date,
t2.end_date end_date
from
(select distinct
if(@cid = t1.cid and @cname = t1.cname, @start_date, @start_date:=t1.start_date) as start_date,
@cid:=t1.cid cid,
@cname:=t1.cname cname
from
((select
product_category_id cid,
product_category_name cname,
effective_date start_date
from
product_dim
order by cid , start_date) t1, (select @cid:=0, @cname:='', @start_date:='0000-00-00') t2)) t1, (select distinct
if(@cid = t1.cid and @cname <> t1.cname, t1.end_date, '2200-01-01') as end_date,
@cid:=t1.cid cid,
@cname:=t1.cname cname
from
((select
product_category_id cid,
product_category_name cname,
expiry_date end_date
from
product_dim
order by cid , end_date desc) t1, (select @cid:=0, @cname:='', @end_date:='0000-0000-00') t2)) t2
where
t1.cid = t2.cid and t1.cname = t2.cname) t2
where
t1.product_catagory_id = t2.cid;
-- 装载产品附属表
insert into sat_product
(
hub_product_id,
load_dts,
load_end_dts,
record_source,
product_name,
unit_price
)
select t1.hub_product_id,t2.start_date,t2.end_date,'hub_product,product_dim' record_source,
t2.pname pname,t2.unit_price
from hub_product t1,
(
select
t1.pid pid,
t1.pname pname,
t1.unit_price,
t1.start_date start_date,
t2.end_date end_date
from
(select distinct
if(@pid = t1.pid and @pname = t1.pname
and @unit_price = t1.unit_price, @start_date, @start_date:=t1.start_date) as start_date,
@pid:=t1.pid pid,
@pname:=t1.pname pname,
@unit_price:=t1.unit_price unit_price
from
((select
product_id pid,
product_name pname,
unit_price,
effective_date start_date
from
product_dim
order by pid , start_date) t1, (select
@pid:=0,
@pname:='',
@unit_price:=0,
@start_date:='0000-00-00'
) t2)) t1,
(select distinct
if(@pid = t1.pid
and (@pname <> t1.pname
OR @unit_price <> t1.unit_price), t1.end_date, '2200-01-01') as end_date,
@pid:=t1.pid pid,
@pname:=t1.pname pname,
@unit_price:=t1.unit_price unit_price
from
((select
product_id pid,
product_name pname,
unit_price,
expiry_date end_date
from
product_dim
order by pid , end_date desc) t1, (select
@pid:=0,
@pname:='',
@unit_price:=0,
@end_date:='0000-0000-00'
) t2)) t2
where
t1.pid = t2.pid and t1.pname = t2.pname
and t1.unit_price = t2.unit_price) t2 where t1.product_id=t2.pid;
-- 装载销售订单中心表
insert into hub_sales_order (sales_order_id,record_source)
select distinct sales_order_id,'sales_order_dim' from sales_order_dim;
-- 装载销售订单附属表
insert into sat_sales_order
(
hub_sales_order_id,
load_dts,
load_end_dts,
record_source,
order_time,
entry_time,
amount,
allocate_time,
packing_time,
ship_time,
receive_time)
select
t1.hub_sales_order_id,
t2.effective_date,
t2.expiry_date,
'hub_sales_order,sales_order_dim',
t2.order_time,
t2.entry_time,
t2.amount,
t2.allocate_time,
t2.packing_time,
t2.ship_time,
t2.receive_time
from hub_sales_order t1,sales_order_dim t2
where t1.sales_order_id = t2.sales_order_id;
-- 装载订单产品链接表
insert into link_order_product
(
hub_sales_order_id,
hub_product_id,
record_source)
select t1.hub_sales_order_id, t2.hub_product_id,
'hub_sales_order,hub_product,sales_order_dim,product_dim,sales_order_fact'
from
hub_sales_order t1,
hub_product t2,
(select t1.sales_order_id sales_order_id, t2.product_id product_id
from sales_order_dim t1, product_dim t2, sales_order_fact t3
where t1.sales_order_sk = t3.sales_order_sk and t2.product_sk = t3.product_sk) t3
where t1.sales_order_id = t3.sales_order_id and t2.product_id = t3.product_id;
-- 装载订单客户链接表
insert into link_order_customer
(
hub_sales_order_id,
hub_customer_id,
record_source)
select t1.hub_sales_order_id, t2.hub_customer_id,
'hub_sales_order,hub_customer,sales_order_dim,customer_dim,sales_order_fact'
from
hub_sales_order t1,
hub_customer t2,
(select t1.sales_order_id sales_order_id, t2.customer_id customer_id
from sales_order_dim t1, customer_dim t2, sales_order_fact t3
where t1.sales_order_sk = t3.sales_order_sk and t2.customer_sk = t3.customer_sk) t3
where t1.sales_order_id = t3.sales_order_id and t2.customer_id = t3.customer_id;
-- 装载订单产品附属表
insert into sat_order_product
(
link_order_product_id,
load_dts,
load_end_dts,
record_source,
unit_price,
quantity
)
select t1.link_order_product_id,t2.effective_date,t2.expiry_date,
'link_order_product,product_dim,sales_order_dim,sales_order_fact,hub_sales_order,hub_product',
t2.unit_price,
t4.quantity
from
link_order_product t1,
product_dim t2,
sales_order_dim t3,
sales_order_fact t4,
hub_sales_order t5,
hub_product t6
where t1.hub_sales_order_id = t5.hub_sales_order_id
and t1.hub_product_id = t6.hub_product_id
and t4.sales_order_sk = t3.sales_order_sk
and t4.product_sk = t2.product_sk
and t5.sales_order_id = t3.sales_order_id
and t6.product_id = t2.product_id;
COMMIT;
---------------------------------------------------------------
摘自:《下一代数据仓库模型Data Vault的研究及其应用》
Data Vault模型的构建
在Data Vault模型中,各个实体组件有着严格、通用的定义与准确、灵活的功能描述,这不但使得Data Vault模型能够最直观、最一般地反映数掘之间内含的业务规则,同时也为构建Data Vault模型提供了一致而普遍的方法。
简单地讲,Data Vault模型是由业务键(Hub)、业务关系(Link)、业务描述(Satellite)组成的。可见,Data Vault很好地实现了从现实世界到信息世界的抽象。所以,使用Data Vault模型进行数据建模与实际的业务设计非常之相似。
Data Vault模型的建立可以遵循如下步骤:
1.设计Hub组件
首先要确定企业数据仓库要涵盖的业务范围;然后要将业务范围划分为若干原子业务实体,比如客户、产品等;然后,从各个业务实体中抽象出能够唯一标识该实体的“键”,该“键”要在整个业务的生命周期内不会发生变化;最后,由该业务键生成Hub组件。
2.设计Link组件
Link体现Hub之间的业务关联。设计Link,首先要熟悉各个Hub代表的业务实体之间的业务关系,可能是两个Hub或者也可能多个Hub之间的关系,根据业务需求,这种关系可以是1对1、1对多、或者多对多。
然后,从相互之间有业务关系的Hub中,提取出代表各自业务实体的业务键,这些业务键将被加入到Link组件中,组合构成该Link的主键。
在生成Link的同时,要注意如果Hub之间有业务交易数据的话,就需要在Link中保存交易数据,有两种方法,一是采用加权Link,二是给Link加上Satellite来处理交易数据。
3.设计Satellite组件
Satallite包含了各个业务实体(Hub)与业务关联(Link)的详细的上下文描述信息。设计Satellite组件,首先要收集各个业务实体在提取业务键后的其他信息,比如客户住址、产品价格等;由于同一业务实体(Hub)的各个描述信息不具有稳定性,会经常发生变化,所以,存必要的时候,需要将变化频率不同的信息分隔开来,为一个Hub提供几个Satellite,然后提取出该Hub的主键,作为描述该Hub的Satellite的主键。
当业务实体之间存在交易数据的时候,需要为没有加权的Link设计Satellite,也可以根据交易数据的不同变化情况设计多个Satellite。
4.设计必要的PIT表
Point—In—Time表是由satellite派生而来的。如果为一个Hub或者Link设计有多个Satellite的话,而为了访问数据方便,就有用到PIT表的可能。
PIT表的主键也是由其所归属的Hub提取而来,该Hub有几个Satellite,PIT表就至少应该有几个字段来存放各个Satellite的变化对比时间。
建立Data Vault模型时虑该参照如下的原则:
■关于Hub的原则
口Hub的主键不能够直接“伸入”到其他Hub里面。就是说,不存在父子关系的Hub。各个Hub之间的关系是平等的,这也正是Data Vault模型灵活性与扩展性之所在。
口Hub之间必须通过Link相关联,通过Link可以联接两个以上的Hub;
口必须至少有两个Hub才能产生一个有意义的Link;
口Hub的键总是“伸出去”的(到Link或者Satellite);
■关于Link的原则
口Link可以跟其他Link相联;
口Hub和Link都可以使用代理键;
口业务主键从来不会改变,就是说Hub的主键不会改变;
口Link可能包含代理键;
●关于Satellite的原则
口Satellite必须是联接到hub或者link上才会有确定的含义;
口Satellite总是包含装载时间load_dts,从而包含历史数据,并且没有重复的数据;
口由于数据信息的类型或者变化频率快慢的差别,描述信息数据可能会被分隔到多个Satellite之中去;