PowerBI DAX 設(shè)計(jì)模式 - MVC 架構(gòu) 導(dǎo)論 - 案例 - 競(jìng)爭(zhēng)交叉分析(深度購(gòu)物籃)

PowerBI DAX MVC 設(shè)計(jì)模式 導(dǎo)論 引發(fā)了很多會(huì)員伙伴的詢(xún)問(wèn)团滥,希望羅叔給出一個(gè)相對(duì)完整和復(fù)雜的案例來(lái)體會(huì) MVC 架構(gòu)和設(shè)計(jì)模式的作用。

本文將結(jié)合設(shè)計(jì)模式與 MVC 架構(gòu)設(shè)計(jì)演示一個(gè)真實(shí)的案例:競(jìng)爭(zhēng)交叉分析各淀。用戶(hù)任選兩個(gè)對(duì)比實(shí)體,來(lái)看兩個(gè)參與對(duì)比實(shí)體的某種度量值表現(xiàn)诡挂。例如:

  • 對(duì)于辦公用品大類(lèi)碎浇,其中的紙張和裝訂機(jī)同時(shí)出現(xiàn)在不同類(lèi)型客戶(hù)的訂單中的概率是怎樣的?
  • 對(duì)于辦公用品大類(lèi)璃俗,其中的紙張和裝訂機(jī)出現(xiàn)在不同地區(qū)的銷(xiāo)售是怎樣的奴璃?

效果

為了更加清楚的理解這種對(duì)比,羅叔先和大家一起看看效果:

image

如上圖所示城豁,其功能包括:

  • 分為兩個(gè)對(duì)比項(xiàng)切片器苟穆,且該切片器按照頂部切片器(類(lèi)別)進(jìn)行聯(lián)動(dòng);
  • 交叉訂單數(shù),用于顯示同時(shí)滿(mǎn)足左右對(duì)比項(xiàng)交叉(同時(shí)包括)時(shí)的訂單數(shù)雳旅;
  • 交叉銷(xiāo)售額按地域跟磨,用于顯示按地域且同時(shí)考慮兩個(gè)對(duì)比項(xiàng)的四種課程模式:
    • 僅包括左邊的選擇,不包括右邊的選擇的訂單銷(xiāo)售額攒盈;
    • 僅包括右邊的選擇抵拘,不包括左邊的選擇的訂單銷(xiāo)售額;
    • 同時(shí)包括左右兩邊的選擇的訂單銷(xiāo)售額沦童;
    • 不包括任何一邊的訂單銷(xiāo)售額。

不難看出叹话,本案例是購(gòu)物籃分析的深度增強(qiáng)版偷遗。處于教學(xué)目的,羅叔故意增加了分析的靈活性和動(dòng)態(tài)性驼壶,問(wèn)題是如何實(shí)現(xiàn)上述的分析氏豌?

難點(diǎn)分析

在羅叔給出正確設(shè)計(jì)方案前,我們先一起來(lái)看看其中的難點(diǎn)以及你是否已經(jīng)想到這些:

  • 如何構(gòu)建兩個(gè)對(duì)比切片器热凹?雖然數(shù)據(jù)都是產(chǎn)品子類(lèi)別泵喘,但應(yīng)該如何構(gòu)建?
  • 構(gòu)建的兩個(gè)切片器是否應(yīng)該與原有模型建立關(guān)系般妙?
  • 如果構(gòu)建的兩個(gè)切片器與原有模型沒(méi)有關(guān)系纪铺,那類(lèi)別切片器如何影響這兩個(gè)切片器聯(lián)動(dòng)?
  • 如何實(shí)現(xiàn)交叉分析的計(jì)算碟渺?
  • 如何實(shí)現(xiàn)四種模式下交叉銷(xiāo)售額的計(jì)算鲜锚?

對(duì)于初學(xué)者,為了讓可視化效果產(chǎn)生聯(lián)動(dòng)苫拍,會(huì)構(gòu)建子類(lèi)別并與數(shù)據(jù)模型進(jìn)行關(guān)聯(lián)芜繁,這是很自然的想法,雖然這個(gè)思路確實(shí)可以實(shí)現(xiàn)最終效果绒极,但這個(gè)思路是錯(cuò)誤的骏令。在真正的復(fù)雜項(xiàng)目中,這種類(lèi)似交叉分析的分析主題可能會(huì)非常多垄提,多到幾十個(gè)頁(yè)面甚至需要上百個(gè)度量值榔袋,如果使用這個(gè)思路,必然會(huì)使得模型變得非常復(fù)雜铡俐。

