如何设计 Mondrian Schema模式

1.什么是Schema

2.Schema模式文件

    1.Annotation注解

3.逻辑模型

    1.Cube数据立方

    2.Measure数据度量

    3.Dimesions,Hierarchies,Levels:维度,层次,层级

        1.维度,层次映射到数据库表结构中

        2.“All”成员

        3.时间维度

    4.Level的摆放顺序与显示效果

    5.多个层次

    6.维度退化

    7.Inline表

    8.Member成员的属性与格式

    9.近似的level层级基数

    10.缺省的Measure度量属性

    11.有效的依赖优化

    12.table表格注释

4.星型模式与雪花模式

    1.共享的维度

    2.Join连接优化

5.高级逻辑结构设计

    1.虚拟数据立方

    2.父-子层次

        1.调整父-子层级

        2.闭合表

        3.填充闭合表

    3.Member成员属性

    4.计算的成员

    5.命名集合

6.插件

    1.用户自定义函数

    2.Member成员读取器

    3.Cell单元格读取器

    4.Cell单元格式

    5.Member成员格式

    6.属性格式

    7.Schema模式处理器

    8.数据源更新监听器

    9.动态数据源xmla servlet

7.国际化

8.聚合表

9.Access-control控制取值

    1.定义角色

    2.汇总策略

    3.角色联合

    4.设置连接器角色

10.附录A:XML元素




1.什么是模式Schema

一个模式文件定义了一个多维数据库。模式中包含了一个逻辑模型,逻辑模型

由数据立方Cube,层次Hierarchies,成员members,以及一个将逻辑模型与物理模型的映射组成。


逻辑模型包含了将在MDX语言的查询中要使用到的结构:cubes,dimensions,hierachies,levels,以及members.


物理模型是数据源,物理模型通过逻辑模型来呈现。物理模型是一个典型的星型模式,即是关系数据库中的一系列表。后面,我们将展示一个其他类型的映射(雪花型)。


2.模式文件

Mondrian模式文件是一个xml文件。Mondrian在其下载包的“demo/FoodMart.xml”中,提供了一个模式文件的例子,包含了几乎所有我们会讨论到的结构。运行这个模式的数据集也在发布的下载包中。

当前,创建模式文件的唯一方法是在文本编辑器中编辑一个模式的xml文件。XML的语法并不复杂,因此,当你在使用FoodMart.xml模式文件作为一个引导实例时,并不困难。


XML文件的结构如下:

<Schema>
<Cube>
<Table>
<AggName>
aggElements
<AggPattern>
aggElements
<Dimension>
<Hierarchy>
relation
<Closure/>
<Level>
<KeyExpression>
<SQL/>
<NameExpression>
<SQL/>
<CaptionExpression>
<SQL/>
<OrdinalExpression>
<SQL/>
<ParentExpression>
<SQL/>
<Property>
<PropertyExpression>
<SQL/>
<DimensionUsage>
<Measure>
<MeasureExpression>
<SQL/>
<CalculatedMemberProperty/>
<CalculatedMember>
<Formula/>
<CalculatedMemberProperty/>
<NamedSet>
<Formula/>
<VirtualCube>
<CubeUsages>
<CubeUsage>
<VirtualCubeDimension>
<VirtualCubeMeasure>
<Role>
<SchemaGrant>
<CubeGrant>
<DimensionGrant>
<HierarchyGrant>
<MemberGrant/>
<Union>
<RoleUsage/>
<UserDefinedFunction/>
<Parameter/>
relation ::=
<Table>
<SQL/>
<View>
<SQL/>
<InlineTable>
<ColumnDefs>
<ColumnDef>
<Rows>
<Row>
<Value>
<Join>
relation
aggElement ::=
<AggExclude>
<AggFactCount>
<AggIgnoreColumn>
<AggForeignKey>
<AggMeasure>
<AggLevel>



注意:XML元素在文件中的放置顺序很重要,比如<UserDefinedFunction>元素必须出现在<Schema>元素里面,且在所有<Cube>, <VirtualCube>, <NamedSet><Role>的集合的后面。


