数据模式(Schema)定义

数据模式(Schema)定义

Created 星期一 24 十月 2016

模式(Schema)定义了一个多维数据库,它包一个含逻辑模型,并定义了逻辑模型到物理模型的映射
物理模型包含多维数据的存储方式:事实表、维表及其结构等。
逻辑模型包含了用于MDX 查询的结构,如数据立方体、维度、层次、成员、度量等。
Mondrian 使用一个XML 文件来描述模式。
Mondrian 包含一个创建、修改模式文件的Java桌面应用schema-workbench

模式文件

Schema 文件可以定义虚拟立方体,基于一个或多个基础立方体来建立。也可以定义角色以及角色的访问权限(对立方体、维度等)。有关虚拟立方体和角色的内容本文档不涉及。
Schema 文件主要结构如下(去掉了VirtualCube 和Role 等):
Schema 包含立方体、虚拟立方体、共享维度、角色

Cube 维度和度量的集合,以事实表为中心

Table 事实表

AggName 声明一个聚集表

aggElements 聚集表设置,结构见下

AggPattern 声明一批聚集表

aggElements

Dimension 维度

Hierarchy 维度层次

relation 物理表、视图,结构见下
Closure/ 映射父子层次关系
Level 一个层次

DimensionUsage 引用共享维度
Measure 度量

CalculatedMemberProperty/

CalculatedMember 计算成员
NamedSet 命名集合

Formula/ 公式

UserDefinedFunction/ 声明用户自定义函数

Relation 可以是Table、View、Inline Table、Join:
aggElement 可以是以下元素:

  • AggExclude
  • AggFactCount
  • AggIgnoreColumn
  • AggForeignKey
  • AggMeasure
  • AggLevel

示例:
personDemo.xml



<Dimension name="部门" foreignKey="USERID" >

<Hierarchy hasAll="true" primaryKey="USERID" allMemberName="所有部门" >


<Level name="部门" column="DEPARTMENT" uniqueMembers="true" />














<Measure name="人数" column="USERID" aggregator="distinct count" />

度量

每个度量都有一个名字,一个事实表的列,一个聚集器(aggregator)。聚集起通常为sum,但count,min,max,avg,distinct-count 都是可以的;

  • 可选的datatype 属性可以是String、Integer、Numeric、Boolean、Date、Time 以及Timestamp,默认是Numeric,除了是count 或distinct-count,,这两个默认是Integer。
  • 可选的formatString 属性指定怎样打印这个值。
  • 度量可以有一个caption(标题)属性以便Member.getCaption()方法返回它而不是返回名字。

度量除了可以来自一个列,也可以使用一条SQL 表达式来计算。下面Promotion Sales 就是
一个例子:

(case when sales_fact_1997.promotion_id =0 then 0 else
sales_fact_1997.store_sales end)


为了一致,度量被视为一个特别的维度的成员,这个维度叫做Measures

缺省度量

Cube(和VirtualCube)元素允许指定可选的属性defaultMeasure

...

维度,层次

 

表映射

Dimension 元素有一个foreignKey 属性,它是事实表的列名
而Hierarchy 元素有一个primaryKey 属性
如果一个层次有不止一个表,可以使用primaryKeyTable 属性来区分。
Level 的column 定义了它的键,必须是这个层次所在表的列名。如果键是一个表达式,可以使用KeyExpression 元素子元素。
Level 元素的uniqueMembers 属性用于优化SQL 生成。

成员"ALL"

多层次体系
一个维度可以由多个层次组成:





uniqueMembers="false"/>





uniqueMembers="false"/>


除了它们都连接事实表的同一列"time_id"以外,这些维度层次没有多少共同的地方,它们甚至没有使用同一个表。
把两个层次放到一个维度中的主要原因是,这对终端用户来说有更多意义。终端用户知道如果把"Time"层次放到一个轴上而把"Time Weekly"放到另一个轴上是没有意义的。如果两个层次是同一个维度,MDX 不会允许它们用于同一个查询中。

退化维度

退化维度是这样的一种维度:由于它过于简单而不值得为它创建一个维表。考虑下面的事实表:
产品 时间 支付方式 客户 数量 金额
55 20040106 Credit 123 3 3.54
78 20040106 Cash 89 1 20.00
199 20040107 ATM 3 2 2.99
55 20040106 Cash 122 1 1.18
假设我们为支付方式列的值创建一个维表:
payment_method
Credit
Cash
ATM
这个维表没什么意义,它只有三个取值,没有额外的信息,并产生了额外的连接开销。你可以创建一个退化维度,只要声明一个维度却不指定表,Mondrian 会认为这些列是来自事实表。





uniqueMembers="true"/>




注意由于没有连接,Dimension 的foreignKey 属性是不必要的,并且Hierarchy 元素没有Table 子元素或primaryKey 属性。

 

内嵌表

http://mondrian.pentaho.com/documentation/schema.php#Inline_tables
InlineTable 构件允许你在模式文件定义一个数据集。你必须要声明列名,列类型(String 或Numeber),以及一个行集。像Table 和View 一样,你必须提供一个唯一别名以引用这个数据集。这里是一个例子(定义了严重性级别维度):









1
High


2
Medium


3
Low