下面羅叔基于 MVC 架構(gòu)設(shè)計(jì)給出標(biāo)準(zhǔn)的實(shí)現(xiàn)并指出我們應(yīng)該遵守的設(shè)計(jì)思想和設(shè)計(jì)模式摘昌。

非侵入式設(shè)計(jì)

這里正式提出重要的設(shè)計(jì)思想:非侵入式設(shè)計(jì)。羅叔并不記得這個(gè)思路來(lái)自哪里高蜂,在 PowerBI DAX 領(lǐng)域聪黎,該思想由我們首次提出,其內(nèi)涵為:不應(yīng)該為了展現(xiàn)而破壞業(yè)務(wù)數(shù)據(jù)模型。

由于我們整體采用了 MVC 架構(gòu)設(shè)計(jì)稿饰,在導(dǎo)論中我們指出數(shù)據(jù)模型包括:數(shù)據(jù)模型視圖模型锦秒,由于這里是以分析和展現(xiàn)為目的的崭孤,并沒(méi)有引入任何新的業(yè)務(wù)邏輯歌逢,因此,我們?cè)谕耆挥绊憯?shù)據(jù)模型的前提下完成所有設(shè)計(jì)预麸。

視圖模型

首先給出滿(mǎn)足非侵入式設(shè)計(jì)的視圖模型:

image

可以看出侣姆,這由三個(gè)游離的表構(gòu)成生真,它們均由 DAX 構(gòu)造,如下:

View.Competitor.LeftItem = VALUES( Model_Product[子類(lèi)別] )

View.Competitor.RightItem = VALUES( Model_Product[子類(lèi)別] )

View.Competitor.Legend = 
VAR X = {
    ( "L1R0" , "LeftOnly" , 1 ),
    ( "L0R1" , "RightOnly" , 2 ),
    ( "L1R1" , "Both" , 3 ),
    ( "L0R0" , "None" , 4 )
}
RETURN SELECTCOLUMNS( X , "ID" , [Value1] , "Name" , [Value2] , "OrderBy" , [Value3] )

這三個(gè)表(或者稱(chēng)列表)與主數(shù)據(jù)模型(或者稱(chēng)業(yè)務(wù)數(shù)據(jù)模型)沒(méi)有任何篩選關(guān)系捺宗,也就不會(huì)影響業(yè)務(wù)模型的計(jì)算或變更柱蟀。

展現(xiàn)邏輯 - 交叉訂單數(shù)計(jì)算

在進(jìn)行圖表展現(xiàn)時(shí),一個(gè)最佳實(shí)踐是:

  • 第一步蚜厉,將你希望呈現(xiàn)的最終效果用維度和度量值來(lái)表示长已,其中度量值可以是占位符;
  • 第二步昼牛,實(shí)現(xiàn)這個(gè)度量值术瓮。

可視化大概的效果為:

image

現(xiàn)在給出這個(gè)度量值的 DAX 表達(dá)式:

View.Competior.SharedOrderNumber = // 共同出現(xiàn)的訂單數(shù)
VAR vOrdersFromLeft = 
    CALCULATETABLE( 
        VALUES( Model_Order[訂單ID] ) , TREATAS( { SELECTEDVALUE( 'View.Competitor.LeftItem'[子類(lèi)別] ) } , Model_Product[子類(lèi)別] ) )

VAR vOrdersFromRight = 
    CALCULATETABLE( 
        VALUES( Model_Order[訂單ID] ) , TREATAS( { SELECTEDVALUE( 'View.Competitor.RightItem'[子類(lèi)別] ) } , Model_Product[子類(lèi)別] ) )

RETURN COUNTROWS( INTERSECT( vOrdersFromLeft , vOrdersFromRight ) )