每一个XML元素的内容都在附录和XML模式中进行了描述。


2.1 Annotation注解

模式文件中的主要元素类型(Schema,Cube,Virtual cube,Shared dimesion,Dimesion,Hierarchy,Level,Measure,Calculated member)都支持注解。注解是一种将用户自定义属性与元数据联系起来的方式,另外,注解还允许工具在不扩展官方Mondrian模式的前提下添加元数据。


创建一个<Annotations>元素作为一个你希望注解的元素的child(通常是第一个child元素,可以查看schema定义),然后包含一些<Annotation>元素,这些元素的名字必须在他们的父元素中是唯一的。如果你打算添加annotations来支持一个你使用的工具,那么要谨慎选择annotation的命名,以确保不会跟其他工具使用的annotations冲突。


下面的例子展现了Author和Date元素的注解

<Schema name="Rock Sales">
<Annotations>
<Annotation name="Author">Fred Flintstone</Annotation>
<Annotation name="Date">10,000 BC</Annotation>
</Annotations>
<Cube name="Sales">
…



3.逻辑模型Logical model

Schema模式文件中最重要的组成部分是:数据立方Cube,度量Measure,维度Dimession.

数据立方Cube:是一个在特定对象区域中的维度和度量的集合。

度量Measure:是一个你希望度量计算的数量值,比如产品的销售数,或产品的成本。

维度Dimession:是一个属性,或者一个属性集合,通过维度,可以将度量划分到不同的子类别中。比如,你希望对Sales表根据颜色,客户性别和商品所在门店进行划分的话,那么颜色,性别和门店就是不同的维度。


让我们来看一看一个XML定义的简单schema例子。

<Schema>
<Cube name="Sales">
<Table name="sales_fact_1997"/>
<Dimension name="Gender" foreignKey="customer_id">
<Hierarchy hasAll="true" allMemberName="All Genders" primaryKey="customer_id">
<Table name="customer"/>
<Level name="Gender" column="gender" uniqueMembers="true"/>
</Hierarchy>
</Dimension>
<Dimension name="Time" foreignKey="time_id">
<Hierarchy hasAll="false" primaryKey="time_id">
<Table name="time_by_day"/>
<Level name="Year" column="the_year" type="Numeric" uniqueMembers="true"/>
<Level name="Quarter" column="quarter" uniqueMembers="false"/>
<Level name="Month" column="month_of_year" type="Numeric" uniqueMembers="false"/>
</Hierarchy>
</Dimension>
<Measure name="Unit Sales" column="unit_sales" aggregator="sum" formatString="#,###"/>
<Measure name="Store Sales" column="store_sales" aggregator="sum" formatString="#,###.##"/>
<Measure name="Store Cost" column="store_cost" aggregator="sum" formatString="#,###.00"/>
<CalculatedMember name="Profit" dimension="Measures" formula="[Measures].[Store Sales] - [Measures].[Store Cost]">
<CalculatedMemberProperty name="FORMAT_STRING" value="$#,##0.00"/>
</CalculatedMember>
</Cube>
</Schema>



这个schema文件包含了一个简单的叫做“Sales”的数据立方Cube,这个cube有两个维度:时间和性别,还有4个度量:单元销售,门店销售,门店成本,利润。


我们可以根据这个模式文件来编辑MDX查询语句:

SELECT {[Measures].[Unit Sales], [Measures].[Store Sales]} ON COLUMNS,
  {descendants([Time].[1997].[Q1])} ON ROWS
FROM [Sales]
WHERE [Gender].[F]


这条查询语句使用了Sales 数据立方[Sales],和每个维度[Measures], [Time], [Gender],还有这些维度的几个成员。查询结果如下:

[Time]             [Measures].[Unit Sales]   [Measures].[Store Sales]

[1997].[Q1]    0                         0

[1997].[Q1].[Jan]    0                    0

[1997].[Q1].[Feb]    0                    0

[1997].[Q1].[Mar]    0                    0


接下来,我们来了解schema模式的更多细节。


3.1 数据立方Cube

