本文档介绍了有关 Dataform 代码库的以下信息:
Dataform 中的代码库最佳实践概览
本部分概述了在 Dataform 中管理代码库大小、代码库结构和代码生命周期的最佳实践。
有关代码库大小的最佳实践
代码库大小会影响 Dataform 中的多个开发方面,例如:
- 协作
- 代码库可读性
- 开发流程
- 工作流编译
- 执行工作流
Dataform 会对编译资源实施 API 配额和限制。如果代码库过大,可能会导致代码库超出这些配额和限制。这可能会导致工作流编译和执行失败。
为降低此风险,我们建议您拆分大型代码库。拆分大型代码库时,您需要将大型工作流拆分为多个较小的工作流,这些工作流位于不同的代码库中,并通过跨代码库依赖项连接在一起。
这种方法可让您遵守 Dataform 配额和限制、实现精细的流程和权限,并提高代码库的可读性和协作性。不过,管理拆分的代码库可能比管理单个代码库更具挑战性。
如需详细了解代码库大小在 Dataform 中的影响,请参阅代码库大小概览。 如需详细了解拆分代码库的最佳实践,请参阅拆分代码库。
代码库结构方面的最佳实践
我们建议您以反映工作流程阶段的方式来组织 definitions
目录中的文件。请注意,您可以采用最符合自己需求的自定义结构。
以下推荐的 definitions
子目录结构反映了大多数工作流程的关键阶段:
sources
用于存储数据源声明。intermediate
用于存储数据转换逻辑。output
用于存储输出表的定义。extras
(可选),用于存储其他文件。
Dataform 中所有文件的名称都必须符合 BigQuery 表命名指南。我们建议 Dataform 代码库中 definitions
目录中的文件名称反映子目录结构。
如需详细了解在代码库中组织和命名文件的最佳实践,请参阅在代码库中组织代码。
代码生命周期最佳实践
Dataform 中的默认代码生命周期包含以下阶段:
在 Dataform 工作区中开发工作流代码。
您可以使用 Dataform 核心或仅使用 JavaScript 进行开发。
-
您可以通过发布配置和工作区编译替换来配置自定义编译结果。
借助发布配置,您可以配置整个代码库的自定义编译结果。您稍后可以在工作流配置中安排它们的执行时间。
借助工作区编译替换,您可以为代码库中的所有工作区配置编译替换,从而为每个工作区创建自定义编译结果。
在 BigQuery 中执行编译结果。
您可以使用工作流配置来安排执行或代码库编译结果。
如需在 Dataform 中管理代码生命周期,您可以创建执行环境,例如开发环境、预演环境和生产环境。
如需详细了解 Dataform 中的代码生命周期,请参阅 Dataform 中的代码生命周期简介。
您可以选择将执行环境保存在单个代码库中,也可以保存在多个代码库中。
单个代码库中的执行环境
您可以在单个 Dataform 代码库中使用工作区编译替换和版本配置来创建隔离的执行环境,例如开发环境、预演环境和生产环境。
您可以通过以下方式创建隔离的执行环境:
- 按架构拆分开发表和生产表。
- 按架构和 Google Cloud 项目拆分开发表和生产表。
- 按 Google Cloud 项目拆分开发、预演和生产表。
然后,您可以使用工作流配置在预演环境和生产环境中安排执行。 我们建议在开发环境中手动触发执行。
如需详细了解在 Dataform 中管理工作流生命周期的最佳实践,请参阅工作流生命周期最佳实践。
多个代码库中的代码生命周期
为了根据代码生命周期的每个阶段量身定制 Identity and Access Management 权限,您可以创建多个代码库副本,并将它们存储在不同的 Google Cloud 项目中。
每个 Google Cloud 项目都充当与代码生命周期阶段(例如开发和生产)相对应的执行环境。
在这种方法中,我们建议在所有项目中保持代码库的代码库相同。如需自定义每个代码库副本中的编译和执行,请使用工作区编译替换、发布配置和工作流配置。
代码库大小概览
本部分将帮助您了解代码库大小对工作流开发和 Dataform 编译资源使用情况的影响,以及如何估算代码库的编译资源使用情况。
Dataform 中的代码库大小
代码库的大小会影响 Dataform 中的以下开发方面:
协作。多位协作者处理大型代码库时可能会创建过多的拉取请求,从而增加合并冲突的风险。
代码库可读性。单个代码库中构成工作流的文件数量过多可能会导致难以浏览该代码库。
开发流程。单个代码库中大型工作流的某些区域可能需要自定义权限或流程(例如调度),这些权限或流程与应用于工作流其余部分的权限和流程不同。如果代码库过大,就很难根据工作流程的特定领域调整开发流程。
工作流编译。Dataform 会对编译资源用量设置限制。如果代码库过大,可能会超出这些限制,导致编译失败。
工作流执行。在执行期间,Dataform 会在工作区内运行代码库代码,并将资源部署到 BigQuery。代码库越大,Dataform 运行所需的时间就越长。
如果大型代码库对您在 Dataform 中的开发工作造成了负面影响,您可以将代码库拆分为多个较小的代码库。
关于代码库编译资源限制
在开发期间,Dataform 会编译工作区内的所有代码库代码,以生成代码库中工作流的表示形式。这称为“编译结果”。Dataform 会对编译资源实施用量限额。
您的代码库可能因以下原因而超出使用限额:
- 代码库代码中存在无限循环 bug。
- 代码库代码中的内存泄漏 bug。
- 代码库较大,大约有 1, 000 多个工作流操作。
如需详细了解编译资源的用量限制,请参阅 Dataform 编译资源限制。
估算代码库的编译资源用量
您可以估算代码库中以下编译资源的使用情况:
- CPU 时间使用情况。
- 在您的代码库中定义的生成的操作图的最大序列化数据总大小。
如需大致了解代码库当前编译的 CPU 时间使用情况,您可以在本地 Linux 或 macOS 机器上对 Dataform 工作流的编译进行计时。
如需为工作流的编译计时,请在代码库中运行以下格式的 Dataform CLI 命令
dataform compile
:time dataform compile
以下代码示例展示了执行
time dataform compile
命令的结果:real 0m3.480s user 0m1.828s sys 0m0.260s
您可以将 real
结果视为代码库编译的 CPU 时间使用情况的大致指标。
如需大致了解代码库中生成的行动图的总大小,您可以将该图的输出写入 JSON 文件。您可以将未压缩的 JSON 文件的大小视为图表总大小的粗略指标。
如需将工作流的已编译图的输出写入 JSON 文件,请在您的代码库中运行以下 Dataform CLI 命令:
dataform compile --json > graph.json
拆分代码库
本部分讨论了拆分 Dataform 代码库和管理跨代码库依赖项的策略。
存储库是 Dataform 中的核心单元。代码库存储构成工作流的所有 SQLX 和 JavaScript 文件,以及 Dataform 配置文件和软件包。您可以将工作流存储在单个代码库中,也可以将工作流拆分到多个代码库中。
在 Dataform 中拆分代码库具有以下优势:
- 遵守 Dataform 对编译资源使用情况的限制。将大型工作流拆分为多个较小的代码库可降低超出 Dataform 编译资源限制的风险。
- 细化流程。您可以为工作流的每个拆分片段以及开发该片段的团队单独设置流程,例如持续集成 (CI) 规则。
- 细化权限。您可以为工作流的每个拆分片段以及开发该片段的团队单独设置权限,以提高工作流的整体安全性。
- 通过尽可能减少处理工作流每个拆分片段的协作者数量来改进协作。
- 提高代码库的可读性。将构成大型工作流的文件拆分为多个代码库,这样一来,您就可以更轻松地单独浏览每个代码库,而无需一次性浏览整个工作流。
- 与执行整个工作流相比,加快执行工作流的每个拆分片段。
在 Dataform 中拆分代码库存在以下缺点:
- 每个 Dataform 代码库及其对应的 Git 代码库所需的自定义持续集成和持续开发 (CI/CD) 配置。
- 每个 Dataform 代码库及其对应的 Git 代码库都需要自定义调度配置。
- 难以管理工作流中位于多个代码库中的对象之间的依赖关系。
- 无法全面直观地呈现在多个代码库之间拆分的 SQL 工作流的有向无环图 (DAG)。在每个代码库中,生成的 DAG 仅表示完整工作流的一部分。
拆分代码库的策略
拆分代码库时,您需要将构成父 SQL 工作流的文件拆分为较小的子工作流,这些子工作流位于单独的 Dataform 代码库中。
您可以选择采用以下任一方式拆分代码库:
- 每个开发团队一个代码库。
- 每个网域一个代码库,例如销售、营销或物流。
- 一个中央代码库,以及每个网域一个使用中央代码库的内容作为数据源的代码库。
如需将父工作流托管在第三方 Git 托管平台上,您需要将包含子工作流的每个单独的代码库分别连接到专用的第三方 Git 代码库。
管理跨代码库依赖项
拆分代码库的最有效方法是将父 SQL 工作流划分为独立的子工作流,从而创建独立的代码库。独立代码库不使用其他代码库的内容作为数据源。此方法不需要管理跨代码库依赖项。
如果无法避免跨代码库依赖项,您可以将一个代码库拆分为一系列代码库,其中每个代码库都依赖于其前身,并是其后继代码库的数据源,从而管理这些依赖项。代码库及其依赖项的顺序必须最能反映父工作流的结构。
您可以使用 Dataform 数据源声明在存储库之间创建依赖关系。您可以将其他 Dataform 代码库中的 BigQuery 表类型声明为正在编辑的代码库中的数据源。声明数据源后,您可以像引用任何其他 Dataform 工作流操作一样引用该数据源,并使用它来开发工作流。
如果您要安排执行在具有跨代码库依赖项的代码库之间拆分的工作流,则必须按跨代码库依赖项的顺序逐个运行代码库。
我们建议避免将代码库拆分为一组具有双向依赖关系的代码库。当一个存储库是另一个存储库的数据源,并且还使用该存储库作为数据源时,就会出现存储库之间的双向依赖关系。存储库之间的双向依赖关系会使父工作流的调度和执行以及开发流程变得复杂。
在代码库中构建代码
本部分介绍了在 Dataform 代码库的根 definitions
目录中构建和命名工作流文件的最佳实践。definitions
目录的推荐结构反映了工作流的各个阶段。您可以采用任何符合您业务需求的结构。
您可能需要出于以下原因将工作流代码放在 definitions
目录中:
- 通过为工作流的选定部分指定团队,改进代码库协作。
- 在组织发生变化时,提高工作流程的可维护性。
- 改进了代码库的导航。
- 提高代码库的可伸缩性。
- 最大限度地减少团队的管理开销。
definitions
目录的推荐结构
Dataform 代码库中的根 definitions
目录包含用于创建工作流元素的代码。您可以将 definitions
目录中的文件整理成反映工作流结构的目录结构。
在开发工作流时,您需要声明源表并对其进行转换,以创建可用于业务或分析目的的输出表。
您可以区分工作流程的三个关键阶段:
- 数据源声明。
- 源数据的转换。
- 转换后的源数据的输出表定义。
definitions
目录中的以下子目录结构反映了工作流的关键阶段:
sources
- 数据源声明和源数据的基本转换(例如过滤)。
intermediate
- 从
sources
读取数据并在您使用转换后的数据定义outputs
表之前转换数据的表和操作。在 Dataform 将这些表运行到 BigQuery 后,这些表通常不会再暴露给其他流程或工具(例如商业智能 [BI] 工具)。 outputs
- 在 Dataform 于 BigQuery 中运行后,供流程或工具(例如 BI)使用的表的定义。
extra
- 工作流主流水线之外的文件,例如包含为其他用途(如机器学习)准备的工作流数据的文件。可选的自定义子目录。
有关“sources
”目标的最佳实践
sources
子目录包含工作流的第一阶段:声明和基本转换源数据。
在 sources
子目录中,存储用于过滤、分类、转换或重命名列的数据源声明和表。
避免存储合并了来自多个来源的数据的表。
转换存储在 intermediate
子目录中的表中的 sources
数据。
如果您声明了来自多个池(例如 Google Ads 或 Google Analytics)的数据源,请为每个池专门设置一个子目录。
以下示例展示了 sources
的子目录结构,其中包含两个来源池:
definitions/
sources/
google_ads/
google_ads_filtered.sqlx
google_ads_criteria_metrics.sqlx
google_ads_criteria_metrics_filtered.sqlx
google_ads_labels.sqlx
google_ads_labels_filtered.sqlx
google_analytics/
google_analytics_users.sqlx
google_analytics_users_filtered.sqlx
google_analytics_sessions.sqlx
如果您在同一架构中声明了多个数据源表,则可以将它们的声明合并到单个 JavaScript 文件中。
如需详细了解如何使用 JavaScript 创建数据源声明,请参阅完全使用 JavaScript 创建工作流。
以下代码示例展示了单个 JavaScript 文件中声明的一个架构内的多个数据源:
[
"source_table_1",
"source_table_2",
"source_table_3"
].forEach((name) =>
declare({
database: "gcp_project",
schema: "source_dataset",
name,
})
);
为了防止工作流受到数据源更改的影响,您可以为每个数据源声明(例如 analytics_users_filtered.sqlx
)创建一个视图。视图可以包含源数据的基本过滤和格式设置。
将视图存储在 sources
子目录中。
然后,在创建 intermediate
或 outputs
表时,引用这些视图,而不是原始源表。通过此方法,您可以测试源表。如果源表发生更改,您可以修改其视图,例如添加过滤条件或重新转换数据。
有关“intermediate
”目标的最佳实践
intermediate
子目录包含工作流的第二阶段:转换和汇总来自一个或多个来源的源数据。
在 intermediate
子目录中,存储可显著转换 sources
子目录中一个或多个来源的源数据的文件,例如联接数据的表。intermediate
子目录中的表通常会查询源表或其他 intermediate
表中的数据。
使用 intermediate
表创建 outputs
表。通常,在 Dataform 将 intermediate
表运行到 BigQuery 后,不会再将这些表用于其他用途(例如数据分析)。您可以将 intermediate
表视为可创建输出表的数据转换逻辑。
有关“outputs
”目标的最佳实践
outputs
子目录包含工作流程的最后阶段:根据转换后的数据创建用于业务目的的输出表。
在 outputs
目录中,存储您计划在 Dataform 将表运行到 BigQuery 后在其他流程或工具中使用的表,例如报告或信息中心。outputs
目录中的表通常会查询 intermediate
表中的数据。
按业务实体(例如营销、订单或分析)对 outputs
表进行分组。为每个营业实体分配一个子目录。
如需在 BigQuery 中单独存储输出表,您可以为输出表配置专用架构。如需了解如何配置表架构,请参阅替换表设置。
以下示例展示了 outputs
的子目录结构,其中包含 sales
和 marketing
业务实体:
definitions/
outputs/
orders/
orders.sqlx
returns.sqlx
sales/
sales.sqlx
revenue.sqlx
marketing/
campaigns.sqlx
命名策略
Dataform 中所有文件的名称都必须符合 BigQuery 表格命名指南。
我们建议 Dataform 代码库中 definitions
目录中的文件名称反映子目录结构。
在 sources
子目录中,文件名应指向文件所关联的来源。在文件名中添加来源名称作为前缀,例如 analytics_filtered.sqlx
在 intermediate
子目录中,文件名应标识子目录,以便协作者清楚地区分 intermediate
文件。选择一个唯一的前缀,并仅将其应用于 intermediate
目录中的文件,例如 stg_ads_concept.sqlx
。
在 outputs
子目录中,文件名应简洁明了,例如 orders.sqlx
。如果您在不同的实体子目录中有 outputs
个同名表,请添加用于标识实体的前缀,例如 sales_revenue.sqlx
或 ads_revenue.sqlx
。
以下示例展示了 definitions
目录中的子目录结构,其中的文件名符合建议的命名策略:
definitions/
sources/
google_analytics.sqlx
google_analytics_filtered.sqlx
intermediate/
stg_analytics_concept.sqlx
outputs/
customers.sqlx
sales/
sales.sqlx
sales_revenue.sqlx
ads/
campaigns.sqlx
ads_revenue.sqlx
后续步骤
- 如需详细了解 Dataform 中的代码生命周期以及配置代码生命周期的不同方式,请参阅 Dataform 中的代码生命周期简介。
- 如需详细了解工作流生命周期的最佳实践,请参阅工作流生命周期的最佳实践。
- 如需详细了解 Dataform 编译资源限制,请参阅 Dataform 编译资源限制。
- 如需了解如何将 Dataform 代码库连接到第三方 Git 代码库,请参阅连接到第三方 Git 代码库。
- 如需详细了解 Dataform 中的工作流,请参阅工作流概览。