其思路如下:

  • vOrdersFromLeft - 將左側(cè)切片器所選內(nèi)容動(dòng)態(tài)掛載到數(shù)據(jù)模型,以篩選出相應(yīng)的訂單集合贰健;
  • vOrdersFromRight - 將右側(cè)切片器所選內(nèi)容動(dòng)態(tài)掛載到數(shù)據(jù)模型胞四,以篩選出相應(yīng)的訂單集合;
  • 求上述兩個(gè)集合的交集的行數(shù)即可伶椿;
  • 注意撬讽,在這個(gè)過(guò)程數(shù)據(jù)模型始終保持被細(xì)分或行業(yè)篩選。

展現(xiàn)邏輯 - 交叉銷(xiāo)售額的計(jì)算

類(lèi)似地悬垃,不同類(lèi)型的交叉銷(xiāo)售額也需要得到展現(xiàn)時(shí)的計(jì)算游昼,最終效果:

image

按照展現(xiàn)的最佳實(shí)踐:

  • 第一步,將你希望呈現(xiàn)的最終效果用維度和度量值來(lái)表示尝蠕,其中度量值可以是占位符烘豌;
  • 第二步,實(shí)現(xiàn)這個(gè)度量值看彼。

這里涉及一個(gè)圖例維度廊佩,如下:

View.Competitor.Legend = 
VAR X = {
    ( "L1R0" , "LeftOnly" , 1 ),
    ( "L0R1" , "RightOnly" , 2 ),
    ( "L1R1" , "Both" , 3 ),
    ( "L0R0" , "None" , 4 )
}
RETURN SELECTCOLUMNS( X , "ID" , [Value1] , "Name" , [Value2] , "OrderBy" , [Value3] )

該圖例給出了四種可能的交叉情況,進(jìn)而繼續(xù)實(shí)現(xiàn)度量值靖榕,如下:

View.Competior.SalesByLegend = 

VAR vLeftItem = SELECTEDVALUE( 'View.Competitor.LeftItem'[子類(lèi)別] )
VAR vRightItem = SELECTEDVALUE( 'View.Competitor.RightItem'[子類(lèi)別] )

// 計(jì)算當(dāng)前圖例
VAR vLegendItem = SELECTEDVALUE( 'View.Competitor.Legend'[ID] )

// 左右元素對(duì)應(yīng)的訂單集合
VAR vOrdersFromLeft = CALCULATETABLE( VALUES( Model_Order[訂單ID] ) , TREATAS( { vLeftItem } , Model_Product[子類(lèi)別] ) )
VAR vOrdersFromRight = CALCULATETABLE( VALUES( Model_Order[訂單ID] ) , TREATAS( { vRightItem } , Model_Product[子類(lèi)別] ) )

// 四種交叉的集合可能
VAR vSetL1R0 = EXCEPT( vOrdersFromLeft , vOrdersFromRight )
VAR vSetL0R1 = EXCEPT( vOrdersFromRight , vOrdersFromLeft )
VAR vSetL1R1 = INTERSECT( vOrdersFromLeft , vOrdersFromRight )
VAR vSetL0R0 = EXCEPT( ALL( Model_Order[訂單ID] ) , UNION( vOrdersFromLeft , vOrdersFromRight ) )

// 對(duì)應(yīng)不同圖例标锄,計(jì)算與該圖例一致的交叉銷(xiāo)售額
RETURN SWITCH( TRUE() ,
    vLegendItem = "L1R0" , CALCULATE( [KPI.Sales] , vSetL1R0 ) ,
    vLegendItem = "L0R1" , CALCULATE( [KPI.Sales] , vSetL0R1 ) ,
    vLegendItem = "L1R1" , CALCULATE( [KPI.Sales] , vSetL1R1 ) ,
    vLegendItem = "L0R0" , CALCULATE( [KPI.Sales] , vSetL0R0 ) ,
    BLANK()
)

對(duì)該 DAX 表達(dá)式的注解參見(jiàn)上述表達(dá)式注釋。

MVC 架構(gòu)設(shè)計(jì)

上述設(shè)計(jì)按照非侵入式設(shè)計(jì)思想構(gòu)建茁计,在構(gòu)建的過(guò)程中料皇,我們始終是在 MVC 框架下進(jìn)行的,我們整理這個(gè)框架,視圖如下:

image

視圖的展現(xiàn)邏輯:

image