数据立方Cube包含了度量和维度在其内。度量与维度处于同一个事实表中,这个例子中的事实表是sales_fact_1997。正如我们将看到的,事实表包含了用于计算度量的列,并且包含了拥有维度的数据库表的参照。

<Cube name="Sales">
<Table name="sales_fact_1997"/>
...
</Cube>


事实表使用<Table>元素来定义。如果事实表不在默认的Schema模式中,我们可以通过Schema的属性明确提供一个模式,比如:

<
Table
 schema=" dmart" name=“sales_fact_1997"/>


我们也可以使用<View>结构来构建更复杂的SQL语句。<Join>结构不支持事实表。


3.2 度量Measure

Sales数据立方中定义了若干个度量,包括“Unit Sales”和”Store Sales”。

<Measure name="Unit Sales" column="unit_sales" aggregator="sum" datatype="Integer" formatString="#,###"/>
<Measure name="Store Sales" column="store_sales" aggregator="sum" datatype="Numeric" formatString=“#,###.00"/>


每个度量都有一个名字,以及一个对应事实表中的列,和一个aggregator。

aggregator通常包括:sum,count,min,max,avg,distinct-count。其中distinct-count在使用包含父-子层级的数据立方时存在一些限制条件。


可选的属性datatype指定了在Mondrian的缓存中cell的值以何种格式展示,以及通过xml文件如何返回分析查询结果。datatype属性包含的值包括:String,Integer,Numeric,Boolean,Date,Time和Timestamp。默认的是Numeric。而count和distinct-count属性的默认格式是Integer。


一个可选的formatString属性指定了这个度量值是如何呈现(打印)出来的。

一个度量可以拥有一个标题属性caption来代替name属性,并通过Member.getCaption()方法返回其标题。定义一个指定的标题有时很有作用,比如 使用特殊字符(如Σ 或 Π)展示时。

<
Measure
 name="Sum X" column="sum_x" aggregator="sum" caption="&#931; X”/>


度量可以不是来自于某个列,它可以使用一个cell reader,或一个度量可以使用一个SQL表达式来计算它的值。比如度量“Promotion Sales”就是这样一个例子:

<Measure name="Promotion Sales" aggregator="sum" formatString="#,###.00">
<MeasureExpression>
<SQL dialect="generic">
(case when sales_fact_1997.promotion_id =
0 then 0 else sales_fact_1997.store_sales end)
</SQL>
</MeasureExpression>
</Measure>


这个例子中,如果sales属于一个推广销售,那么sales将包含进总和里面。任意的SQL表达式可以使用,当然也包括子查询。然而,底层的数据库必须能够支持将SQL表达式写进一个aggregate聚合环境中。不同数据库之间的语句变化将通过指定的SQL标签中的dialect方言进行处理。


一个度量可以使用cell formatter来提供一个cell 值的具体格式。


3.3 维度,层次,层级

更多的定义:
(1)成员,指的是在一个维度内,由属性值的一个特定集合指定的一个取值点。比如 性别层次用两个成员:M和F。商店层次有三个成员:’San Francisco', 'California' 和 'USA' 。

(2)层次,指的是一个成员的集合。为了方便分析,成员的集合被组织进一个结构中。比如,商店层次包括店名,城市,州和国家。这个层次允许我们构造一个中间的部分整体。对于一个state州来说,这个部分整体就是这个州内的所有城市的部分整体的总和,每个城市中的部分整体又是这个城市中所有商店的部分整体的总和。

(3)层级,指的是所有到顶层root层级相同距离的成员的集合。

(4)维度,指的是层次的集合。这些层次通过相同的事实表属性进行区分。

为了统一,度量作为一种特殊的维度,称之为Measures维度。


下面是一个简单的维度的例子:

<Dimension name="Gender" foreignKey="customer_id">
<Hierarchy hasAll="true" primaryKey="customer_id">
<Table name="customer"/>
<Level name="Gender" column="gender" uniqueMembers="true"/>
</Hierarchy>
</Dimension>


