跳转到内容

高级数据映射器用法

在深入了解数据映射器的高级功能之前,先简要回顾一下基本功能。

数据映射器用于将源数据中的列映射到目标数据表。

使用检查源菜单按钮可以通过更多方式将列从源映射到目标:

  • 填充两个映射表:将源数据表中的所有值传播到目标数据表。这是默认行为。
  • 仅填充源映射表:仅映射源数据表中的所有值。当源列结构发生变化而需要修改现有工作流时,此选项很有用。
  • 仅填充目标映射表:仅将所有值传播到目标数据表。

如果上述源列和目标列选项还不够,还可以通过以下几种方式将其他列添加到目标数据表中:

  • 全部传播会将所有源列插入目标数据表,无论它们是否已存在。
  • 传播所选项仅插入所选的源列。
  • 在目标侧右键单击并选择插入行,可在当前所选行的正上方插入一行。
  • 在目标侧右键单击并选择追加行,可在目标数据表的底部(最右侧)插入一行。

若要从目标数据表中删除列,请选择所需的列,然后右键单击并选择删除。

若要重新排列目标数据表中的列,请选择所需的列。可以使用以下任一方式:

  • 批量移动箭头:使用右上角的箭头选择所需的移动选项
  • 上下文菜单:右键单击并选择移到顶部、上移、下移或移到底部。

若只返回非重复的结果,请选择非重复菜单选项。这会为源中的每一列显示一组复选框。只需勾选相应列旁边的复选框,即可仅返回非重复的结果。

若要聚合结果,请选择汇总菜单选项。这会为目标数据表中的每一列显示一组选择框。请为每一列选择合适的汇总方法。

源列cust_idamtdtnote目标列customer_idamountorder_date重命名转换 → decimal重命名未映射 → 丢弃
映射器将每个源列连接到一个目标列,并在此过程中重命名列和转换类型。未映射的源列不会出现在结果中。

若要聚合结果,请选择汇总菜单选项。这会为目标数据表中的每一列显示一组选择框。可使用以下汇总选项:

函数 说明
分组依据 按值对结果分组
计数 组中非空观测值的数量
计数(含空值) 组中观测值的数量
合计 组中值的总和
平均值 组中值的平均值
中位数 组中值的中位数
众数 组中值的众数
最小值 组中值的最小值
最大值 组中值的最大值
第一个值 按排序顺序,组中值的第一个值
最后一个值 按排序顺序,组中值的最后一个值
标准差 组内的无偏标准差
样本标准差 组内的样本标准差
总体标准差 组内的总体标准差
方差 组内的无偏方差
样本方差 组内的样本方差
总体方差 组内的总体方差
高级非分组依据 使用窗口函数时的特殊聚合选择

请为列选择合适的汇总方法。

通过 REST API 或 AI 助手设置步骤时,每个目标列都在 agg 中携带其汇总方式,步骤的 aggregation_type 选择相同的选项。每个带数据映射器的步骤都接受以下值:

键 汇总方式
group 分组依据
dont_group 高级非分组依据:该列既不分组也不聚合,适用于自行聚合或使用窗口函数的表达式
count 组中非空观测值的计数
count_null 含空值的计数
count_distinct 组中非重复值的计数
sum 合计
avg 平均值
median 中位数
min 最小值
max 最大值
stddev 标准差
stddev_samp 样本标准差
stddev_pop 总体标准差
variance 方差
var_samp 样本方差

每个目标列都可以带有 sort:asc、desc 或 none,也可以是对象 {ascending, order}。ascending 为 true 或 false。order 是一个整数,用于设置排序键的优先级:带有 order 的列优先排序,数字最小的最先,其余已排序的列随后按列位置排序。

使用窗口函数时,请选择高级非分组依据作为聚合方法。由于窗口函数本身已包含聚合,因此必须使用这一特殊选项。

在常量列中指定值,将覆盖源列的值(如果已指定),并用指定的常量值填充该列。

目标列的值取自您填写的以下内容之一,优先级依次为:常量优先,其次是表达式,最后是源列。

因此,自行计算值的列不需要源。对于常量或表达式,请将其留空:常量或表达式已经说明了值是什么,与之并存的源会被忽略。当您将列从传入数据直接映射过来、重命名它,或在此过程中转换其类型时,再填写源。

表达式通过 get_column(table, 'Column Name') 按名称读取传入的列,而不是通过源单元格。

数据映射器提供了便捷的点选式清理器功能,可对列中的数据应用转换。

清理操作包括以下类别:

  • 文本裁剪
  • 文本格式设置
  • 文本转换
  • 与 NULL 值互相转换
  • 数字格式
  • 日期解析

清理器的选择结果会被转换为一个合并的表达式,可在表达式信息中查看。

数据映射器中的表达式是 PlaidCloud 中最强大、最灵活的概念之一。它们提供近乎无限的灵活性,即使在极大的数据上也具有出色的性能。