視圖模型:

image

我們?cè)倩仡櫼幌?MVC 架構(gòu)的模型如下:

image

不難看出這里的設(shè)計(jì)完全嚴(yán)格遵守了 MVC 架構(gòu)設(shè)計(jì)践剂,具體說(shuō)來(lái):

  • 視圖鬼譬,依賴(lài)于視圖模型與展現(xiàn)度量值;
  • 視圖模型逊脯,是從數(shù)據(jù)模型導(dǎo)出的优质,在展現(xiàn)度量值計(jì)算時(shí),動(dòng)態(tài)掛載到數(shù)據(jù)模型以產(chǎn)生篩選效應(yīng)军洼;
  • 展現(xiàn)度量值巩螃,完全按照展現(xiàn)效果設(shè)計(jì),將視圖模型與數(shù)據(jù)模型實(shí)現(xiàn)動(dòng)態(tài)掛載匕争。

可以看出避乏,這樣的 MVC 架構(gòu)設(shè)計(jì)與非侵入式設(shè)計(jì)思想融為一體。要實(shí)現(xiàn)非侵入式設(shè)計(jì)汗捡,采用 MVC 架構(gòu)設(shè)計(jì)是通用的思路淑际;而采用 MVC 架構(gòu)設(shè)計(jì)便實(shí)現(xiàn)了非侵入式設(shè)計(jì)畏纲。

數(shù)據(jù)模型與視圖模型的聯(lián)動(dòng)

至此扇住,我們?nèi)匀挥幸粋€(gè)問(wèn)題沒(méi)有給出答案,那就是:

  • 子類(lèi)別來(lái)自于孤立的視圖模型表盗胀;
  • 類(lèi)別來(lái)自于數(shù)據(jù)模型艘蹋;
  • 它們之間沒(méi)有任何關(guān)系是如何實(shí)現(xiàn)聯(lián)動(dòng)的?

這要得益于 PowerBI 最近幾個(gè)月更新所支持的用度量值控制切片器的元素票灰,這樣就具有了動(dòng)態(tài)性女阀。我們構(gòu)造了一個(gè)度量值如下:

View.Competitor.LeftItem.Check = 
IF(
    CALCULATE( 
        SELECTEDVALUE( Model_Product[類(lèi)別] ) , 
        TREATAS( { SELECTEDVALUE( 'View.Competitor.LeftItem'[子類(lèi)別] ) } , Model_Product[子類(lèi)別] ) 
    ) = SELECTEDVALUE( Model_Product[類(lèi)別] ) , 
    "有效" 
)

并將其置于切片器的篩選中,如下:

image

這個(gè)有效性由度量值給出屑迂,而該度量值是與數(shù)據(jù)模型動(dòng)態(tài)計(jì)算關(guān)聯(lián)的“橋梁”浸策。

總結(jié)

羅叔正式提出 MVC 架構(gòu)設(shè)計(jì)以及非侵入式設(shè)計(jì)其實(shí)已經(jīng)等候多時(shí),它需要幾個(gè) PowerBI 的構(gòu)件做支撐惹盼,具體包括:

  • 度量值可以用文件夾組織庸汗,用于分類(lèi);
  • 切片器可以被度量值篩選手报,以實(shí)現(xiàn)視圖模型與數(shù)據(jù)模型的橋接聯(lián)動(dòng)效應(yīng)蚯舱;
  • 可視化元素可以被編組以實(shí)現(xiàn)視圖級(jí)可視化元素與展現(xiàn)度量值的對(duì)應(yīng)關(guān)系;
  • 模型可以創(chuàng)建新的布局以區(qū)分?jǐn)?shù)據(jù)模型和視圖模型掩蛤;
  • DAX 可以驅(qū)動(dòng)更多視覺(jué)元素的可視化以便形成強(qiáng)大的展現(xiàn)計(jì)算能力枉昏。

在 2019 年幾個(gè)月來(lái) PowerBI 的更新后,我們終于迎來(lái)了正式推出這套思想揍鸟,并給出案例以明顯體會(huì)到這種模式的優(yōu)越性兄裂。