这个维度包含了一个单独的层次,其中包含的层级由一个叫Gender的层级组成。(我们以后将会介绍,这里还有一个特殊的层级:All,包含了一个总计值)


这个维度的值来自于customer表的gender列。gender列包含了两个值:F和M,因此Gender维度包含了两个成员:[Gender].[F]和[Gender].[M]。

对于任意给定的sale,gender维度指的是进行支付的顾客的性别。这是通过join事实表sales_fact_1997.customer_id和维度表customer.customer_id来表现的。


3.3.1 维度、层次与数据库表的映射

维度与cube数据立方建立连接,是通过一对“列字段”来实现的,其中一个列是在事实表中,另一个列是在维度表中。<Dimension>元素有一个foreignKey属性,它是事实表中的对应的某个列的名字;<Hierarchy>元素有一个primaryKey属性。

如果层次中的数据表有一个以上,我们可以使用primaryKeyTable属性来指定主表。

column属性定义了这个层级上的key值。这个属性必须是这个层级数据库表中的一个列的名字。如果这个key值是个表达式,我们可以在Level内部使用<KeyExpression>元素来代替。下面是一个等同于上面的一个例子:

<Dimension name="Gender" foreignKey="customer_id">
<Hierarchy hasAll="true" primaryKey="customer_id">
<Table name="customer"/>
<Level name="Gender" column="gender" uniqueMembers="true">
<KeyExpression>
<SQL dialect="generic">customer.gender</SQL>
</KeyExpression>
</Level>
</Hierarchy>
</Dimension>



关于<Level>,<Measure>,<Property>元素的其他属性对应了嵌套的元素:

Parent element      Attribute        Equivalent nested element      Description

<Level>                   column            <KeyExpression>                          Key of level.

<Level>                   nameColumn    <NameExpression>                          Expression which defines the name of members of this level. If not specified, the level key is used.

<Level>                  ordinalColumn        <OrdinalExpression>             Expression which defines the order of members. If not specified, the level key is used.

<Level>                 captionColumn        <CaptionExpression>             Expression which forms the caption of members. If not specified, the level name is used.

<Level>                 parentColumn<ParentExpression>Expression by which child members reference their parent member in a parent-child hierarchy. Not specified in a regular hierarchy.

<Measure>column<MeasureExpression>SQL expression to calculate the value of the measure (the argument to the SQL aggregate function).

<Property>column<PropertyExpression>SQL expression to calculate the value of the property.


uniqueMembers属性也是用于优化SQL语句生成。如果我们知道维度表中给定的层级level列的值在父层级levels的该列值中是唯一的,就设uniqueMembers=true,否则就是false。比如,类似于[Year].[Month]的时间维度在Month层级的uniqueMembers=false,因为不同的years中会出现相同的Month。另一方面,如果我们有一个层次[product class].[product name],并且确定[product name]是唯一的,那么就可以设uniqueMembers=true。如果不确定是不是唯一的,那么通常设置为false。在顶层的level层级中,通常是为true,因为没有更高的父层级了。


highCardinality属性用于通知Mondrian,在当前dimesion维度中有未定义的,且非常大的元素。这个属性的值是true或false(默认)。当设置highCardinality=true时,执行在所有维度元素集上到动作将不能在执行了。

3.3.2 ‘all’成员

缺省情况下,每个hierarchy层次包含一个顶级层级:All,这个顶级层级包含一个单一成员:’(All {hierarchyName})’。’all’成员是hierarchy层次所有其他成员的父级,并且代表一个累计值。这个成员也是hierarchy的默认成员;也就是说,当这个层次没有包含在一个轴或切片上时,这个’all’成员用于计算单元格的值。allMemberNameallLevelName属性覆盖了所有层级和成员的缺省名字

如果在<Hierarchy>元素中设置了 hasAll=“false”,那么’all’层级就失效了。这个维度中的默认成员将会成为第一个level层级的第一个成员,举个例子,在Time层次中,将会是这个层次的第一年。改变默认成员将会被不允许,因此通常使用 hasAll=“true”.

<Hierarchy>元素也有一个defaultMember属性,以覆盖层次中的默认成员:

