Tableau 中创建计算的最佳做法
本文介绍在 Tableau 中创建高效计算的若干提示和准则。这些准则旨在帮助您优化工作簿性能。有关可提高工作簿性能的所有方式的详细信息,请参见优化工作簿性能系列。
一般规则:避免在另一个计算中使用某个计算字段多次
在另一个计算中引用同一计算字段多次将导致性能问题。如果您在计算内使用计算字段(也称为创建嵌套计算),请尝试只在计算中引用该计算字段一次。
请注意,在计算中引用某个字段(终端字段)多次应该不会使性能降级。
示例
假设您创建一个计算字段,该字段使用复杂的多行计算在推文中查找提及(或推特用户名)。计算字段名为“Twitter Handle”(推特用户名)。返回的每个用户名以“@”符号开头(例如:@user)。
为了便于分析,您想要移除“@”符号。
为此,您可以使用以下计算来从字符串中移除第一个字符:
RIGHT([Twitter Handle], LEN([Twitter Handle]) -1)
此计算非常简单。但是,由于它引用了“Twitter Handle”(推特用户名)计算两次,因此会为数据源中的每条记录执行该计算两次:一次针对 RIGHT 函数执行,另一次针对 LEN 函数执行。
为了避免计算同一个计算多次,您可以将计算改写为只使用“Twitter Handle”(推特用户名)计算一次。在本例中,您可以使用 MID 来完成相同目标:
MID([Twitter Handle], 2)
提示 1:将多个等式比较转换为 CASE 表达式或组
假设您有以下计算,该计算使用计算字段“Person (calc)”多次,并使用一系列 OR 函数。此计算尽管是一个简单的逻辑表达式,但会导致查询性能问题,因为它会执行“Person (calc)”计算至少十次。
IF [Person (calc)] = 'Henry Wilson'
OR [Person (calc)] = 'Jane Johnson'
OR [Person (calc)] = 'Michelle Kim'
OR [Person (calc)] = 'Fred Suzuki'
OR [Person (calc)] = 'Alan Wang'
THEN 'Lead'
ELSEIF [Person (calc)] = 'Susan Nguyen'
OR [Person (calc)] = 'Laura Rodriguez'
OR [Person (calc)] = 'Ashley Garcia'
OR [Person (calc)] = 'Andrew Smith'
OR [Person (calc)] = 'Adam Davis'
THEN 'IC'
END
请尝试以下解决方案,而不是使用等式比较。
解决方案 1
使用 CASE 表达式。例如:
CASE [Person (calc)]
WHEN 'Henry Wilson' THEN 'Lead'
WHEN 'Jane Johnson' THEN 'Lead'
WHEN 'Michelle Kim' THEN 'Lead'
WHEN 'Fred Suzuki' THEN 'Lead'
WHEN 'Alan Wang' THEN 'Lead'
WHEN 'Susan Nguyen' THEN 'IC'
WHEN 'Laura Rodriguez' THEN 'IC'
WHEN 'Ashley Garcia' THEN 'IC'
WHEN 'Andrew Smith' THEN 'IC'
WHEN 'Adam Davis' THEN 'IC'
END
在本例中,只引用了计算字段“Person (calc)”一次。因此该计算也只会执行一次。CASE 表达式在查询管道中还得到了进一步优化,因此性能得以额外提升。
解决方案 2
创建组,而不是计算字段。有关详细信息,请参见对数据进行分组。
提示 2:将多个字符串计算转换为单一 REGEXP 表达式
注意:REGEXP 计算仅在使用 Tableau 数据提取或连接到文本文件、Hadoop Hive、Google BigQuery、PostgreSQL、Tableau 数据提取、Microsoft Excel、Salesforce、Vertica、Pivotal Greenplum、Teradata(版本 14.1 及更高版本)和 Oracle 数据源时可用。有关详细信息,请参见其他函数。
示例 1:CONTAINS
假设您有以下计算,该计算使用计算字段“Category (calc)”多次。此计算尽管也是一个简单的逻辑表达式,但会导致查询性能问题,因为它会执行“Category (calc)”计算多次。
IF CONTAINS([Segment (calc)],'UNKNOWN')
OR CONTAINS([Segment (calc)],'LEADER')
OR CONTAINS([Segment (calc)],'ADVERTISING')
OR CONTAINS([Segment (calc)],'CLOSED')
OR CONTAINS([Segment (calc)],'COMPETITOR')
OR CONTAINS([Segment (calc)],'REPEAT')
THEN 'UNKNOWN'
ELSE [Segment (calc)] END
您可以使用 REGEXP 表达式来获得同样的结果,而不必进行同样的重复。
解决方案
IF REGEXP_MATCH([Segment (calc)], 'UNKNOWN|LEADER|ADVERTISING|CLOSED|COMPETITOR|REPEAT') THEN 'UNKNOWN'
ELSE [Segment (calc)] END
对于使用类似模式的字符串计算,您可以使用相同的 REGEXP 表达式。
示例 2:STARTSWITH
IF STARTSWITH([Segment (calc)],'UNKNOWN')
OR STARTSWITH([Segment (calc)],'LEADER')
OR STARTSWITH([Segment (calc)],'ADVERTISING')
OR STARTSWITH([Segment (calc)],'CLOSED')
OR STARTSWITH([Segment (calc)],'COMPETITOR')
OR STARTSWITH([Segment (calc)],'REPEAT')
THEN 'UNKNOWN'
解决方案
IF REGEXP_MATCH([Segment (calc)], '^(UNKNOWN|LEADER|ADVERTISING|CLOSED|COMPETITOR|REPEAT)') THEN 'UNKNOWN'
ELSE [Segment (calc)] END
请注意,此解决方案中使用“^”符号。
示例 3:ENDSWITH
IF ENDSWITH([Segment (calc)],'UNKNOWN')
OR ENDSWITH([Segment (calc)],'LEADER')
OR ENDSWITH([Segment (calc)],'ADVERTISING')
OR ENDSWITH([Segment (calc)],'CLOSED')
OR ENDSWITH([Segment (calc)],'COMPETITOR')
OR ENDSWITH([Segment (calc)],'REPEAT')
THEN 'UNKNOWN'
ELSE [Segment (calc)] END
解决方案
IF REGEXP_MATCH([Segment (calc)], '(UNKNOWN|LEADER|ADVERTISING|CLOSED|COMPETITOR|REPEAT)$') THEN 'UNKNOWN'
ELSE [Segment (calc)] END
请注意,此解决方案中使用“$”符号。
提示 3:使用 REGEXP(而不是 LEFT、MID、RIGHT、FIND、LEN)操作字符串
正则表达式可能是一种非常强大的工具。在执行复杂的字符串操作时,请考虑使用正则表达式。在许多情况下,使用正则表达式会使计算更加简短高效。有关正则表达式的详细信息,请参见 Tableau 博客上的 Become a regex regular and wrangle imperfect data(成为正则表达式精英并照管不完美的数据)(链接在新窗口中打开)博文。
示例 1
假设您有以下计算,该计算从 URL 中移除协议。例如:“https://www.tableau.com”变为“www.tableau.com”。
IF (STARTSWITH([Server], "http://")) THEN
MID([Server], Len("http://") + 1)
ELSEIF(STARTSWITH([Server], "https://")) THEN
MID([Server], Len("https://") + 1)
ELSEIF(STARTSWITH([Server], "tcp:")) THEN
MID([Server], Len("tcp:") + 1)
ELSEIF(STARTSWITH([Server], "\\")) THEN
MID([Server], Len("\\") + 1)
ELSE [Server]
END
解决方案
可通过使用 REGEXP_REPLACE 函数来简化计算和提高性能。
REGEXP_REPLACE([Server], "^(http://|https://|tcp:|\\\\)", "")
示例 2
假设您有以下计算,该计算返回 IPv4 地址的第二部分。例如:“172.16.0.1”变为“16”。
IF (FINDNTH([Server], ".", 2) > 0) THEN
MID([Server],
FIND([Server], ".") + 1,
FINDNTH([Server], ".", 2) - FINDNTH([Server], ".", 1) - 1
)
END
解决方案
可通过使用 REGEXP_EXTRACT 函数来简化计算和提高性能。
REGEXP_EXTRACT([Server], "\.([^\.]*)\.")
提示 4:不要在计算中使用集
如果在计算中使用集,请考虑将集替换为一个替代等效计算。
示例
假设您有以下计算,该计算使用集“Top Customers (set)”。
IF ISNULL([Customer Name]) OR [Top customers (set)] THEN [Segment] ELSE [Customer Name] END
解决方案 1
如果集很简单,您可以创建一个其返回结果与集相同的计算字段。例如:
CASE [Customer Name]
WHEN 'Henry Wilson' THEN True
WHEN 'Jane Johnson' THEN True
WHEN 'Michelle Kim' THEN True
WHEN 'Fred Suzuki' THEN True
WHEN 'Alan Wang' THEN True
ELSE False
END
注意:建议在此情况下使用模式 WHEN TRUE … ELSE,以避免由于使用集而导致的性能问题。大多数情况下不推荐使用该模式。
解决方案 2
如果集比较复杂,请考虑创建一个组,该组将集中的所有元素映射到一个给定的值或属性(例如“IN”),然后修改计算来检查该值/属性。例如:
IF ISNULL([Customer Name]) OR [Top Customers(group)]='IN' THEN [Segment] ELSE [Customer Name] END
提示 5:不要使用集对数据进行分组
集旨在对数据的子集进行比较。组旨在将相关成员合并在一个字段中。不推荐将集转换为组,例如通过以下示例进行转换:
IF [Americas Set] THEN "Americas"
ELSEIF [Africa Set] THEN "Africa"
ELSEIF [Asia Set] THEN "Asia"
ELSEIF [Europe Set] THEN "Europe"
ELSEIF [Oceania Set] THEN "Oceania"
ELSE "Unknown"
END
之所以不推荐这样做,有以下几个原因:
集并不始终是排他的。某些成员可能会出现在多个集中。例如,“俄罗斯”既可能放在“欧洲”集中,也可能放在“亚洲”集中。
集并不会始终转换为组。如果集是通过排除、条件或限制定义的,则可能很难甚至无法创建等效的组。
解决方案
使用“组”功能对数据进行分组。有关详细信息,请参见对数据进行分组。