本文給出了一個(gè)基于 MVC 架構(gòu)的典型案例,該案例要求復(fù)雜的展現(xiàn)分析,而我們的設(shè)計(jì)不但可以實(shí)現(xiàn)目的懦窘,還完全不影響數(shù)據(jù)模型本身前翎,這便是我們需要的。

值得注意的是:我們?cè)谠O(shè)計(jì)視圖模型時(shí)畅涂,對(duì)維度的命名為:View.Competitor.RightItem港华,這個(gè)命名根本沒(méi)有提及子類(lèi)別,而子類(lèi)別是蘊(yùn)含在其中的午衰,也就是說(shuō)這個(gè)命名是抽象的立宜,我們完全可以繼續(xù)擴(kuò)展這種設(shè)計(jì),以實(shí)現(xiàn)按產(chǎn)品子類(lèi)別分析或者其他實(shí)體(如:產(chǎn)品)來(lái)分析臊岸。也就是這是依賴(lài)于抽象橙数,而不依賴(lài)于具體的,這使得我們的設(shè)計(jì)有最大化的可復(fù)用潛力帅戒。這在設(shè)計(jì)模式中叫做面向接口的設(shè)計(jì)灯帮。我們真正打開(kāi)了 PowerBI DAX 通用設(shè)計(jì)模式的大門(mén),我們會(huì)在后續(xù)的文章中不斷給出通用設(shè)計(jì)模式逻住,以使得我們的 PowerBI 設(shè)計(jì)更加完美钟哥,無(wú)懈可擊。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末瞎访,一起剝皮案震驚了整個(gè)濱河市腻贰,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌扒秸,老刑警劉巖播演,帶你破解...
    沈念sama閱讀 210,978評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異伴奥,居然都是意外死亡写烤,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,954評(píng)論 2 384
  • 文/潘曉璐 我一進(jìn)店門(mén)拾徙,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)洲炊,“玉大人,你說(shuō)我怎么就攤上這事锣吼⊙』耄” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 156,623評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵玄叠,是天一觀的道長(zhǎng)古徒。 經(jīng)常有香客問(wèn)我,道長(zhǎng)读恃,這世上最難降的妖魔是什么隧膘? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,324評(píng)論 1 282
  • 正文 為了忘掉前任代态,我火速辦了婚禮,結(jié)果婚禮上疹吃,老公的妹妹穿的比我還像新娘蹦疑。我一直安慰自己,他們只是感情好萨驶,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,390評(píng)論 5 384
  • 文/花漫 我一把揭開(kāi)白布歉摧。 她就那樣靜靜地躺著,像睡著了一般腔呜。 火紅的嫁衣襯著肌膚如雪叁温。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,741評(píng)論 1 289
  • 那天核畴,我揣著相機(jī)與錄音膝但,去河邊找鬼。 笑死谤草,一個(gè)胖子當(dāng)著我的面吹牛跟束,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播丑孩,決...
    沈念sama閱讀 38,892評(píng)論 3 405
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼冀宴,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了嚎杨?” 一聲冷哼從身側(cè)響起花鹅,我...
    開(kāi)封第一講書(shū)人閱讀 37,655評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤氧腰,失蹤者是張志新(化名)和其女友劉穎枫浙,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體古拴,經(jīng)...
    沈念sama閱讀 44,104評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡箩帚,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,451評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了黄痪。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片紧帕。...
    茶點(diǎn)故事閱讀 38,569評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖桅打,靈堂內(nèi)的尸體忽然破棺而出是嗜,到底是詐尸還是另有隱情,我是刑警寧澤挺尾,帶...
    沈念sama閱讀 34,254評(píng)論 4 328
  • 正文 年R本政府宣布鹅搪,位于F島的核電站,受9級(jí)特大地震影響遭铺,放射性物質(zhì)發(fā)生泄漏丽柿。R本人自食惡果不足惜恢准,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,834評(píng)論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望甫题。 院中可真熱鬧馁筐,春花似錦、人聲如沸坠非。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,725評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)炎码。三九已至赦抖,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間辅肾,已是汗流浹背队萤。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,950評(píng)論 1 264
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留矫钓,地道東北人要尔。 一個(gè)月前我還...
    沈念sama閱讀 46,260評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像新娜,于是被迫代替她去往敵國(guó)和親赵辕。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,446評(píng)論 2 348