<Dimension name="Time" type="TimeDimension" foreignKey="time_id">
<Hierarchy hasAll="false" primaryKey="time_id" defaultMember="[Time].[1997].[Q1].[1]"/>
...


3.3.3 时间维度

基于year/month/week/day的时间维度在编码上比较特殊,因为MDX中有与时间相关的函数,比如:

ParallelPeriod([level[, index[, member]]])

PeriodsToDate([level[, member]])

WTD([member])

MTD([member])

QTD([member])

YTD([member])

LastPeriod(index[, member])

时间维度有一个属性:type=“TimeDimension”。时间维度中的层级的角色通过层级的属性levelType来

体现,这个属性可以取如下的值:

levelType  valueMeaning

TimeYearsLevel is a year

TimeQuartersLevel is a quarter

TimeMonthsLevel is a month

TimeWeeksLevel is a week

TimeDaysLevel represents days


下面是一个关于时间维度的例子:

<Dimension name="Time" type="TimeDimension">
<Hierarchy hasAll="true" allMemberName="All Periods" primaryKey="dateid">
<Table name="datehierarchy"/>
<Level name="Year" column="year" uniqueMembers="true" levelType="TimeYears" type="Numeric"/>
<Level name="Quarter" column="quarter" uniqueMembers="false" levelType="TimeQuarters"/>
<Level name="Month" column="month" uniqueMembers="false" ordinalColumn="month" nameColumn="month_name" levelType="TimeMonths" type="Numeric"/>
<Level name="Week" column="week_in_month" uniqueMembers="false" levelType="TimeWeeks"/>
<Level name="Day" column="day_in_month" uniqueMembers="false" ordinalColumn="day_in_month" nameColumn="day_name" levelType="TimeDays" type="Numeric"/>
</Hierarchy>
</Dimension>



3.3.4 level层级的出现顺序与显示效果

注意上述关于时间层次的例子中的<Level>元素中的ordinalColumnnameColumn属性,这些属性影响层级在结果中如何显示。ordinalColumn属性指明层次表中的一个列,这个列提供 指定层级中成员的顺序。nameColumn指明将显示的列。


比如,在上述Month层级中,datehierarchy层级表有month(1,…,12)和month_name(January, February, …)列。在MDX内部将被使用的列的值就是month列,因此有效的成员定义的形式是:[Time].[2005].[Q1].[1]。[Month]层级的成员将按照月份先后顺序进行呈现。


在一个父子层次中,成员都按照层次顺序进行了排序。ordinalColumn属性控制父层次中的兄弟层次的显示顺序。


序数列可以是任意的数据类型,即能用于order by的语句中。因此,在上述例子中,day_in_month列将会在每个月中循环呈现。从JDBC驱动中返回的值需为非空的java.lang.Comparable实例,当Comparable.compareTo方法被调用时,产生期望的有序结果。


Level层级包含一个type属性,可取值:"String", "Integer", "Numeric", "Boolean", "Date", “Time”和”Timestamp”。默认是Numeric,因为主键列的值通常为Numeric类型。如果是不同的类型,Mondrian需要知道正确类型,以产生正确的SQL语句。比如,字符串将会用单引号生成:WHERE productSku = ‘123-455-AA’;


3.3.5多个层次

一个维度中可以包含多个层次:

<Dimension name="Time" foreignKey="time_id">
<Hierarchy hasAll="false" primaryKey="time_id">
<Table name="time_by_day"/>
<Level name="Year" column="the_year" type="Numeric" uniqueMembers="true"/>
<Level name="Quarter" column="quarter" uniqueMembers="false"/>
<Level name="Month" column="month_of_year" type="Numeric" uniqueMembers="false"/>
</Hierarchy>
<Hierarchy name="Time Weekly" hasAll="false" primaryKey="time_id">
<Table name="time_by_week"/>
<Level name="Year" column="the_year" type="Numeric" uniqueMembers="true"/>
<Level name="Week" column="week" uniqueMembers="false"/>
<Level name="Day" column="day_of_week" type="String" uniqueMembers="false"/>
</Hierarchy>
</Dimension>