表达式使用 Python SQLAlchemy 语法编写,并附带 PlaidCloud 中提供的一些额外辅助函数。 这使 PlaidCloud 能够直接公开底层数据仓库(例如 Greenplum、SAP HANA、Redshift 等)的全部功能。此外,还有许多公开资源提供了 SQLAlchemy 操作用法的速查参考。通过使用标准的 SQLAlchemy 语法,PlaidCloud 避免了再创造一种领域专用语法这一常见陷阱。

双击该列的表达式单元格即可打开表达式编辑器。打开后,左侧显示列的列表,右侧显示丰富的函数库。

虽然完全可以直接在编辑器中键入表达式,但通常更容易的做法是先使用点选式的函数和列选择来入手。函数库包括以下分组:

  • 条件
  • 列特定条件
  • 转换
  • 日期
  • 数学
  • 文本
  • 汇总
  • 窗口函数运算
  • 数组
  • JSON
  • PostGIS(地理空间)
  • 三角函数

完成表达式后,请保存表达式,使其应用于该列。

可在表达式区域查看示例和表达式函数。

在所有数据仓库上,cast(x, Float) 都会返回 64 位双精度数,因此像 1225541207.71 这样的金额会保留每一位数字。在 StarRocks 上,现在会应用到 Float 的转换(此前会被跳过);在 Databend 上,它是双精度而不是单精度。PlaidCloud 根据浮点数据创建的 Float 列同样是双精度。已有单精度列的表,在下次由步骤使用覆盖重建时会变为双精度。

在 StarRocks 上:

  • 转换为大整数可容纳超过约 21 亿的值。
  • 未指定精度的 Numeric 转换会保留小数(最多 10 位),而不是四舍五入为整数。
  • 会应用到 JSON 的转换。

在所有数据仓库上,无法转换的值(例如将非数字文本转换为数字)会变为 null,而不是使步骤停止。

sqlalchemy.literal_column 会将一段 SQL 原样传递给数据仓库,并且只接受单个值:列、计算、CASE、函数调用、转换或窗口函数。包含子查询((SELECT ... FROM ...))的 literal_column 会被拒绝,因为子查询会访问步骤从未声明的表。

本节中的规则适用于编写表达式的任何位置:此处的映射器、步骤的筛选器,以及在其他位置组装并发送到平台的查询。它们会在保存步骤时以及将表达式转换为 SQL 时再次检查。

请改用 sqlalchemy.select(...) 构建子查询:需要在列中得到单个值时使用 .scalar_subquery(),需要从中选择数据时使用 .subquery():

# Refused
sqlalchemy.literal_column('(SELECT rate FROM fx WHERE fx.cc = t.cc)')
# Supported — a single value in a column
sqlalchemy.select(fx.c.rate).where(fx.c.cc == t.c.cc).scalar_subquery()
# Supported — a table to select from
sqlalchemy.select(fx.c.rate).subquery()

最外层运算符为 OR 的 literal_column 同样会被拒绝。PlaidCloud 会原样传递文本,因此在其后添加的条件只会绑定到其中一半:a OR b 后面跟 AND region = 'East' 会被解读为 a OR (b AND region = 'East'),本应排除的行会被返回。

加上括号即可像以前一样工作:

# Refused
sqlalchemy.literal_column("status = 'open' OR status = 'pending'")
# Supported
sqlalchemy.literal_column("(status = 'open' OR status = 'pending')")

表达式内部任意位置的析取(例如在 CASE 中,或已加括号)不受影响。

无论是否加括号,XOR 在出现的任何位置都会被拒绝:各数据仓库对其绑定优先级的处理不一致,因此不存在在所有位置都安全的解读。请改为写成 (a AND NOT b) OR (NOT a AND b)。

带有注释的 literal_column 出于同样的原因也会被拒绝:注释会延伸到语句末尾,因此会抹去 PlaidCloud 在您的表达式之后添加的任何内容,而不仅仅是您所写的内容。

-- 在会波及语句其余部分的位置会被拒绝。# 在文本中的任何位置都会被拒绝,没有例外,包括在带引号的字符串内,也包括 Postgres 的 #> 和 #>> JSON 路径运算符:

# Refused
sqlalchemy.literal_column("attrs #> '{a,b}'")
sqlalchemy.literal_column("code || '#'")

在 StarRocks 等兼容 MySQL 的数据仓库上,# 会开启注释;而且编写表达式时,PlaidCloud 并不知道将由哪个数据仓库运行它,因此文本中没有任何位置是可靠安全的,在一个引擎看来带引号的 #,在另一个引擎看来却是注释的开头。如果需要将该字符作为数据,请将其作为值传入:

# Supported
sqlalchemy.func.concat(table.code, sqlalchemy.literal('#'))

.op('...') 中同样会拒绝这两种写法。

literal_column 的其他常规用法不受影响:literal_column('current_date')、literal_column("CASE WHEN amount > 0 THEN 'p' ELSE 'n' END") 和 func.count() 都和以前一样可用。包含空格、点或引号的列名也不受影响,数据仓库会为您加上引号。