这跟你的数据库有一个名为severity 的表以及下面的声明是一样的效果。
Severity 表:
id desc
1 High
2 Medium
3 Low

成员属性

成员属性通过Level 内的Property 元素来定义,例如:

formatter="com.example.MyPropertyFormatter"/>

Property 的属性formatter 定义了一个属性格式化器,它修改了成员的
getPropertyFormattedValue()的默认行为。格式化器要实现mondrian.spi.PropertyFormatter接口。
一旦属性在模式中定义了以后,就可以在MDX 语句中使用它,通过member.Properties("属性名")函数。例如:
SELECT
{[Store Sales]} ON COLUMNS,
TopCount(Filter([Store].[Store Name].Members,
[Store].CurrentMember.Properties("Store Type") = "Supermarket"),
10, [Store Sales]) ON ROWS
FROM [Sales]
先筛选类型为"Supermarket"的商场(Filter 函数),再选出销售额最大的十家(TopCount 函数),把它们放在行上。

计算成员

假设你想创建一个度量,它的值不是来自事实表的列,而是来自一个MDX 公式
有两种方式。
一种方式使用with member 字句,像这样:
WITH MEMBER [Measures].[Profit] AS '[Measures].[Store Sales]-[Measures].[Store Cost]',
FORMAT_STRING = '$#,###'
SELECT {[Measures].[Store Sales], [Measures].[Profit]} ON COLUMNS,
{[Product].Children} ON ROWS
FROM [Sales]
WHERE [Time].[1997]
但比起在每个MDX 查询中包含这个子句,更好的办法是,你可以把这个成员定义到模式中,作为立方体定义的一部分:

[Measures].[Store Sales] - [Measures].[Store Cost]


你可以给计算成员指定SOLVE_ORDER 属性,用于确定计算时的优先级:

命名集合


...
<NamedSet name="Top Sellers">

TopCount([Warehouse].[Warehouse Name].MEMBERS, 5,
[Measures].[Warehouse Sales])



在MDX 中使用:
SELECT
{[Measures].[Warehouse Sales]} ON COLUMNS,
{[Top Sellers]} ON ROWS
FROM [Warehouse]
WHERE [Time].[Year].[1997]

星型和雪花型

前面的立方体都是基于一个事实表、事实表上的维度以及连接到事实表的维表构建。这是最普通的映射方式,称为星型模式(Star Schema)。
一个维度可以基于不止一个维表,只要这些表能有良好定义的路径连接到事实表。这样定义维度的方式就是一个雪花型模式(Snowflake Schema)。这些维表通过Join 操作来定义。例如:

...

primaryKeyTable="product">
<Join leftKey="product_class_key" rightAlias="product_class"
rightKey="product_class_id">


<Join leftKey="product_type_id" rightKey="product_type_id">







上面定义了一个由三个表组成的Product 维度。事实表连接到product(通过外键
product_id),而product 连接到product_class(通过外键product_class_id),而
product_class 连接到product_type(通过外键product_type_id)。我们需要一个Join 元素内嵌套一个Join 元素,因为Join 接收两个操作数。操作数可以是表、连接(Join)甚至查询。
注意这里Join 元素有一个rightAlias 属性。这是必要的,因为Join 的右边组件(嵌套的Join元素)由不止一个表组成。这种情形下leftAlias 属性是不必要的,因为leftKey 来自product表,没有歧义。

 

共享维度

当一个维度(维表)被多个立方体使用时,可以把它定义为共享维度(shared dimensions),在立方体内引用这个维度即可。因为一个共享维度不属于一个立方体,你必须给它一个明确的表(或其他数据源)。当你在某个立方体中使用它时,指定维度的外键。








...
<DimensionUsage name="Store Type" source="Store Type" foreignKey="store_id"/>

闭包表

http://mondrian.pentaho.com/documentation/schema.php#Closure_tables
举例来说,闭包表(closure table)就是包含所有雇员/主管关系记录(不管深度如何)的SQL 表。

聚集表

http://mondrian.pentaho.com/documentation/schema.php#Aggregate_tables
设想一个CEO要运行一个销售报表,这个报表只包含一个数值:今年所有产品在所有地区的销售总额。为了获得这个数值,Mondrian产生像这样的一条SQL语句:
SELECT sum(store_sales)
FROM sales_fact, time
WHERE sales_fact.time_id = time.time_id AND time.year = 2005
并发送给数据库,而数据库要花好几分钟去执行它。这也容易理解,因为数据库要读取事实表中所有今年的记录(比方说,几百万条销售数据)然后汇总成一个汇总数。很明显,在这里,以及其他类似的时候,所需要的只是一个预先计算的概括性数据:聚集表。
聚集表跟基础事实表同时共存,包含着从事实表建立的预先聚集的度量。它在Mondrian的模式文件中注册,因此在一个特定的查询中能应用得上的时候,Mondrian 就能够选择某个聚集表而不是事实表。

Mondrian 有一个工具AggGen (aggregate generator)用于辅助设计和维护聚集表。它可以生成创建聚集表的SQL 语句,它也可以根据一条MDX 语句,给出能够优化这个查询的创建/插入聚集表的SQL 语句。

 

 

 

你可能感兴趣的:(数据)