要注意的是,第一个层次没有指定名称,默认情况下,层次拥有跟其所属的维度一样的名称,因此第一个层次也叫做“Time”。


除了通过事实表中一个相同用于表连接的列 “time_id”之外,这些层次没有太多相同的地方,他们甚至连层次表都不同。将两个层次放在同一个维度中的主要原因是:这样做对于最终用户更有意义,最终用户知道,如果将“Time”层次放在一个轴上,而“Time Weekly”层次放在其他轴上,将毫无疑义。如果两个层次在相同维度下,那么MDX语言将不允许你在一个查询中同时使用这两个层次。


3.3.6 退化的维度

所谓 退化的维度,指的是一个维度太简单,以至于都没有必要为它创建一个维度表。举个例子,看看如下的事实表:

product_id   time_id   payment_method   customer_id    store_id   item_count dollars

55        20040106   Credit                      123                   22             3                   $3.54

78              20040106    Cash                        89                     22            1                    $20.00

假设我们为payment_method列上的值创建一个维度表,这个维度表毫无意义,反而会导致额外的表连接开销。

如果我们使用一个退化的维度,就可以更简单。首先声明一个不包含表的维度,Mondrian将假定这些列来自于事实表。

<Cube name="Checkout">
<!-- The fact table is always necessary. -->
<Table name="checkout">
<Dimension name="Payment method">
<Hierarchy hasAll="true">
<!-- No table element here. Fact table is assumed. -->
<Level name="Payment method" column="payment_method" uniqueMembers="true"/>
</Hierarchy>
</Dimension>
<!-- other dimensions and measures -->
</Cube>


注意,由于此处不存在表联接了,所以维度的foreignKey属性也不需要了,而且维度中的Hierarchy层次元素也不需要<Table>子元素和primaryKey属性了。


3.3.7 内联表

<InlineTable>内联表结构允许我们在Schema模式文件中定义一个数据集。我们需要声明这些列的名字,类型,以及行的集合。为了在<Table>和<View>元素中使用,还必须为这个数据集定义一个唯一的名字。下面是一个例子:

<Dimension name="Severity">
<Hierarchy hasAll="true" primaryKey="severity_id">
<InlineTable alias="severity">
<ColumnDefs>
<ColumnDef name="id" type="Numeric"/>
<ColumnDef name="desc" type="String"/>
</ColumnDefs>
<Rows>
<Row>
<Value column="id">1</Value>
<Value column="desc">High</Value>
</Row>
<Row>
<Value column="id">2</Value>
<Value column="desc">Medium</Value>
</Row>
<Row>
<Value column="id">3</Value>
<Value column="desc">Low</Value>
</Row>
</Rows>
</InlineTable>
<Level name="Severity" column="id" nameColumn="desc" uniqueMembers="true"/>
</Hierarchy>
</Dimension>


定义一个名叫severity的内联表的效果,其实等同于你在数据库中存在一个名叫“severity”的表:

如表结构和值:

iddesc

1High

2Medium

3Low

在模式文件中使用:

<Dimension name="Severity">

<Hierarchy hasAll="true" primaryKey="severity_id">

<Table name="severity"/>

<Level name="Severity" column="id" nameColumn="desc" uniqueMembers="true"/>

</Hierarchy>

</Dimension>

如果要为某行指定NULL值,忽略掉column的<Value>元素,该列的值将默认为NULL。


3.3.8 成员属性和格式

在后面,我们会提到,一个level层级的定义中,包含了成员属性和成员格式的定义。


3.3.9 近似层级基数

<Level>层级元素允许指定可选属性:approxRowCount,指定这个属性能通过减少对层级,层次和维度基数的需求,达到改善效果的目标。这在通过XMLA连接到Mondrian时有重要影响。


3.3.10 缺省的度量属性

<Cube> 和 <VirtualCube> 元素允许指定可选属性:defaultMeasure。

在<Cube> 元素中指定defaultMeasure,用户能显式指定任意基本度量作为默认度量;

