Mondrian是一個開放源代碼的Rolap服務器,使用java開發的。它實現了xmla和jolap規范,而且自定義了一種使用mdx語言的客戶端接口。Mondrian是olap服務器,而不是數據倉庫服務器,因此Mondrian的元數據主要包括olap建模的元數據,不包括從外部數據源到數據庫轉換的元數據。也就是說Mondria的元數據僅僅包括了多維邏輯模型,從關系型數據庫到多維邏輯模型的映射,存取權限等信息。在功能上,Mondrian支持共享維和成員計算,支持星型模型和雪花模型的功能。
Mondrian中使用物理的xml文件存儲元數據,它的設計者規定了xml文件的格式。下面簡單介紹一下它是如何存儲元數據的。
Element Description
根元素
<Schema> Collection of Cubes, Virtual cubes, Shared dimensions, and Roles.
邏輯元素
<Cube> A collection of dimensions and measures, all centered on a fact table.
<VirtualCube> A cube defined by combining the dimensions and measures of one or more cubes.
<Dimension>
<DimensionUsage> Usage of a shared dimension by a cube.
<Hierarchy>
<Level>
<Property>
<Measure>
物理元素
<Table> Fact- or dimension table.
<View> Defines a 'table' using a SQL query, which can have different variants for different underlying databases.
<Join> Defines a 'table' by joining a set of queries.
存取控制
<Role> An access-control profile.
<SchemaGrant> A set of rights to a schema.
<CubeGrant> A set of rights to a cube.
<HierarchyGrant> A set of rights to a hierarchy and levels within that hierarchy.
<MemberGrant> A set of rights to a member and its children.
其他
<Parameter>
<Table>
<Table>
一個模式定義一個多維數據庫,它包括一個邏輯模型,由立方體,層次,成員和邏輯模型到物理模型的映射構成。一個邏輯模型由可以用MDX語言來查詢。Mondrain的模型由xml文件來描述。現在創建模式的唯一途徑是用文本編輯a器編輯xml文件。Xml的語法不是太復雜,因此沒有想象中的那么難。目前正在開發一個圖形界面的程序來創建和修改模式。
一個模式最重要的組成部分是立方體,度量和維:在一個主題域中立方體是維和度量的集合。一個度量是一個可測量的數值,比如產品銷售的數量或者詳細清單的價格
一個維是一個屬性或者是屬性的集合, 通過維你可以將度量劃分到字類中。比如:你希望將銷售產品按顏色,顧客性別,售出的商店分為八個部分,那么顏色,性別,商店都是維。
下面是一個簡單的模型定義的例子:
<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="#,###.##"/>
</Cube>
</Schema>
這個模型包含了一個銷售cube,這個cube有兩個維,時間和性別維;兩個度量,銷售數量和銷售總額。
我們可以在這個模型上寫一個 MDX 查詢:
select {[Measures].[Unit Sales], [Measures].[Store Sales]} on columns,
{[Time].[1997].[Q1].descendants} on rows
from [Sales]
where [Gender].[F]
這 個查詢涉及到了銷售立方體, 每一個維 [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
下面詳細地介紹一下模式定義:
一個立方體是一個或者多個維和度量的集合,通常是一個事實表,這里是 ‘sales_fact_1997". 事實表保存了需要計算的列和包含維的參考表.
<Cube name="Sales">
<Table name="sales_fact_1997"/>
...
</Cube>
這里用 <Table> 元素定義事實表. 如果事實表 不在默認的模式中, 你可以用"schema"屬性指定一個明確地模式,例如:
<Table schema="foodmart" name="sales_fact_1997"/>
你也可以利用 <View> 和 <Join> 結構來創建更復雜的sql .
度量
銷售立方體定義了兩個維 "Unit Sales" 和 "Store Sales".
<Measure name="Unit Sales" column="unit_sales"
aggregator="sum" formatString="#,###"/>
<Measure name="Store Sales" column="store_sales"
aggregator="sum" formatString="#,###.00"/>
每個度量有一個名字,對應事實表中的一列, 采用一個聚集函數 (usually "sum").
一個可選的格式字符串指定了值如何被打印. 這里我們選擇銷售數量不帶小數的輸出(因為銷售數量是整數) ,銷售總額帶2位小數 . 符號',' 和 '.' 是對地區敏感的, 因此如果是在意大利運行, 銷售總額可能會出現 "48.123,45". 你可以用 advanced format strings來實現更嚴格的效果.度量值不是從列中來的,而是從立方體的單元中來的
維
性別維由單一的層次組成,僅有一層。
<Dimension name="Gender" foreignKey="customer_id">
<Hierarchy hasAll="true" primaryKey="customer_id">
<Table name="customer"/>
<Level name="Gender" column="gender" uniqueMembers="true"/>
</Hierarchy>
</Dimension>
對于任意給定的銷售, 性別維是指購買改產品的客戶的性別. 它通過連接事實表"sales_fact_1997.customer_id"和維表"customer.customer_id"
來表示 。"gender" 包括兩個值, 'F' 和 'M', 因此性別維包含的成員: [Gender].[F] and [Gender].[M]. 因為 hasAll="true", 系統產生一個特別的 'all' 層, 僅包括一個成員 [All Genders].
一個維可以包含多個層次:
<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"。在一個維上存在兩個層次的原因是這樣對最終用戶是有用的. 如果一個維上存在兩個層次, MDX會強制不允許在一個查詢中同時用到他們.
A dimension can live in the fact table:
<Cube name="Sales">
<Table name="sales_fact_1997"/>
...
<Dimension name="Payment method">
<Hierarchy hasAll="true">
<Level name="Payment method" column="payment_method" uniqueMembers="true"/>
</Hierarchy>
</Dimension>
</Cube>
每個維包含有多層組成的一個層次,
大多數維都是僅有一個層次,但有時候一個維有多個層次。比如:你可能希望在時間維上從天聚集到月,季度和年;或者從天聚集到周和年。這兩種層次都是從天到年,但是聚集的路徑不同。大多數層次有全成員,全成員包括層次的所有成員,因此能夠代表他們的總合。它通常命名為'All something',比如:'All stores'.
星型模式和雪花模式
mondrian支持星型模式和雪花模式。下面介紹一下雪花模式的建模,它需要用到操作符 <Join>.比如:
<Cube name="Sales">
...
<Dimension name="Product" foreignKey="product_id">
<Hierarchy hasAll="true" primaryKey="product_id" primaryKeyTable="product">
<Join leftKey="product_class_id" rightAlias="product_class" rightKey="product_class_id">
<Table name="product"/>
<Join leftKey="product_type_id" rightKey="product_type_id">
<Table name="product_class"/>
<Table name="product_type"/>
</Join>
</Join>
...
</Hierarchy>
</Dimension>
</Cube>
這里定義一個 "Product" 維 由三個表構成. 事實表連接 表"product" (通過外鍵 "product_id"),表"product"連接表"product_class" (通過外鍵 "product_class_id"),表"product_class"連接表 "product_type" (通過外鍵 "product_type_id"). 我們利用 <Join> 元素的循環嵌套, <Join>帶有兩個操作對象; 操作對象可能是表,連接或者查詢 。
按照操作對象行的數目來安排次序,表 "product" 的行數最大, 因此它首先出現連接事實表;然后是表 "product_class"和 "product_type",在雪花的末端擁有的行數最小.
注意外部元素 <Join>有一個屬性 rightAlias. 這是必要的,因為join 的右邊(是內部元素 <Join> ) 有可能是許多表組成的.這種情況下不需要屬性leftAlias,因為列 leftKey 很明確的來自表 "product".
共享維
當為一個連接生成SQL的時候, mondrian 需要知道連接哪一個列. 如果一正在連接一個多表連接, 你需要告訴它連接這些表里的哪一個表,哪一個列.
因為共享維不屬于一個cube,你必須給它們一個明確的表 (或者數據源). 當你在一個特別的cube里用他們的時候, 你要指定外鍵 foreign key. 下面的例子顯示了 Store Type 維被 連接到 Sales cube ,用了外鍵 sales_fact_1997.store_id, 并且被連接到Warehouse cube ,用了外鍵 warehouse.warehouse_store_id :
<Dimension name="Store Type">
<Hierarchy hasAll="true" primaryKey="store_id">
<Table name="store"/>
<Level name="Store Type" column="store_type" uniqueMembers="true"/>
</Hierarchy>
</Dimension>
<Cube name="Sales">
<Table name="sales_fact_1997"/>
...
<DimensionUsage name="Store Type" source="Store Type" foreignKey="store_id"/>
</Cube>
<Cube name="Warehouse">
<Table name="warehouse"/>
...
<DimensionUsage name="Store Type" source="Store Type" foreignKey="warehouse_store_id"/>
</Cube>
虛擬 cubes
父子層次
一個使用方便的層次 有一個嚴格的層的集合, 成員與層緊密的聯系.比如,在 Product 層次中, 任何產品名稱層的成員在商標層上都有一個父親 ,商標層上的成員在產品子目錄層也都有一個父親. 這種結構對于現實世界中的數據有時候太嚴格了.
一個父子層次只有一層 (不計算 'all' 層), 但是任何成員可以在同一層上有父親成員. 一個典型的例子是Employees 層次:
<Dimension name="Employees" foreignKey="employee_id">
<Hierarchy hasAll="true" allMemberName="All Employees" primaryKey="employee_id">
<Table name="employee"/>
<Level name="Employee Id" uniqueMembers="true" type="Numeric"
column="employee_id" nameColumn="full_name"
parentColumn="supervisor_id" nullParentValue="0">
<Property name="Marital Status" column="marital_status"/>
<Property name="Position Title" column="position_title"/>
<Property name="Gender" column="gender"/>
<Property name="Salary" column="salary"/>
<Property name="Education Level" column="education_level"/>
<Property name="Management Role" column="management_role"/>
</Level>
</Hierarchy>
</Dimension>
這里parentColumn 和nullParentValue是重要的屬性:
屬性parentColumn 是一個成員連接到它父親成員的列名。在這種情況下, 它是指向雇員經理的外鍵。元素<Level>的子元素 <ParentExpression> 是與屬性 parentColumn 有相同作用的,但是元素允許定義任意的SQL表達式, 就像元素 <Expression>. 屬性 parentColumn (或者 元素<ParentExpression>) 是維一向Mondrian指出 層次有父子結構的。
屬性 nullParentValue 是指明成員沒有父成員的值 。 缺省情況下 nullParentValue="null", 但是因為許多數據庫不支持null, 建模時 用其他值來代替空值,0和-1.
物理結構
member reade
member reader 是訪問成員的方法. 層次通常以維表為基礎建立的 , 因此要用sql來構造.但是甚至你的數據沒有存在于 RDBMS, 你可以通過一個 Java 類來訪問層次。(自定義 member reader)
Here are a couple of examples:
DateSource (to be written)生成一個時間層次. 按常規,數據倉庫工具生成一個表 ,每天包含一行。但是問題是這個表需要裝載,并且隨著時間的變化能夠添加更多的行。 DateSource 在內存中按照要求生成日期成員.
FileSystemSource (to be written) 按照目錄和文件的層次描述文件系統。 Like the time hierarchy created by DateSource, this is a virtual hierarchy: the member for a particular file is only created when, and if, that file's parent directory is expanded.
ExpressionMemberReader (to be written) 創建了一個基于表達式的層次。
自定義member reader 必須實現接口 mondrian.rolap.MemberSource. 如果你需要實現一個更大的成員操作集合, 需要實現接口 interface mondrian.rolap.MemberReader; 否則, Mondrian在 mondrian.rolap.CacheMemberReader中封裝 你的 reader類.你的 member reader 必須有一個公共的構造函數,這個構造函數擁有參數(Hierarchy,Properties),拋出未檢查的錯誤.
Member readers 用 元素<Hierarchy> 的屬性memberReaderClass來聲明; 任何 <Parameter> 子元素通過屬性構造函數來傳遞.
這是一個例子:
<Dimension name="Has bought dairy">
<Hierarchy hasAll="true" memberReaderClass="mondrian.rolap.HasBoughtDairySource">
<Level name="Has bought dairy" uniqueMembers="true"/>
<Parameter name="expression" value="not used"/>
</Hierarchy>
</Dimension>
Cell readers
<Measure name="name" cellReaderClass="com.foo.MyCellReader">
類 "com.foo.MyCellReader" 實現了接口interface mondrian.olap.CellReader.
存取控制
可以定義存取控制的屬性(角色), 作為模式的一部分, 并且可以在建立連接的時候設置角色。
定義角色
角色可以通過 元素<Role>來設置 , 它是元素<Schema> 的直接的子元素.
下面是一個關于角色的例子:
<Role name="California manager">
<SchemaGrant access="none">
<CubeGrant cube="Sales" access="all">
<HierarchyGrant hierarchy="[Store]" access="custom" topLevel="[Store].[Store Country]">
<MemberGrant member="[Store].[USA].[CA]" access="all"/>
<MemberGrant member="[Store].[USA].[CA].[Los Angeles]" access="none"/>
</HierarchyGrant>
<HierarchyGrant hierarchy="[Customers]" access="custom" topLevel="[Customers].[State Province]" bottomLevel="[Customers].[City]">
<MemberGrant member="[Customers].[USA].[CA]" access="all"/>
<MemberGrant member="[Customers].[USA].[CA].[Los Angeles]" access="none"/>
</HierarchyGrant>
<HierarchyGrant hierarchy="[Gender]" access="none"/>
</CubeGrant>
</SchemaGrant>
</Role>
元素 <SchemaGrant> 定義了模式中缺省的對象方問權限. 訪問屬性可以是 "all" 或者 "none"; 這個屬性可以被具體的權限對象繼承. 在這個例子中, 因為 access="none", 用戶只能瀏覽"Sales" 立方體, 這里明確的賦予了這個權限.
元素 <CubeGrant> 定義了立方體的訪問權限. 就像 <SchemaGrant>, 屬性access 可以是"all" 或者 "none", 并且能夠被cube中具體的子對象繼承.
元素 <HierarchyGrant>定義了層次的訪問權限. 屬性access 可以是"all", 意思是所有的members都是可見的; "none",意思是 hierarchy的存在對用戶是隱藏的; "custom", 你可以利用屬性 topLevel 定義可見的最高層 (阻止用戶 進行上卷操作, 比如瀏覽稅收 上卷到 Store Country 層); 或者用屬性 bottomLevel 定義可見的最底層 (這里阻止用戶查看顧客個人的細節數據);或者控制用戶查看哪一個成員集合,通過嵌套定義元素 <MemberGrant>.
你也可以只定義元素 <MemberGrant> ,如果模式的<HierarchyGrant> 有屬性access="custom". Member grants 賦予 (或者取消) 訪問給定的成員, 以及它的所有子成員.
posted on 2007-09-06 22:30
扭曲的鉛筆 閱讀(673)
評論(0) 編輯 收藏 所屬分類:
BI