从数据到信息
从信息到洞察

FILTER

初识迭代函数

广义的迭代是对反馈过程的重复,其目的通常是为了接近并到达所需的目标或结果。每一次对过程的重复被称为一次“迭代”,而每一次迭代得到的结果会被用来作为下一次迭代的初始值。

在 DAX 中,迭代函数可以迭代一张表,为表的每一行执行相同的 DAX 表达式,然后根据不同的函数执行不同的后续操作。DAX 的迭代函数数量很多,包括以 X 结尾的所有聚合函数,比如SUMXAVERAGEX;包括 FILTER、ADDCOLUMNS、RANKX 等函数,它们都可以创建行上下文。本章我们介绍 FILTER 和以 X 结尾的聚合函数

理解 FILTER

FILTER 函数的作用很简单:它获取一个表并返回一个与原始表具有相同列的表,逐行应用筛选条件,最后返回满足筛选条件的行。

FILTER 语法

FILTER ( <table>, <FilterExpression> )

FILTER 迭代整张表<table>,为每一行计值布尔表达式<FilterExpression>,当计值结果为 TRUE,FILTER 返回当前行;否则,就跳过当前行。

从逻辑角度来看,FILTER 为表中的每个行计值条件表达式。但是,DAX 的内部优化逻辑可能会将这些计算的数量减少到条件表达式中包含的列的唯一值的数量。条件表达式的实际计算次数对应于 FILTER 操作的“粒度”(granularity)。这个粒度决定了 FILTER 的性能,它是 DAX 优化的重要因素。

例如,下面的查询筛选出产品表中的 Fabrikam 品牌

EVALUATE
FILTER (
    Product,
    Product[Brand] = "Fabrikam"
)

只筛选 Fabrikam 品牌的产品

FILTER 嵌套

可以将对 FILTER 的调用嵌套在另一个 FILTER 函数中,因为任何返回表的表达式都可以用作 FILTER 的参数。最内层的 FILTER 首先执行。通常,嵌套两个筛选器与用 AND 函数包含逻辑条件的结果相同。换言之,以下查询产生相同的结果:

FILTER ( <table>, AND ( <condition1>, < condition2> ) )

FILTER ( FILTER ( <table>, < condition1> ), < condition2> ) )

但是,如果表有许多行,并且两个条件具有不同的复杂性,则可能会观察到不同的性能。例如,考虑下面的查询,它返回的单价是单位成本的三倍以上的 Fabrikam 产品,如下图所示。

EVALUATE
FILTER (
    Product,
    AND (
        Product[Brand] = "Fabrikam",
        Product[Unit Price] > Product[Unit Cost] * 3
    )
)

查询筛选出了单价是单位成本的三倍以上的 Fabrikam 产品

此类查询会将这两个条件应用于产品表的所有行。如果两个条件中有一个更快、更有约束性,则可以在内层的 FILTER 函数里首先应用它。例如,以下查询将对单位价格和单位成本的筛选应用于最内层的 FILTER 函数,然后按品牌筛选满足价格条件的产品。

EVALUATE
FILTER (
    FILTER (
        Product,
        Product[Unit Price] > Product[Unit Cost] * 3
    ),
    Product[Brand] = "Fabrikam"
)

如果反转条件,那么也会反转它们的执行顺序。以下查询仅将价格筛选应用于 Fabrikam 品牌的产品:

EVALUATE
FILTER (
    FILTER (
        Product,
        Product[Brand] = "Fabrikam"
    ),
    Product[Unit Price] > Product[Unit Cost] * 3
)

当你优化 DAX 表达式时,这些知识会很有用。你可以选择执行顺序,首先应用最具约束性的筛选器。然而,请在彻底清楚计值上下文之后再开始优化 DAX 语言。你将在 DAX 优化章节中找到关于查询优化的更完整的介绍。这些示例的目的是让你了解表函数在嵌套调用时的执行顺序。

随着 DAX 版本的更新,引擎的自动优化能力也在不断增强,在普通场景中,以上不同写法的实际性能差异已经微乎其微。但这种优化思路仍然有其参考价值,因为在更加复杂的模型和公式中,你无法完全依赖于引擎的自动优化。

关于执行顺序

通常,嵌套函数的执行顺序是从最内层函数到最外层函数。稍后你将看到,CALCULATE 和CALCULATETABLE可能是此行为的一个例外,因为用于计算它们的参数有特定顺序。考虑到你可能在某些相似情况下使用 FILTER 和CALCULATETABLE,所以在嵌套调用时要注意这个区别。

测试题

你已经了解在 FILTER 中执行多个条件判断时的最优策略,让我们来回顾一下需要同时满足多条件(AND 运算)时,FILTER 所有可能的写法。以两个条件为例,使用 Contoso 样例数据库文件,定义以下三个公式:

CALCULATE (
    COUNTROWS ( Sales ),
    FILTER (
        ALL ( Sales ),
        Sales[Order Date] <= DATE ( 2007, 1, 1 ) 
            && Sales[Delivery Date] >= DATE ( 2006, 1, 1 )
    )
)
CALCULATE (
     COUNTROWS ( Sales ),
     FILTER (
         FILTER ( ALL ( Sales ), Sales[Order Date] <= DATE ( 2007, 1, 1 ) ),
         Sales[Delivery Date] >= DATE ( 2006, 1, 1 )
     )
 )
CALCULATE (
      COUNTROWS ( Sales ),
      FILTER ( ALL ( Sales ),[Order Date] <= DATE ( 2007, 1, 1 ) ),
      FILTER ( ALL ( Sales ),[Delivery Date] >= DATE ( 2006, 1, 1 ) )
)

它们的用时排序是怎么样的?

公众号二维码加载失败时的替代文字
此处内容已经被作者无情的隐藏,请输入验证码查看内容
验证码:
请关注“PowerBI极客”公众号,回复关键字“FILTER”,获取验证码。 【注】手机扫描二维码快速关注“PowerBI极客”官方公众号。

 

参考阅读:CALCULATETABLE vs FILTER

4
说点什么

avatar
1000
 
鼓掌微笑开心憧憬爱你色并不觉得吃瓜doge二哈喵喵思考笑哭捂脸悲伤大哭抓狂汗偷笑打脸捂眼黑线问号晕拜拜闭嘴衰咒骂ok作揖
2 评论数
2 被回复的评论
3 订阅评论的人数
 
查看最近回复
查看最热评论
  订阅本文评论  
最新 最旧 得票最多
提醒
jianyao0105
成员
jianyao0105

filter连用了10+个 “||”运算符,dax studio跑了快2分钟 捂脸 。这种情况下,filtre函数或者“||”是最优的吗?等下还要再用个 and函数筛一下,估计更慢了。
公式主要想筛选出特定的10几个产品,在最近一天的有效消费(max日期消费>0)总金额。

136****6402
成员
136****6402

A例中我理解的是filter对sales表的全部内容迭代筛选,保留满足条件的行,然后calculate以filter的结果赋予calculate第一参数中的sales表,最后计算表行数.
我表达应该不准确,其中可能还会有很多其他数据流动,只是想问问浅层这么理解的话有问题吗?