在 <VirtualCube>元素中指定,用户能显式指定任意VirtualCube度量作为默认度量。


需要注意的是:如果没有指定默认度量,那么将用cube数据立方中的第一个度量作为默认度量。而在virtual cube虚拟数据立方中,将用虚拟数据立方中定义的第一个cube立方中的第一个base  measure基本度量作为其默认度量。


显式指定defaultMeasure属性值,在选择一个计算得出的成员作为默认度量时,变得很有用。要实现这个目标,这个计算得出的成员需要在其中一个基本数据立方中定义,并在虚拟数据立方中指定为defaultMeasure。

<Cube name="Sales" defaultMeasure="Unit Sales">

...

<CalculatedMember name="Profit" dimension="Measures">

<Formula>[Measures].[Store Sales] - [Measures].[Store Cost]</Formula>

...

</CalculatedMember>

</Cube>

<VirtualCube name="Warehouse and Sales" defaultMeasure="Profit">

...

<VirtualCubeMeasure cubeName="Sales" name="[Measures].[Profit]"/>

</VirtualCube>


3.3.11 功能性依赖优化

在某些情况下,利用即将被处理的数据间的功能性依赖,可以进行效率优化。这些依赖通常是由业务规则产生的,且与生成这些数据的系统联系在一起,并通常不能通过数据本身进行推测。


功能性依赖在Mondrian中是通过<Property>元素的dependsOnLevelValue属性和<Hierarchy>元素的uniqueKeyLevelName属性来声明。

<Property>元素的dependsOnLevelValue属性用于表明成员属性的值是功能性依赖于<Level>的值,而成员属性就定义在这个<Level>中。也就是说,对于一个level层级的给定值,这个属性值是不变的。

<Hierarchy>元素的uniqueKeyLevelName属性用于表明在hierarchy层次中跟所有更高层的层级一起获得的给定level层级,相当于一个唯一的替换key值,以确保对于任意唯一的这些level层级值的联系,只有。。。


为了说明,可以想象一个层次,构造了美国的汽车制造和汽车牌照:

<Dimension name="Automotive" foreignKey="auto_dim_id">

<Hierarchy hasAll="true" primaryKey="auto_dim_id" uniqueKeyLevelName="Vehicle Identification Number">

<Table name="automotive_dim"/>

<Level name="Make" column="make_id" type="Numeric"/>

<Level name="Model" column="model_id" type="Numeric"/>

<Level name="ManufacturingPlant" column="plant_id" type="Numeric"/>

<Property name="State" column="plant_state_id" type="Numeric" dependsOnLevelValue="true"/>

<Property name="City" column="plant_city_id" type="Numeric" dependsOnLevelValue="true"/>

<Level name="Vehicle Identification Number" column="vehicle_id" type="Numeric"/>

<Property name="Color" column="color_id" type="Numeric" dependsOnLevelValue="true"/>

<Property name="Trim" column="trim_id" type="Numeric" dependsOnLevelValue="true"/>

<Level name="LicensePlateNum" column="license_id" type="String"/>

<Property name="State" column="license_state_id" type="Numeric" dependsOnLevelValue="true"/>

</Hierarchy>

</Dimension>


在上述例子中,我们知道一个给定的制造企业只存在于唯一的一个城市和州,而一辆汽车有一个颜色模式和一个修理维度,且牌照编号与唯一的州相互联系。因此,我们可以表明,所有这些成员属性都是功能性依赖于这些层级的值。


3.3.12 表格的Hint 提示

Mondrian支持对<Table>元素的有限的数据库特征的hint提示,这些提示会传递导包含这些表格的SQL语句中。这类hints包括:

DatabaseHint TypePermitted ValuesDescription

MySQLforce_indexThe name of an index on this tableForces the named index to be used when selecting level values from this table.

比如:

<Table name="automotive_dim">

<Hint type="force_index">my_index</Hint>

</Table>

与功能性依赖优化一起,支持表格hints提示是在一个传统阶段,在Mondrian4.0中会有所变化。任何使用了表格hints提示的schema模式文件可能会需要修改,以匹配新的模式文件的语法规则。