如何理解 DAX 数据沿袭

2021-11-15 16:30:15 浏览数 (2)

数据沿袭,这个词汇,相当生僻,很多小伙伴都问这个什么意思,以及如何去使用他。那本文就来帮大家理解这个事物。

数据沿袭

数据沿袭(data lineage),表示数据的一种本质联系。

举一个例子,如下:

SUMX 进行计算的时候,问题来了:

  • vTable,是一个孤立的表吗?
  • vTable,是一个与原数据模型实际保持关联的表数据吗?

SUMX 的计算结果来看,这的确是总计结果。

这说明,在针对 vTable 进行计算时候,进行的上下文转换,的确由于筛选上下文对模型有实际的影响,这说明:

虽然 vTable 是通过 VAR 独立构建的,但它依然保持着在实际数据模型中的数据血缘关系。

进一步的案例

如果刚刚的案例没能让你觉得有什么特别,那么请看这个例子:

代码语言:javascript复制
DataLineage.Demo = 
VAR vTable = SELECTCOLUMNS( DISTINCT( 'Product'[Category] ) , "Item" , 'Product'[Category] )
RETURN SUMX( vTable , [KPI] )

现在,用 VAR 构建的 vTable 的过程是:

第一步,先计算 DISTINCT( 'Product'[Category] 得到一个过程中的表;

第二步,再通过 SELECTCOLUMNS 取出上述过程表的 'Product'[Category] 列,并更名为:Item;

第三步,针对这个 vTable 计算度量值后求和。

我们看看最后的结果:

可以看出,与此前的结果是一致的。

也就是说,不管我们在中间的计算过程再增加多少过程,如果其本质只是针对数据模型中的列的获取,那都不会改变数据模型本身,也就不会改变计算过程中数据与数据模型的联系。

一个反例

当然,我们需要一个反例来更好的理解这个数据沿袭,如下:

代码语言:javascript复制
DataLineage.Error = 
VAR vTable = SELECTCOLUMNS( DISTINCT( 'Product'[Category] ) , "Item" , 'Product'[Category] & "" )
RETURN SUMX( vTable , [KPI] )

这里的区别在于:

在使用 SELECTCOLUMNS 取出元素的时候,将该列的元素进行了计算,那么虽然元素没有变化,但计算结果就不再一样了,如下:

由于没有了数据沿袭,在计算 SUMX 的时候,vTable 有 3 行,由于其山下文转换没有了数据沿袭的存在,不再构成对数据模型的联系,也就不会筛选数据模型,进而导致总的结果是普通计算结果的 3 倍。

进一步实验

从刚才的反例可以看出,如果破坏了列的元素,就会丢失数据沿袭。

还可以再做一个更仔细的实验,如下:

代码语言:javascript复制
DataLineage.Error2 = 
VAR vTable = 
    SELECTCOLUMNS( 
        DISTINCT( 'Product'[Category] ) , 
        "Item" , IF( 'Product'[Category] = "家具" , 'Product'[Category] & "" , 'Product'[Category] )
    )
RETURN SUMX( vTable , [KPI] )

这个实验的特点是,仅仅针对某个元素进行破坏数据沿袭的计算,而其他元素保持不变,那么可以还会部分保持数据沿袭吗?

神奇的效果出现了:

也就是说,如果某行的计算并非获取原始元素,而进行了计算;而其他元素直接获取原始元素,在这种情况下,是否可以部分保持数据沿袭?

请在留言区写下你的看法和你的理解吧。

当然,你可以自己完成这个实验里知道这个结果是什么。

数据沿袭有什么用

数据沿袭,其本质是一种非常自然的存在。请大家考虑一个经典的帕累托积累 % 计算问题,如下:

针对这条积累 % 的计算曲线,考虑以下 DAX 公式:

代码语言:javascript复制
ABC.KPI.Cumulate% =
VAR vCurrentValue = [KPI.Sales]
VAR vItemList = ALLSELECTED( 'Model_产品'[产品子类别] )
VAR vItems = 
    FILTER( 
        vItemList , [KPI.Sales] >= vCurrentValue
    )
RETURN CALCULATE( [KPI.Sales], vItems ) / CALCULATE( [KPI.Sales] , ALLSELECTED( 'Model_产品'[产品子类别] ) )

其中,vItemList = ALLSELECTED( 'Model_产品'[产品子类别] ) 已经将数据模型的某列进行了暂存,而进一步对其进行计算,得到 vItems,更重要的是在最后的计算中,vItems 作为 CALCULATE 的筛选参数是否可以起到筛选的作用呢,毕竟 vItems 已经经过了四次转换:

  • 第一次,ALLSELECTED ('Model_产品 '[产品子类别] );
  • 第二次,赋给 vItemList;
  • 第三次,FILTER;
  • 第四次,vItems。

在四次转换后所得到的 vItems,即使你理解了上述的数据沿袭的概念,但此时你可以意识到以下两个重要的知识吗?

  • 【重要知识】即使经过多达 4 次,且包括取出,暂存,过滤等操作,依然会保持数据沿袭,与原有数据模型有关系。
  • 【重要启发】可以通过数据沿袭的特性构建逻辑清晰但形式多步复杂的计算流程,由于数据沿袭,整个计算流程完全自然与数据模型打通。

上述的 ABC.KPI.Cumulate% 的计算逻辑是正确的,而且,这正反应了这两点重要的知识。

结论

数据沿袭,表面是一个晦涩的概念,但其实它是数据模型在计算中的自然演化,保持对数据模型的联系。

注意:这里用了 “联系” 二字,而没有用 “关系” 二字。请你理解我们想强调的以及避免的混淆。

另外,在理解了数据沿袭的知识后,我们通过上述的【重要启发】构建很多复杂的计算而逻辑清晰,这篇文章就是为了后续的内容做的引子。有了数据沿袭,我们就可以设计出一些通用的模式,在随后的文章中会和大家分享。

最后,请你猜猜:上述 DataLineage.Error2 的计算会不会保持部分数据沿袭?请你在留言区写出你的想法吧。

0 人点赞