Mondrian:建模多值维度属性
聚合類型:平均
一位名叫布魯諾的生動讀者最近在閱讀了我關于橋牌表的文章之后聯系了我:他正在尋找一個具有挑戰性的場景的解決方案?任務是為學生創建一個模型,為他們參加的課程取得成績。學生可以有一個或多個愛好,其中一個分析問題是:有愛好X的學生參加Y課程的平均成績是多少?這引起了我的興趣,我很想知道如何用Mondrian實現這一點。
在我們的示例中,我們使用以下數據:
- 學生鮑勃參加了數學課程并獲得了7分(成績)。他還參加了物理課程并獲得了3分(成績)。鮑勃的愛好是游戲和閱讀。
- 學生Lilian參加了數學課程并獲得了8分(成績)。她的愛好是游戲,慢跑和寫作。
雖然我有一些想法,但只有與Nelson Sousa的談話才能找到一個可行的解決方案:他建議創建兩個單獨的事實表,一個存儲每個學生每個課程的成績(當然你也會有一個約會,但我們為了簡單而忽略它清酒)。另一個事實表只存儲學生和愛好關系。后者不一定必須在事實表本身中有一個度量,但是,為了完整起見我添加了一個(值的常量1)。最后,有一個學生維度作為兩個事實表之間的鏈接:
multivalued.dim_student:
| 1 | 短發 |
| 2 | 莉蓮 |
multivalued.fact_grades:
| 1 | 數學 | 7 |
| 1 | 數學 | 4 |
| 1 | 物理 | 3 |
| 2 | 數學 | 8 |
multivalued.fact_student_hobbies:
| 1 | 賭博 | 1 |
| 1 | 讀 | 1 |
| 2 | 賭博 | 1 |
| 2 | 跑步 | 1 |
| 2 | 寫作 | 1 |
創建標準多維數據集以回答簡單的問題
這里重要的一點是,我們希望使用平均類型的聚合函數(因為成績不能求和):
立方體定義:
<Schema name="Multivalued Dimension Attribute"><Dimension type="StandardDimension" name="Student"><Hierarchy name="Student Name" hasAll="true" primaryKey="student_tk"><Table name="dim_student" schema="multivalued"/><Level name="Student Name" column="student_name" type="String" uniqueMembers="true" levelType="Regular"/></Hierarchy></Dimension><Dimension type="TimeDimension" name="Date"><Hierarchy name="Date" hasAll="true" primaryKey="date_tk"><Table name="dim_date" schema="multivalued"/><Level name="Date" column="the_date" type="Date" uniqueMembers="true" levelType="TimeDays"/></Hierarchy></Dimension><Cube name="Grades" cache="true" enabled="true"><Table name="fact_grades" schema="multivalued"/><Dimension type="StandardDimension" name="Course Name"><Hierarchy name="Course Name" hasAll="true"><Level name="Course Name" column="course_name" type="String" uniqueMembers="false" levelType="Regular"></Level></Hierarchy></Dimension><DimensionUsage source="Student" name="Student" foreignKey="student_tk"/><Measure name="Grade" column="grade" datatype="Integer" aggregator="avg"/></Cube><Cube name="Hobbies" cache="true" enabled="true"><Table name="fact_student_hobbies" schema="multivalued"/><Dimension type="StandardDimension" name="Hobby Name"><Hierarchy name="Hobby Name" hasAll="true"><Level name="Hobby Name" column="hobby_name" type="String" uniqueMembers="false" levelType="Regular"></Level></Hierarchy></Dimension><DimensionUsage source="Student" name="Student" foreignKey="student_tk"/><Measure name="Count Hobbies" column="cnt" datatype="Integer" formatString="#,###" aggregator="sum"/></Cube> </Schema>我們為每個事實表創建了一個多維數據集來回答具體問題:
問:學生的平均成績是多少?
SELECT[Student.Student Name].Children ON ROWS, [Measures].[Grade] ON COLUMNS FROM [Grades]結果:
| 短發 | 4.667 |
| 莉蓮 | 8 |
問:課程的平均成績是多少?
SELECT[Course Name].Children ON ROWS, [Measures].[Grade] ON COLUMNS FROM [Grades]結果:
| 數學 | 6.333 |
| 物理 | 3 |
問:有多少學生將游戲作為業余愛好?
SELECTNON EMPTY [Student.Student Name].Members ON ROWS, [Measures].[Count Hobbies] ON COLUMNS FROM [Hobbies] WHERE[Hobby Name].[Gaming]結果:
| 所有學生。學生姓名 | 2 |
| 短發 | 1 |
| 莉蓮 | 1 |
創建虛擬多維數據集以回答復雜問題
然后我們可以創建一個虛擬多維數據集來回答跨越兩個事實表的問題。我們將這個立方體稱為Grades and Hobbies。
我建議閱讀虛擬多維數據集上的官方?Mondrian Docu,了解如何構建虛擬多維數據集。
虛擬多維數據集:如何加入基礎多維數據集
為此目的使用全局(符合)維度。在我們的例子中,Student維度鏈接兩個事實表,并定義為全局維度。
<VirtualCubeDimension name="Student"/>重要說明:請注意,對于公共維度,我們不定義cubeName屬性值。
問:這實際上是否也需要定義,CubeUsage因為在這種情況下VirtualCubeDimension元素沒有為cubeName?指定值?否則,Mondrian如何知道這個全局維度存在于兩個基礎多維數據集中,并且因此可以使用它來加入基礎多維數據集?
答:CubeUsage是可選的,不是必需的。如果你在引用一個全球性虛擬多維數據集,蒙德里安將檢查所定義的基礎多維數據虛擬措施,看看這個全球層面是在引用的基礎多維數據集。
完整虛擬多維數據集定義:
<VirtualCube name="Grades and Hobbies" enabled="true"><!-- common dimensions --><VirtualCubeDimension name="Student"/><!-- specific dimensions --><VirtualCubeDimension name="Course Name" cubeName="Grades"/><VirtualCubeDimension name="Hobby Name" cubeName="Hobbies"/><VirtualCubeMeasure name="[Measures].[Count Hobbies]" cubeName="Hobbies"/><VirtualCubeMeasure name="[Measures].[Grade]" cubeName="Grades"/> </VirtualCube>讓我們創建一個有愛好數量和平均成績的學生列表:
SELECT[Student.Student Name].Children ON ROWS, {[Measures].[Grade], [Measures].[Count Hobbies]} ON COLUMNS FROM [Grades and Hobbies]| 短發 | 4.667 | 2 |
| 莉蓮 | 8 | 3 |
以下結果顯示了一個非常有趣的結果:愛好的數量僅在所有級別上可用,但是各個級別都可用:
SELECT[Student.Student Name].Members * [Course Name].Members ON ROWS, {[Measures].AllMembers} ON COLUMNS FROM [Grades and Hobbies]| 所有學生。學生姓名 | 所有課程名稱 | 五 | 5.5 |
| ? | 數學 | ? | 6.333 |
| ? | 物理 | ? | 3 |
| 短發 | 所有課程名稱 | 2 | 4.667 |
| ? | 數學 | ? | 5.5 |
| ? | 物理 | ? | 3 |
| 莉蓮 | 所有課程名稱 | 3 | 8 |
| ? | 數學 | ? | 8 |
| ? | 物理 | ? | ? |
這是有道理的,因為愛好的數量只能在一個All Courses級別上提供,因為我們當然不存儲它們!
讓我們得到一個以游戲為業余愛好的學生名單:
SELECTFILTER([Student.Student Name].Children, ([Hobby Name].[Gaming], [Measures].[Count Hobbies] ) > 0 ) ON ROWS, {} ON COLUMNS FROM [Grades and Hobbies]結果:
| 短發 |
| 莉蓮 |
問:Hobby的平均成績是多少?
SELECT[Course Name].Members ON ROWS, {[Measures].[Grade]} ON COLUMNS FROM [Grades and Hobbies]| 數學 | 6.333 |
| 物理 | 3 |
學習練習
讓我們回過頭來了解一些基礎知識:注意WHERE以下查詢中的slicer():
WITH SET STUDENTS AS FILTER([Student.Student Name].Children, ([Hobby Name].[Reading], [Measures].[Count Hobbies] ) > 0 ) SELECTSTUDENTS ON ROWS, {[Measures].[Grade]} ON COLUMNS FROM [Grades and Hobbies] WHERE [Course Name].[Course Name].[Math]有趣的是,我們沒有得到任何記錄!但是,如果我們將限制從切片器移動到其中一個軸,那么一切都很好:
WITH SET STUDENTS AS FILTER([Student.Student Name].Children, ([Hobby Name].[Reading], [Measures].[Count Hobbies] ) > 0 ) SELECTSTUDENTS * [Course Name].[Course Name].[Math] ON ROWS, {[Measures].[Grade]} ON COLUMNS FROM [Grades and Hobbies]結果:
| 短發 | 數學 | 5.5 |
這樣做的原因是切片器也直接影響計算成員和集合,而如果我們將約束移動到軸之一上,則計算成員和集合將在沒有此約束的情況下進行評估。
或者,您也可以將All成員添加到過濾器以覆蓋切片器中的約束:
WITH SET STUDENTS AS FILTER([Student.Student Name].Children, ([Hobby Name].[Reading], [Course Name].[All Course Names], [Measures].[Count Hobbies] ) > 0 ) SELECTSTUDENTS ON ROWS, {[Measures].[Grade]} ON COLUMNS FROM [Grades and Hobbies] WHERE [Course Name].[Course Name].[Math]這將產生完全相同的結果。
接下來讓我們看一下原始問題:
問:參加數學課程并將游戲作為業余愛好的學生的平均成績是多少?
此查詢返回所有對游戲感興趣并參加數學課程的學生:
WITH SET STUDENTS AS FILTER([Student.Student Name].Children, ([Hobby Name].[Gaming], [Measures].[Count Hobbies] ) > 0 ) SELECTSTUDENTS * [Course Name].[Course Name].[Math] ON ROWS, {[Measures].[Grade]} ON COLUMNS FROM [Grades and Hobbies]| 短發 | 數學 | 5.5 |
| 莉蓮 | 數學 | 8 |
我們現在嘗試回答原始問題:
WITH SET STUDENTS AS FILTER([Student.Student Name].Children, ([Hobby Name].[Gaming], [Course Name].[All Course Names], [Measures].[Count Hobbies] ) > 0 ) SELECTSTUDENTS ON ROWS, {[Measures].[Grade]} ON COLUMNS FROM [Grades and Hobbies] WHERE [Course Name].[Course Name].[Math]這里的訣竅是在獲得課程成績之前獲得具有特定愛好的學生列表。另外,請注意我們將Math課程的約束移動到切片器(WHERE子句)中。由于這也影響了計算集,我們也必須明確地添加[Course Name].[All Course Names]它。
結果:
| 短發 | 5.5 |
| 莉蓮 | 8 |
聚合類型:SUM
在這個主題的變化中,我們想象我們是一個銷售各種商品的公司。該客戶有不同的利益,我們希望看到多少收入,我們產生的用戶興趣。我們不想權衡利益?- 我們將所有收入分配給每一個利益。目的是找出哪些利息產生了大部分收入(好吧,我們不會在這里做到這一點,但你會得到這個想法)。
multivalued.dim_client:
client_tk | client_name -----------+-------------1 | Joe2 | Susan3 | Timmultivalued.fact_client_interests:
client_tk | interest_name | cnt -----------+---------------+-----1 | Fishing | 11 | Photography | 11 | Cooking | 12 | Cooking | 12 | Biology | 13 | Geography | 13 | Photography | 13 | Cooking | 1multivalued.dim_product:
product_tk | product_name | unit_price ------------+--------------+------------1 | AAA | 2.002 | BBB | 3.003 | CCC | 1.40multivalued.dim_date:
date_tk | the_date ----------+------------20170324 | 2017-03-24multivalued.fact_sales:
date_tk | client_tk | product_tk | no_of_units | amount_spent ----------+-----------+------------+-------------+--------------20170324 | 1 | 1 | 2 | 420170324 | 2 | 1 | 3 | 620170324 | 1 | 2 | 4 | 1220170324 | 2 | 2 | 2 | 620170324 | 3 | 2 | 3 | 920170324 | 2 | 3 | 2 | 2.820170324 | 3 | 3 | 1 | 1.4多維數據集定義:在這種情況下,客戶端是我們的全局維度,它鏈接兩個多維數據集(銷售和興趣)。設置很簡單,所以我不會詳細說明:
<Schema name="Multivalued Dimension Attribute"><Dimension type="TimeDimension" name="Date"><Hierarchy name="Date" hasAll="true" primaryKey="date_tk"><Table name="dim_date" schema="multivalued"/><Level name="Date" column="the_date" type="Date" uniqueMembers="true" levelType="TimeDays"/></Hierarchy></Dimension><Dimension type="StandardDimension" name="Product"><Hierarchy name="Product Name" hasAll="true" primaryKey="product_tk"><Table name="dim_product" schema="multivalued"/><Level name="Product Name" column="product_name" type="String" uniqueMembers="true" levelType="Regular"/></Hierarchy></Dimension><Dimension type="StandardDimension" name="Client"><Hierarchy name="Client Name" hasAll="true" primaryKey="client_tk"><Table name="dim_client" schema="multivalued"/><Level name="Client Name" column="client_name" type="String" uniqueMembers="true" levelType="Regular"/></Hierarchy></Dimension><Cube name="Sales" cache="true" enabled="true"><Table name="fact_sales" schema="multivalued"/><DimensionUsage source="Date" name="Date" foreignKey="date_tk"/><DimensionUsage source="Client" name="Client" foreignKey="client_tk"/><DimensionUsage source="Product" name="Product" foreignKey="product_tk"/><Measure name="Number of Units" column="no_of_units" datatype="Integer" formatString="#,###" aggregator="sum"/><Measure name="Revenue" column="amount_spent" datatype="Numeric" formatString="#,###.00" aggregator="sum"/></Cube><Cube name="Interests" cache="true" enabled="true"><Table name="fact_client_interests" schema="multivalued"/><Dimension type="StandardDimension" name="Interest Name"><Hierarchy name="Interest Name" hasAll="true"><Level name="Interest Name" column="interest_name" type="String" uniqueMembers="true" levelType="Regular"/></Hierarchy></Dimension><DimensionUsage source="Client" name="Client" foreignKey="client_tk"/><Measure name="Count Interests" column="cnt" datatype="Integer" formatString="#,###" aggregator="sum"/></Cube><VirtualCube name="Sales and Interests" enabled="true"><!-- common dimensions --><VirtualCubeDimension name="Client"/><!-- specific dimensions --><VirtualCubeDimension name="Date" cubeName="Sales"/><VirtualCubeDimension name="Product" cubeName="Sales"/><VirtualCubeDimension name="Interest Name" cubeName="Interests"/><VirtualCubeMeasure name="[Measures].[Number of Units]" cubeName="Sales"/><VirtualCubeMeasure name="[Measures].[Revenue]" cubeName="Sales"/><VirtualCubeMeasure name="[Measures].[Count Interests]" cubeName="Interests"/></VirtualCube> </Schema>我們為每個事實表創建了一個多維數據集來回答具體問題:
問:我們產品的收入是多少?
SELECT[Product.Product Name].Children ON ROWS, {[Measures].[Number of Units], [Measures].[Revenue]} ON COLUMNS FROM [Sales]| AAA | 五 | 10.00 |
| BBB | 9 | 27.00 |
| CCC | 3 | 4.20 |
問:我們為每位用戶帶來多少收入?
select [Client.Client Name].Children ON ROWS, {[Measures].[Number of Units], [Measures].[Revenue]} ON COLUMNS FROM [Sales]| 喬 | 6 | 16.00 |
| 蘇珊 | 7 | 14.80 |
| 蒂姆 | 4 | 10.40 |
問:有多少客戶對烹飪感興趣?
SELECTNON EMPTY [Client.Client Name].Members ON ROWS, [Measures].[Count Interests] ON COLUMNS FROM [Interests] WHERE[Interest Name].[Cooking]| 所有Client.Client名稱 | 3 |
| 喬 | 1 |
| 蘇珊 | 1 |
| 蒂姆 | 1 |
我們還創建了一個虛擬立方體來回答涉及兩個立方體的問題。
問:用戶對攝影有多大興趣?
讓我們先獲得相關客戶的列表:
SELECTFILTER([Client.Client Name].Children, ([Interest Name].[Interest Name].[Photography], [Measures].[Count Interests] ) > 0 ) ON ROWS, {} ON COLUMNS FROM [Sales and Interests]然后構造最終查詢:
WITH SET CLIENTS AS FILTER([Client.Client Name].Children, ([Interest Name].[Interest Name].[Photography], [Product.Product Name].[All Product.Product Names], [Measures].[Count Interests] ) > 0 ) SELECTCLIENTS ON ROWS, {[Measures].[Revenue]} ON COLUMNS FROM [Sales and Interests] WHERE [Product.Product Name].[Product Name].[AAA]| 喬 | 4.00 |
| 蒂姆 | ? |
有效措施
在某些情況下,您可能希望顯示數字,即使在當前選擇中它們不可用。拿這個senario:
當我們選擇Date,Client而且Product Name我們可以看到值Number of Units和Revenue,但不適用于Count Interests:
?
如果我們想要查看Count Interests數字,但必須選擇Client Name和Interest作為維度,但在這種情況下Number of Units并且Revenue是空的:
?
現在讓我們假設我們想要顯示最接近的Number of Units,Revenue在這種情況下,我們如何實現這一點。我們知道最接近的可用數字是總數Client Name,所以基本上這個數字會重復幾次。如果這確實是可以接受的行為,那么與業務用戶一起確認是值得的。
要實現此操作,請將原始虛擬度量設置為不可見,并使用函數在虛擬多維數據集中創建計算成員,這些函數應引用原始虛擬度量。它應該是這樣的:ValidMeasure()
<VirtualCube name="Sales and Interests" enabled="true"><!-- common dimensions --><VirtualCubeDimension name="Client"/><!-- specific dimensions --><VirtualCubeDimension name="Date" cubeName="Sales"/><VirtualCubeDimension name="Product" cubeName="Sales"/><VirtualCubeDimension name="Interest Name" cubeName="Interests"/><VirtualCubeMeasure name="[Measures].[Number of Units]" cubeName="Sales" visible="false"/><VirtualCubeMeasure name="[Measures].[Revenue]" cubeName="Sales" visible="false"/><VirtualCubeMeasure name="[Measures].[Count Interests]" cubeName="Interests"/><CalculatedMember name="No of Units" dimension="Measures"><Formula><![CDATA[ValidMeasure([Measures].[Number of Units])]]></Formula></CalculatedMember><CalculatedMember name="Total Revenue" dimension="Measures"><Formula><![CDATA[ValidMeasure([Measures].[Revenue])]]></Formula></CalculatedMember> </VirtualCube>基于此新虛擬多維數據集的報告將如下所示:
?
在Joe的例子中,我們知道他對烹飪,釣魚和攝影很感興趣,總共購買了6個單位,總收入為16。
虛擬多維數據集:非規范化事實表
虛擬立方體依賴于全局維度,但是,如果您處理非規范化事實表,則可能使用退化維度。那么這是否意味著您無法為它們創建虛擬多維數據集?不完全的。你可以欺騙系統:
只需為每個簡并表(例如vw_dim_location)創建一個視圖,并在全局dim的表引用中使用它。
總結
以上是生活随笔為你收集整理的Mondrian:建模多值维度属性的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: hadoop fsck命令分析 + 源码
- 下一篇: 控制反转和依赖注入,你真的分得清吗?