dbt的主要目的是通过简单地编写SQL语句,帮助您以轻松且集成的方式转换数据平台的数据。当我们将dbt纳入ELT工作流时,它与转换阶段的活动相匹配,为您提供额外的组件,如版本控制、文档、测试或自动部署,从而简化数据专家的整体工作。这是否让您想起了分析工程师的实际活动?嗯,那是因为dbt是定义分析工程师所做工作的现代工具之一,为他们提供与平台集成的工具,减少了为解决特定问题而设置额外服务的需求,并减少了整体系统复杂性。
dbt支持分析工程师描述的任务,使他们能够协同在数据平台上运行代码,实现度量和业务定义的单一真相。它促进了中心化和模块化的分析代码,利用了Jinja模板语言、宏或包中的DRY代码。同时,dbt还提供了通常在软件工程最佳实践中找到的安全性,例如在数据模型上进行协作、版本控制、测试和在安全地部署到生产环境之前对查询进行文档化,监控和可见性。
我们已经提供了对dbt的全面介绍。然而,在本章中,我们将更深入地探讨dbt的具体细节,并澄清其在数据分析领域的重要性。我们将讨论dbt的设计哲学、支持该转换工具的原则以及dbt在其核心的数据生命周期,展示dbt如何将原始数据转换为易于消费的结构化模型。我们将通过概述其各种功能,如构建模型、文档和测试,以及详细说明其他dbt工件,如YAML文件,来探索dbt项目结构。
通过本章的最后,您将对dbt及其功能有全面的了解,这将使您能够在数据分析工作流中有效地实施它。
dbt设计哲学
随着数据工程和分析工作流程变得越来越复杂,工具在简化过程同时保持数据质量和可靠性方面至关重要。dbt已经成为一种集中解决方案,具有明确定义的设计哲学,支持其对数据建模和分析工程的方法。
总的来说,dbt的设计哲学依赖于以下几点:
-
以代码为中心的方法
dbt的设计哲学的核心是以代码为中心的数据建模和转换方法。与依赖于基于GUI的界面或手动SQL脚本不同,dbt鼓励用户使用代码定义数据转换。这种转向代码驱动的开发促进了协作、版本控制和自动化。
-
用于可重用性的模块化
dbt促进可重用代码组件的模块化。模型、宏和测试可以组织成包,从而促进代码维护和可伸缩性。这种模块化方法与最佳实践一致,增强了代码的可重用性。
-
将转换作为SQL SELECT语句
dbt模型被定义为SQL SELECT语句,使分析师和具有SQL技能的工程师能够访问它们。这种设计选择简化了开发,并确保数据建模紧密遵循SQL最佳实践。
-
声明性语言
dbt使用声明性语言来定义数据转换。分析师指定所需的结果,dbt处理底层实现。这种抽象降低了编写复杂SQL代码的复杂性,并增强了可读性。
-
增量构建
dbt的设计关注效率。它支持增量构建,允许数据工程师仅更新受影响的数据流水线部分,而不是重新处理整个数据集。这加速了开发并减少了处理时间。
-
文档即代码
dbt主张将数据模型和转换的文档化作为代码。描述、解释和元数据存储在项目代码旁边,使团队成员更容易理解并有效协作。数据质量、测试和验证
dbt非常强调数据测试。它提供了一个测试框架,使分析师能够定义数据质量检查和验证规则。这包括整个流水线中的数据可靠性和质量,从而确保数据符合预定义的标准并遵循业务规则。
- 版本控制集成
与Git等版本控制系统的无缝集成是dbt的基本特征。这个功能实现了协作开发、变更跟踪以及回滚变更的能力,确保数据流水线保持在版本控制之下。
- 与数据平台的本地集成
dbt被设计成与Snowflake、BigQuery和Redshift等流行的数据平台无缝配合。它利用这些平台的本地能力,以实现可扩展性和性能。
- 开源和可扩展
dbt是一个开源工具,拥有繁荣的社区。用户可以通过创建自定义宏和包来扩展其功能。这种可扩展性允许组织根据其特定的数据需求定制dbt。
- 转换和加载的分离
dbt在数据流水线中将转换和加载步骤分开。数据在dbt内部进行转换,然后加载到数据平台。
实质上,dbt的设计哲学根植于为数据工程师、分析师和数据科学家创建一个协作、以代码为中心和模块化的环境,以便有效地转换数据、确保数据质量并生成有价值的见解。dbt通过简化数据建模和分析工程的复杂性,赋予组织充分发挥其数据的潜力。
dbt工作流
图4-1展示了数据流的整体图景。它确定了dbt及其功能在整体数据景观中的位置。
正如前文提到的,dbt的主要目的是帮助您转换数据平台的数据,为此,dbt提供了两个工具来实现这一目标:
• dbt Cloud
• dbt Core,这是一个由dbt Labs维护的开源CLI工具,您可以在托管的环境上设置,也可以在本地运行
让我们通过一个示例来了解dbt在实际生活中的工作原理以及它能做什么。想象一下,我们正在处理一个定期从诸如BigQuery之类的数据平台提取数据的流水线,然后通过合并表格进行数据转换(图4-2)。 我们将前两个表格合并成一个,应用多种转换技术,如数据清理或合并。这个阶段发生在dbt中,所以我们需要创建一个dbt项目来完成这个合并。我们会讲到这一点,但首先让我们熟悉一下dbt Cloud以及如何设置我们的工作环境。
在本书中,我们将使用dbt Cloud来编写我们的代码,因为这是使用dbt的最快且最可靠的方式,从开发到编写测试、调度、部署以及调查数据模型。此外,dbt Cloud是在dbt Core的基础上运行的,因此在使用dbt Cloud时,我们将熟悉在dbt Core的CLI工具中使用的相同命令。
dbt Cloud
dbt Cloud是dbt的云端版本,提供了广泛的功能和服务,可用于编写和产品化您的分析代码。dbt Cloud允许您安排dbt作业、监视其进度,并实时查看日志和指标。dbt Cloud还提供高级协作功能,包括版本控制、测试和文档。此外,dbt Cloud与各种云数据仓库集成,如Snowflake、BigQuery和Redshift,使您能够轻松转换您的数据。
您可以使用dbt Core并获得大多数上述功能,但这将需要在您的基础设施上进行配置和设置,类似于运行自己的服务器或Amazon Elastic Compute Cloud(EC2)实例用于诸如Airflow之类的工具。这意味着您需要自主维护和管理它,类似于在EC2上管理虚拟机(VM)。
相比之下,dbt Cloud的运作方式类似于托管服务,类似于Amazon Managed Workflows for Apache Airflow (MWAA)。它提供了便利性和易用性,因为许多操作方面都为您处理,使您能够更专注于分析任务,而不是基础设施管理。
使用BigQuery和GitHub设置dbt Cloud
通过实际操作来学习特定技术是最好的方式,所以让我们设置一下我们将用于应用知识的环境。首先,让我们注册一个dbt账户。
注册后,我们将进入Complete Project Setup页面(图4-3)。
该页面有多个部分,可以正确配置我们的dbt项目,包括连接到我们期望的数据平台和连接到我们的代码存储库。我们将使用BigQuery作为数据平台,并使用GitHub存储我们的代码。
在BigQuery中的第一步是设置一个新项目。在GCP中,通过搜索栏搜索"Create a Project"并点击它(图4-4)。
会出现一个类似于图4-5的屏幕,您可以在其中设置项目。我们将其命名为dbt-analytics-engineer。
配置完成后,进入您的BigQuery IDE(可以再次使用搜索栏)。它应该类似于图4-6。
最后,测试dbt公共数据集以确保BigQuery正常工作。为此,请将示例4-1中的代码复制到BigQuery中,然后点击运行。 示例4-1. 在BigQuery中的dbt公共数据集
csharp
select * from `dbt-tutorial.jaffle_shop.customers`;
select * from `dbt-tutorial.jaffle_shop.orders`;
select * from `dbt-tutorial.stripe.payment`;
如果您看到图4-7中的页面,那么您成功了!
现在让我们将dbt与BigQuery连接,并在dbt IDE中执行这些查询。为了让dbt连接到您的数据平台,您需要生成一个密钥文件,类似于在大多数其他数据平台中使用数据库用户名和密码。
进入BigQuery控制台。在继续下一步之前,请确保在页头中选择了新项目。如果看不到您的帐户或项目,请点击右侧的个人资料图片,并验证您是否使用了正确的电子邮件帐户:
- 进入IAM & Admin,选择Service Accounts。
- 点击Create Service Account。
- 在名称字段中键入dbt-user,然后点击Create and Continue。
- 在"授予此服务帐户对项目的访问权限"中,在角色字段中选择BigQuery Admin。点击Continue。
- 在"授予用户对此服务帐户的访问权限"部分留空字段,然后点击Done。
屏幕应该看起来像图4-8。
继续进行,执行剩下的步骤:
- 点击刚刚创建的服务帐户。
- 选择Keys。
- 点击Add Key;然后选择"Create new key"。
- 选择JSON作为密钥类型;然后点击Create。
- 应该会提示您下载JSON文件。将其保存到本地一个容易记住的位置,并使用清晰的文件名,例如dbt-analytics-engineer-keys.json。
现在让我们回到dbt Cloud进行最后的设置:
- 在项目设置屏幕上,为您的项目提供一个更详细的名称。在我们的案例中,我们选择了dbt-analytics-engineer。
- 在"Choose a warehouse"屏幕上,点击BigQuery图标然后点击Next。
- 上传先前生成的JSON文件。为此,点击Figure 4-9中可见的"Upload a Service Account JSON file"按钮。 最后但并非最不重要的,在上传文件之后,执行剩下的步骤:
- 转到底部并点击"test"。如果看到"Your test completed successfully"(如图4-10所示),那么一切就绪!现在点击Next。另一方面,如果测试失败,很有可能您遇到了与BigQuery凭据有关的问题。尝试重新生成它们。
最后一步是设置GitHub,但首先,让我们了解我们在讨论什么。GitHub是一个流行的版本控制平台,托管Git存储库,允许您跟踪代码的变化并有效地与他人合作。要正确使用Git,遵循这些原则和最佳实践是至关重要的:
- 频繁提交,早期提交
经常提交,即使是小的更改也要提交。这有助于跟踪您的进度并简化调试。每次提交应代表一个逻辑变更或功能。
- 使用有意义的提交消息
编写简洁且描述性的提交消息。一个好的提交消息应该解释发生了什么变化以及为什么要变更。
- 遵循分支策略
使用分支来处理不同的功能、bug修复或开发任务。
- 在推送之前拉取
在推送更改之前,始终从远程存储库拉取最新的更改(例如,git pull)。这减少冲突并确保您的更改基于最新的代码。
- 在提交之前审查代码
如果您的团队进行代码审查,请确保在提交之前审查和测试您的更改。这有助于保持代码质量。
- 使用.gitignore
创建一个.gitignore文件,用于指定应从版本控制中排除的文件和目录(例如,构建产物、临时文件)。
- 使用原子提交
使提交专注于单一、特定的更改。避免在同一次提交中混合无关的更改。
- 使用重整而不是合并
使用git rebase将特性分支中的更改整合到主分支中,而不是传统的合并。这将产生一个更干净的提交历史。
- 保持提交历史清晰
避免提交"正在进行中"的工作或调试语句。使用git stash等工具暂时保存未完成的工作。
- 使用标签
创建标签,如版本标签,以标记项目历史中的重要节点,例如
- 协作和沟通
与团队沟通Git工作流和惯例。建立处理问题、拉取请求和冲突解决的指南。
- 了解如何撤销更改
学习如何撤销提交(git revert)、重置分支(git reset)以及在需要时恢复丢失的工作(git reflog)。
- 文档
在README或贡献指南中记录项目的Git工作流和惯例,以有效地帮助新团队成员融入。
- 使用备份和远程存储库
定期备份您的Git存储库,并使用GitHub等远程存储库进行协作和冗余。
- 持续学习
Git是一个功能强大的工具,具有许多功能。持续学习并探索高级的Git概念,如挑选、交互式重整和自定义挂钩,以改进您的工作流程。
为了更好地实践一些常见的Git术语和命令,让我们看一下表4-1。
这些Git命令和术语为您的项目提供了版本控制的基础。然而,Git命令通常有许多额外的参数和选项,允许对版本控制任务进行精细的控制。虽然我们在这里涵盖了一些基本命令,但重要的是要注意Git的多功能性远远超出了我们概述的范围。
为了更全面地了解Git命令及其可以接受的各种参数,我们建议查阅官方的Git文档。
现在您了解了Git和GitHub以及它们在项目中的作用,让我们建立与GitHub的连接。为此,您需要执行以下操作:
- 如果还没有GitHub账户,请注册一个GitHub账户。
- 单击New创建一个新的存储库,这是您将版本化您的分析代码的地方。在"创建新存储库屏幕"上,为您的存储库命名,然后点击"Create repository"。
- 创建了存储库后,让我们回到dbt。在"设置存储库"部分,选择GitHub,然后连接GitHub账户。
- 单击"Configure GitHub Integration"打开一个新窗口,在该窗口中可以选择安装dbt Cloud的位置。然后选择要安装的存储库。
现在点击"Start developing in the IDE"(在IDE中开始开发)。图4-11是您应该期望看到的内容。
我们将在第163页的"使用dbt Cloud IDE"中概述dbt Cloud集成开发环境(IDE),并在第165页的"dbt项目结构"中更详细地介绍它。
点击左上角的"Initialize dbt project"。现在,您应该能够看到如图4-12所示的屏幕。
我们将在第165页的"dbt项目结构"中详细介绍每个文件夹和文件。现在,让我们看看查询是否有效。通过复制示例4-2中的代码,然后点击Preview来再次运行它们。 示例4-2. 在BigQuery中使用dbt进行测试的dbt公共数据集
csharp
--select * from `dbt-tutorial.jaffle_shop.customers`;
--select * from `dbt-tutorial.jaffle_shop.orders`;
select * from `dbt-tutorial.stripe.payment`;
如果输出看起来类似于图4-13,那就意味着您的连接有效。然后,您可以向您的数据平台提交查询,对我们来说,即是BigQuery。
这里提供的步骤是dbt中BigQuery适配器的文档的一部分。随着技术的发展和改进,这些步骤和配置也可能发生变化。为确保您获取最新的信息,请参考最新的dbt BigQuery文档。这个资源将为您提供与dbt和BigQuery一起工作的最新指导和说明。
最后,让我们通过进行第一次"提交和推送"来测试您的GitHub集成是否正常工作。单击左侧可见的带有相同描述的按钮,如图4-14所示。一个弹出屏幕,如图4-14右侧的图像所示,将出现,您可以在其中编写提交消息。然后点击Commit Changes。
由于我们没有创建Git分支,它将在主分支内对我们的代码进行版本管理。进入您在此设置过程中创建的GitHub存储库,查看您的dbt项目是否存在。图4-15应该与您在GitHub存储库上看到的内容类似。
使用dbt Cloud用户界面
当您登录dbt Cloud时,初始页面会显示欢迎消息和作业执行历史的摘要。正如图4-16所示,一开始页面是空的,但一旦我们创建并运行了第一个作业,就会开始看到信息。在第212页的"作业和部署"中,我们将更详细地介绍作业的执行情况。
在顶部工具栏上,您会看到几个选项。从左边开始,您可以访问"Develop"页面,您将在该页面开发所有的分析代码并创建您的模型、测试和文档。这是dbt开发的核心,我们将在第163页的"使用dbt Cloud IDE"中为您提供更多关于此部分的见解,并在第165页的"dbt项目结构"中深入了解每个组件。
紧挨着"Develop"选项的是"Deploy"菜单,如图4-17所示。从该菜单中,您可以配置作业并通过"Run History"监视其执行,配置开发环境,并通过"Data Sources"验证您快照的数据源新鲜度。
"Deploy"菜单的第一个选项是"Run History",打开的页面如图4-18所示。在这里,您可以查看作业的运行历史。在dbt的背景下,作业是您配置的自动化任务或流程,用于执行特定的操作,例如运行模型、测试或生成文档。这些作业是协调dbt的重要组成部分,涉及管理和自动化各种数据转换和分析任务。
假设您已经在此部分配置了已执行的作业,那么您可以检查每个作业的调用和状态。作业的运行历史中提供了丰富的信息,包括其状态、持续时间、作业执行的环境以及其他有用的细节。您可以访问有关作业经历的步骤的信息,包括每个步骤的相应日志。此外,您还可以找到作业生成的工件,如模型、测试或文档。
"Deploy"菜单的下一个选项是"Jobs"。它打开一个页面,用于配置您所有的自动化,包括CI/CD流水线、运行测试和其他激动人心的行为,而无需手动从命令行运行dbt命令。图4-19显示了空的作业起始页面。我们在第212页的"作业和部署"中有一个专门的部分介绍了作业。
第三个"Deploy"菜单选项是"Environments"(环境)。在dbt内部,我们有两种主要类型的环境:开发环境和部署环境。在刚刚设置dbt项目之后,dbt会为您配置开发环境,这在您的dbt项目中一目了然。图4-20显示了"Environments"起始页面,如果您按照第140页的"使用BigQuery和GitHub设置dbt Cloud"中的步骤进行操作,您的页面应该与此类似。
最后,我们有"Data Sources"选项。这个页面如图4-21所示,一旦您配置了一个作业来快照源数据新鲜度,dbt Cloud会自动填充此页面。在这里,您将看到最新快照的状态,可以分析您的源数据新鲜度是否符合您与组织定义的服务水平协议(SLAs)。我们将在第187页的"Source freshness"中为您提供有关数据新鲜度的更好理解,并在第195页的"Testing sources"中介绍如何测试它。
接下来是"Documentation"选项,只要您和您的团队建立例行程序,确保您的dbt项目得到正确的文档记录,这一步就会具有特殊的重要性。适当的文档可以回答诸如以下问题:
- 这些数据的含义是什么?
- 这些数据来自哪里?
- 这些指标是如何计算的?
图4-22显示了项目的文档页面。我们将在第200页的"Documentation"中解释如何在编写代码时利用和撰写dbt项目内的文档。
右上角的菜单允许您选择您的dbt项目(图4-23)。这个简短的菜单使得在不同的dbt项目之间轻松移动变得简单。
您可以通过点击问号符号找到dbt帮助菜单(图4-24)。在这里,您可以通过聊天直接与dbt团队联系,提供反馈,并访问dbt文档。最后,通过帮助菜单,您还可以加入Slack的dbt社区或GitHub上的dbt讨论。
设置菜单,如图4-25所示,是您可以配置与您的帐户、个人资料甚至通知相关的所有内容的地方。
一旦您点击其中的一个选项,您将进入设置页面,类似于图4-26。在第一个页面"帐户设置"中,您可以编辑和创建新的dbt项目,管理用户及其访问控制级别(如果您是所有者),以及管理计费。
第二个菜单选项"配置文件设置"访问"Your Profile"页面(图4-27)。在这个页面上,您可以查看所有的个人信息,管理关联的账户,如GitHub或GitLab、Slack和单点登录(SSO)工具。您还可以查看并编辑为您的数据平台和API访问密钥定义的凭据。
最后,选择"通知设置"选项访问"Notifications center"(图4-28),在这里,您可以配置在作业运行成功、失败或取消时在选择的Slack频道或电子邮件中接收的警报。
使用dbt Cloud IDE
dbt Cloud中的一个关键部分是IDE,您可以在其中编写所有的分析代码,包括测试和文档。图4-29显示了dbt IDE的主要部分。
接下来,您将找到关于每个部分代表什么以及在集成开发环境中的相关性的详细解释:
- Git 控制和文档
这个菜单是您与Git交互的地方。在这里,您可以查看自上次提交以来发生的变化和新增的内容。IDE中的所有Git命令都在这里,您可以决定是提交和推送还是还原您的代码。此外,在窗口的右上角,您可以看到文档图标。一旦生成文档,您可以点击此快捷方式访问项目文档。
- 文件浏览器
文件浏览器为您提供了dbt项目的主要概览。在这里,您可以查看您的dbt项目是如何构建的------通常以.sql、.yml和其他兼容的文件类型的形式。
- 文本编辑器
IDE的这个部分是您编写和完善分析代码的地方。在这里,您还可以编辑和创建项目的其他相关文件,如YAML文件。如果您从文件浏览器中选择这些文件,它们将在这里弹出。多个文件可以同时打开。
- 信息窗口和代码预览、编译和构建
在单击"预览"或"编译"按钮后,此菜单将显示您的结果。预览将编译并运行您的查询,并将结果显示在屏幕底部的"Results"选项卡中。另一方面,编译将把任何Jinja转换为纯SQL。这将显示在屏幕底部的"Compiled Code"选项卡中的信息窗口中。预览或编译按钮适用于语句和SQL文件。
"构建"是一个仅在特定文件中弹出的特殊按钮。根据您选择的构建类型,运行结果将包含有关选择构建的所有模型、测试、种子和快照的信息,合并到一个文件中。
信息窗口在开发过程中排除错误或使用"Lineage"选项卡检查当前在文本编辑器中打开的模型及其祖先和依赖项的数据血缘关系时也很有帮助。
- 命令行
命令行是您执行特定dbt命令的地方,如dbt run或dbt test。在执行命令期间或之后,它还会显示一个弹出屏幕,以显示处理结果------要实现这一点,请单击命令行开头的箭头。日志也可以在此查看。图4-30显示了扩展的命令行;要执行的命令位于顶部,执行的日志在其后。
dbt项目的结构
一个dbt项目是一个由文件夹和文件、编程模式以及命名约定组成的目录。所有您的分析代码、测试、文档和参数化都将包含在这些文件和文件夹中,而dbt将使用这些命名约定和编程模式。您组织文件夹和文件目录的方式即是您的dbt项目结构。
构建一个合适的dbt项目需要付出努力。为了得到很好的实施,它需要将公司的领域和部门汇聚起来,利用它们的专业知识来映射整个公司的目标和需求。因此,定义一组明确、全面且一致的约定和模式是相关的。通过这样做,可以确保项目在公司扩大规模时保持可访问性和可维护性,同时利用dbt为尽可能多的人提供帮助和利益。
您如何组织dbt项目可能会有所不同,并可能受到您或公司指南定义的变更的影响。这并不是问题。重要的是您要以一种明确、可靠的方式明示这些变更,以便所有贡献者都能轻松访问,并且最重要的是要保持一致性。出于本书的目的,我们将保留您在初始化时遇到的dbt项目的基本结构(示例4-3)。
示例4-3. dbt项目的初始结构
root/
├─ analyses/
├─ dbt_packages/
├─ logs/
├─ macros/
├─ models/
│ ├─ example/
│ │ ├─ schema.yml
│ │ ├─ my_second_dbt_model.sql
│ │ ├─ my_first_dbt_model.sql
├─ seeds/
├─ snapshots/
├─ target/
├─ tests/
├─ .gitignore
├─ dbt_project.yml
├─ README.md
每个文件夹和文件将在本章和第5章的后续部分中进行解释。有些会受到更多的强调,并且会比其他文件夹和文件更常用。然而,了解它们的目的是至关重要的:
- analyses 文件夹
在第197页详细介绍,该文件夹通常用于存储用于审计目的的查询。例如,您可能希望在从另一个系统迁移逻辑到dbt时查找差异,并仍然利用dbt的功能,如使用Jinja和版本控制,而无需将其包含在数据平台内构建的模型中。
- dbt_packages 文件夹
是您安装dbt包的地方。我们将在第242页介绍包的概念,但总体思想是包是独立的dbt项目,解决特定的问题,并可以在组织间重复使用和共享。这促进了DRY-er(不要重复自己)的代码,因为您不会一遍又一遍地实现相同的逻辑。
- logs 文件夹
是默认情况下将写入所有项目日志的地方,除非您在dbt_project.yml中进行了不同的配置。
- macros 文件夹
是存储DRY-ing(不要重复自己)转换代码的地方。宏类似于其他编程语言中的函数,是可以多次重复使用的Jinja代码片段。我们将在第236页的"使用SQL宏"中专门详细介绍它们。
- models 文件夹
是dbt中的一个强制性文件夹。一般来说,模型是一个包含SELECT语句的SQL文件,其中包含一个模块化的逻辑部分,将原始数据转换为最终的转换数据。在dbt中,模型的名称指示未来表或视图的名称,或者如果配置为临时模型,则两者都不是。这个主题将在第174页的"模型"中详细介绍。
- seeds 文件夹
是存储我们查找表的地方。我们将在第198页讨论这一点。一般的想法是种子是很少更改的CSV文件,用于对在任何源系统中都不存在的数据建模。一些有用的用例可能包括将邮政编码映射到州,或者我们需要从分析中排除的测试电子邮件列表。
- snapshots 文件夹
包含项目的所有快照模型,必须与models文件夹分开。dbt快照功能记录表随时间的可变变化。它应用了第二类慢变化维度(SCDs),用于识别表中行在时间内如何变化。这将在第230页的"Snapshots"中详细介绍。
- target 文件夹
包含在运行dbt run、dbt compile或dbt test命令时将写入的已编译SQL文件。您可以选择在dbt_project.yml中配置它们写入另一个文件夹。
- tests 文件夹
用于同时测试多个特定的表。这不会是您编写测试的唯一文件夹。许多测试仍将位于您模型文件夹内的YAML文件中,或者通过宏。然而,tests文件夹更适用于单一测试,报告多个特定模型如何相互交互或相关的结果。我们将在第189页的"Tests"中深入讨论这个主题。
- dbt_project.yml
是每个dbt项目的核心。这是dbt知道一个目录是dbt项目的方式,它包含重要的信息,告诉dbt如何在您的项目上操作。我们将在本书的整个过程中介绍这个文件。它也在第170页的"dbt_project.yml"中有所介绍。
- .gitignore 和 README.md
是通常用于您的Git项目的文件。虽然gitignore指定Git在提交和推送期间应忽略的有意文件,但README文件是一个基本的指南,为其他开发人员提供了对您的Git项目的详细描述。
我们将在本章和第5章中更详细地介绍这些文件夹,深入了解dbt项目和其特性。
Jaffle Shop数据库
在本书中,我们将提供一系列关于如何使用dbt的组件和特性的实际示例。在大多数情况下,我们将需要开发SQL查询来最好地展示我们想要展示的内容。因此,有一个我们可以操作的数据库是至关重要的。这个数据库就是Jaffle Shop。
Jaffle Shop数据库是一个简单的数据库,由两个表组成,分别用于存储顾客和订单信息。为了提供更多上下文,我们将使用来自Stripe的一个附加数据库,其中包含与订单相关的支付信息。这三个表将构成我们的原始数据。
我们使用这个数据库的原因是它已经由dbt Labs在BigQuery中公开提供。这是他们文档和课程中使用的主要数据库之一,因此我们希望它将简化在本书的这个阶段学习dbt平台的整体过程。
图4-31展示了代表我们原始数据的ERD,包括顾客、订单和支付。
YAML文件
YAML是一种人类可读的数据序列化语言,通常用于配置文件和在数据存储或传输的应用程序中。在dbt中,YAML用于定义您的dbt项目的组件的属性和一些配置:模型、快照、种子、测试、数据源,甚至实际的dbt项目,即dbt_project.yml。
除了需要具体命名并放置在特定位置的顶层YAML文件(如dbt_project.yml和packages.yml)之外,您组织dbt项目中的其他YAML文件的方式取决于您自己。请记住,与组织dbt项目的其他方面一样,最重要的指导原则是保持一致性,明确您的意图,并记录组织的方式及原因。平衡集中化和文件大小是重要的,以使特定配置尽可能易于找到。以下是关于如何组织、结构和命名您的YAML文件的一些建议:
- 如前所述,平衡配置的集中化和文件大小特别重要。在一个文件中包含所有配置可能使得在项目扩展时难以找到特定配置(尽管在技术上可以使用一个文件)。由于文件的重复性质,使用Git进行变更管理也会变得复杂。
- 根据前述观点,如果我们采用每个文件夹一个配置的方法,从长远来看,保持所有配置更为合适。换句话说,在每个模型文件夹目录中,建议有一个YAML文件,用于简化该目录中所有模型的配置。通过在同一目录中分离模型的配置文件,并为源配置专门创建一个文件,延伸这个规则(示例4-4)。
在这个结构中,我们使用了暂存模型来代表正在讨论的内容,因为它涵盖了大多数情况,如源、YAML文件等。在这里,您可以看到每个文件夹一个配置的系统,其中源和模型的配置是分开的。它还引入了用于文档的Markdown文件,我们将在第200页的"文档"中详细讨论。最后,文件名前面的下划线将所有这些文件放在各自目录的顶部,以便更容易找到。
示例4-4. 模型目录中的dbt YAML文件
root/
├─ models/
│ ├─ staging/
│ │ ├─ jaffle_shop/
│ │ │ ├─ _jaffle_shop_docs.md
│ │ │ ├─ _jaffle_shop_models.yml
│ │ │ ├─ _jaffle_shop_sources.yml
│ │ │ ├─ stg_jaffle_shop_customers.sql
│ │ │ ├─ stg_jaffle_shop_orders.sql
│ │ ├─ stripe/
│ │ │ ├─ _stripe_docs.md
│ │ │ ├─ _stripe_models.yml
│ │ │ ├─ _stripe_sources.yml
│ │ │ ├─ stg_stripe_order_payments.sql
├─ dbt_project.yml
- 使用文档块时,也应遵循相同的方法,为每个模型目录创建一个Markdown文件(.md)。在第200页的"文档"中,我们将更深入地了解这种类型的文件。
建议您在dbt_project.yml文件中在目录级别设置dbt项目的默认配置,并使用级联作用域优先级定义这些配置的变体。这可以帮助您简化dbt项目管理,确保您的配置是一致且易于维护的。例如,借助示例4-4,假设我们的所有暂存模型默认配置为视图。这将在您的dbt_project.yml中进行配置。但是,如果您有一个特定的用例,需要更改jaffle_shop暂存模型的材质化配置,您可以通过修改_jaffle_shop_models.yml文件来执行此操作。通过这种方式,您可以为这组特定模型自定义材质化配置,同时保持项目的其余部分不变。
能够覆盖特定模型的默认配置是通过在dbt项目构建中使用的级联作用域优先级实现的。虽然所有暂存模型将被配置为视图,因为这是默认配置,但通过更新特定的_jaffle_shop_models.yml YAML文件,暂存jaffle_shop模型将被配置为表。
dbt_project.yml
dbt中最关键的文件之一是dbt_project.yml。该文件必须位于项目的根目录,并且是项目的主要配置文件,包含dbt正确运行所需的相关信息。
dbt_project.yml文件在编写更加模块化的分析代码时也具有一定的相关性。一般来说,您的项目默认配置将存储在此处,并且除非在模型级别被覆盖,否则所有对象将从中继承。
以下是您将在此文件中遇到的一些最重要的字段:
- name (必填) dbt项目的名称。我们建议将此配置更改为您的项目名称。同时,记得在模型部分和dbt_project.yml文件中进行相应更改。在我们的案例中,我们将其命名为dbt_analytics_engineer_book。
- version (必填) 项目的核心版本。与dbt版本不同。
- config-version (必填) 版本2是当前可用的版本。
- profile (必填) 在dbt中,profile用于连接到您的数据平台。
- [folder]-paths (可选) 这里的[folder]是dbt项目中的文件夹列表,可以是模型、种子、测试、分析、宏、快照、日志等。例如,model-paths 将指定模型和源文件的目录。macro-paths 是宏代码的位置,以此类推。
- target-path (可选) 此路径将存储编译后的SQL文件。
- clean-targets (可选) 包含由dbt clean命令删除的构件的目录列表。
- models (可选) 模型的默认配置。在示例4-5中,我们希望staging文件夹中的所有模型都以视图的形式材料化。
示例4-5. dbt_project.yml,模型配置
yaml
models:
dbt_analytics_engineer_book:
staging:
materialized: view
packages.yml
包是独立的dbt项目,解决特定问题,并且可以在组织之间重复使用和共享。它们是包含模型和宏的项目;通过将它们添加到您的项目中,这些模型和宏将成为项目的一部分。
要访问这些包,首先需要在packages.yml文件中定义它们。详细步骤如下:
- 确保packages.yml文件在您的dbt项目中。如果没有,请在与dbt_project.yml文件相同的级别创建它。
- 在dbt packages.yml文件中,定义您希望在dbt项目中使用的包。您可以从dbt Hub等源安装包,也可以从Git存储库(如GitHub或GitLab)安装,甚至可以使用本地存储的包。示例4-6展示了每种情况所需的语法。
- 运行
dbt deps
来安装已定义的包。除非您进行了不同的配置,默认情况下,这些包将被安装在dbt_packages
目录中。
示例4-6. 从dbt Hub、Git或本地安装包的语法
yaml
packages:
- package: dbt-labs/dbt_utils
version: 1.1.1
- git: "https://github.com/dbt-labs/dbt-utils.git"
revision: 1.1.1
- local: /opt/dbt/bigquery
profiles.yml
需要设置profiles.yml
,如果使用dbt Cloud则不需要。此文件包含dbt将用于连接到数据平台的数据库连接。由于其包含敏感内容,该文件存在项目之外,以避免将凭据版本化到代码存储库中。如果您的凭据存储在环境变量下,您可以安全地使用代码版本控制。
一旦在本地环境中调用dbt,dbt解析您的dbt_project.yml
文件并获取配置文件名称,这是dbt连接到数据平台所需的。您可以根据需要拥有多个配置文件,但通常每个dbt项目或每个数据平台都有一个配置文件。即使在本书中使用dbt Cloud,也不需要配置文件。如果您感兴趣或更喜欢使用dbt CLI与BigQuery,我们展示了profiles.yml
的示例。
profiles.yml
的典型YAML模式文件如示例4-7所示。我们在本书中使用dbt Cloud,因此不需要配置文件。但是,我们展示了profiles.yml
的示例,以便您了解或更喜欢使用dbt CLI与BigQuery。
示例4-7. profiles.yml
yaml
dbt_analytics_engineer_book:
target: dev
outputs:
dev:
type: bigquery
method: service-account
project: [GCP项目ID]
dataset: [您的dbt数据集的名称]
threads: [1或更多]
keyfile: [/path/to/bigquery/keyfile.json]
<optional_config>: <value>
profiles.yml
的最常见结构具有以下组件:
- profile_name 配置文件的名称必须与
dbt_project.yml
中找到的名称相同。在我们的案例中,我们将其命名为dbt_analytics_engineer_book
。 - target 这是您在不同环境中拥有不同配置的方式。例如,当在本地进行开发时,您可能希望使用单独的数据集/数据库。但是在部署到生产环境时,最好将所有表放在单个数据集/数据库中。默认情况下,
target
被设置为dev
。 - type 您要连接的数据平台的类型:BigQuery、Snowflake、Redshift等。
- 数据库特定的连接细节 示例4-7包括一些属性,如
method
、project
、dataset
和keyfile
,这些属性是设置与BigQuery连接所需的。 - threads dbt项目将运行的线程数。它在模型之间创建了一个链接的DAG。线程数表示dbt可能并行工作的图中路径的最大数量。例如,如果指定
threads: 1
,dbt将仅开始构建一个资源(模型、测试等)并在继续下一个之前完成。另一方面,如果有threads: 4
,dbt将同时处理最多四个模型,而不违反依赖关系。
Models
模型是您作为数据专业人士在dbt生态系统中将花费大部分时间的地方。它们通常以select语句的形式编写,保存为.sql文件,是dbt中最重要的部分之一,将帮助您在数据平台内转换数据。
要正确构建模型并创建清晰一致的项目结构,您需要熟悉数据建模的概念和技术。如果您的目标是成为分析工程师或者说通用地想要处理数据的人,这是核心知识。
正如我们在第2章中看到的,数据建模是通过分析和定义数据需求的过程,创建支持组织业务流程的数据模型。它将您公司收集和生成的源数据塑造成经过转换的数据,满足公司各个领域和部门的数据需求,并生成附加值。
与数据建模一致,并且如第2章中介绍的那样,模块化是正确构建dbt项目、组织模型并保持代码DRY-er的另一个关键概念。从概念上讲,模块化是将问题分解为一组可以分离和重新组合的模块的过程,这降低了系统的整体复杂性,通常具有灵活性和多样性的使用优势。在分析中,这也是一样的。在构建数据产品时,我们不会一次性编写所有代码。相反,我们一步一步地制作,直到达到最终的数据工件。
由于我们将尝试从一开始就引入模块化,我们的初始模型也将考虑到模块化,并与我们在第2章中讨论的内容一致。按照典型的dbt数据转换流程,我们的模型目录将包含三个层次:
- Staging层 我们的初始模块化构建块位于dbt项目的staging层。在此层中,我们与我们的源系统建立了一个接口,类似于API与外部数据源的交互。在这里,数据被重新排序、清理,并准备进行下游处理。这包括数据标准化和设置下游更高级数据处理阶段的小型转换等任务。
- Intermediate层 此层包含在staging层和marts层之间的模型。这些模型建立在我们的staging模型之上,用于进行广泛的数据转换,以及来自多个源的数据合并,从而创建服务于不同目的的各种中间表。
- Marts层 根据您的数据建模技术,marts将所有模块化的部分汇集在一起,以更广泛的视野展示公司关心的实体。例如,如果我们选择了维度建模技术,marts层包含您的事实表和维度表。在这个上下文中,事实是随着时间推移一直发生的事件,例如订单、页面点击或库存变化,以及它们的相应度量。维度是可以描述这些事实的属性,例如客户、产品和地理位置。Marts可以被描述为数据平台内特定领域或部门导向的数据子集,例如财务、营销、物流、客户服务等。也可以采用一种良好的做法,设置一个名为"core"的marts,它不是针对特定领域的,而是核心业务事实和维度。
在介绍中,让我们现在构建我们的第一个模型,最初只涉及我们的staging层。在models文件夹内创建一个名为staging的新文件夹,以及在staging文件夹内创建jaffle_shop和stripe的各自文件夹。然后创建必要的SQL文件,一个用于stg_stripe_order_payments.sql(示例4-8),另一个用于stg_jaffle_shop_customers.sql(示例4-9),最后一个用于stg_jaffle_shop_orders.sql(示例4-10)。最后,删除models内的example文件夹。这是不必要的,因此在编码时会创建不需要的视觉噪音。文件夹结构应类似于示例4-11。
示例4-8. stg_stripe_order_payments.sql
vbnet
select
id as payment_id,
orderid as order_id,
paymentmethod as payment_method,
case
when paymentmethod in ('stripe'
, 'paypal'
, 'credit_card'
, 'gift_card')
then 'credit'
else 'cash'
end as payment_type,
status,
amount,
case
when status = 'success'
then true
else false
end as is_completed_payment,
created as created_date
from `dbt-tutorial.stripe.payment`
示例4-9. stg_jaffle_shop_customers.sql
csharp
select
id as customer_id,
first_name,
last_name
from `dbt-tutorial.jaffle_shop.customers`
示例4-10. stg_jaffle_shop_orders.sql
csharp
select
id as order_id,
user_id as customer_id,
order_date,
status,
_etl_loaded_at
from `dbt-tutorial.jaffle_shop.orders`
示例4-11. Staging models的文件夹结构
root/
├─ models/
│ ├─ staging/
│ │ ├─ jaffle_shop/
│ │ │ ├─ stg_jaffle_shop_customers.sql
│ │ │ ├─ stg_jaffle_shop_orders.sql
│ │ ├─ stripe/
│ │ │ ├─ stg_stripe_order_payments.sql
├─ dbt_project.yml
现在让我们执行并验证我们所做的。通常,在命令行中键入dbt run
就足够了,但在BigQuery上,您可能需要键入dbt run --fullrefresh
。然后,通过使用命令行左侧的箭头查看日志。日志应该类似于图4-32。
希望您已经收到了"已成功完成"的消息,现在让我们来看看BigQuery,在那里您应该看到所有三个模型已经具体化,如图4-33所示。
默认情况下,dbt会将您的模型在数据平台内具体化为视图。不过,您可以在模型文件顶部的配置块中轻松配置此项(示例4-12)。
vbnet
{{
config(
materialized='table'
)
}}
SELECT
id as customer_id,
first_name,
last_name
FROM `dbt-tutorial.jaffle_shop.customers`
现在,我们已经创建了我们的第一个模型,让我们继续下一步。使用YAML文件重新排列代码,并按照"YAML文件"(第168页)中推荐的最佳实践进行操作。让我们从那里提取代码块,然后在我们的YAML文件中配置我们的具体化(示例4-12)。我们要更改的第一个文件是dbt_project.yml。这应该是默认配置的核心YAML文件。因此,让我们使用示例4-13中呈现的代码更改其中的模型配置,然后再次执行dbt run。
示例4-13. 将模型具体化为视图和表
yaml
models:
dbt_analytics_engineer_book:
staging:
jaffle_shop:
+materialized: view
stripe:
+materialized: table
由于示例4-13强制所有的Stripe暂存模型都被具体化为表格,BigQuery应该类似于图4-34。
示例4-13显示了如何在dbt_project.yml中为每个文件夹配置特定的期望物化。您的暂存模型默认将保留为视图,因此可以在模型文件夹级别覆盖此配置,利用项目构建中的级联作用域优先级。首先,让我们更改dbt_project.yml,将所有暂存模型设置为物化为视图,如示例4-14所示。
yaml
models:
dbt_analytics_engineer_book:
staging:
+materialized: view
现在让我们为stg_jaffle_shop_customers创建单独的YAML文件,指定它需要作为表格物化。为此,请在staging/jaffle_shop目录内创建名为_jaffle_shop_models.yml的相应YAML文件,并复制示例4-15中的代码。
yaml
version: 2
models:
- name: stg_jaffle_shop_customers
config:
materialized: table
重新运行dbt后,查看BigQuery。结果应该类似于图4-35。
这是使用YAML文件的简单示例,演示表格物化的使用,并展示级联作用域优先级在实践中的含义。还有很多要做和看到的,随着我们的学习深入,我们讨论的一些内容将更加实用。现在,我们只是要求您将_jaffle_shop_models.yml中的模型更改为以视图方式物化。这将是您的默认配置。
希望在这个阶段,您已经开发了第一个模型,并大致了解了YAML文件和级联作用域优先级的整体目的。接下来的步骤将是创建我们的中间模型和marts模型,同时学习ref()函数。这将是我们首次使用Jinja,我们将在"使用Jinja进行动态SQL"中详细介绍。
首先要做的事情是明确我们的用例。在暂存区域内有了我们的模型后,我们需要知道我们想要做什么。正如我们在本节开始时提到的,您需要定义支持组织业务流程的数据需求。作为业务用户,我们的数据可以有多个流,其中之一,也是我们的用例,是分析每个客户的订单,显示每个成功订单的总付款金额以及每个成功订单类型(现金和信用)的总金额。
由于我们在这里有一些需要从付款类型级别更改为订单级别的转换,因此在达到marts层之前,有必要在我们达到marts层之前将这个复杂操作隔离出来。这就是中间层的用武之地。在您的models文件夹中,创建一个名为intermediate的新文件夹。在其中,创建一个名为int_payment_type_amount_per_order.sql的新SQL文件,并复制示例4-16中的代码。
sql
with order_payments as (
select * from {{ ref('stg_stripe_order_payments') }}
)
select
order_id,
sum(
case
when payment_type = 'cash' and status = 'success'
then amount
else 0
end
) as cash_amount,
sum(
case
when payment_type = 'credit' and status = 'success'
then amount
else 0
end
) as credit_amount,
sum(
case
when status = 'success'
then amount
end
) as total_amount
from order_payments
group by 1
在创建order_payments CTE时,可以看到我们使用了ref()函数从stg_stripe_order_payments中获取数据。此函数引用了构建数据平台的上游表和视图。由于它在dbt运行期间从环境配置中获取数据库对象的名称,因此我们将在实施分析代码时使用这个函数作为标准,这带来了一些好处,比如:
- 它允许您以灵活的方式在模型之间构建依赖关系,这些依赖关系可以在共同的代码库中共享,因为它在dbt运行期间编译数据库对象的名称,从您创建项目时的环境配置中获取。这意味着在您的环境中,代码将根据您的环境配置进行编译,在您的特定开发环境中可用,但与使用不同开发环境但共享相同代码库的团队成员的环境不同。
- 您可以构建血统图,以可视化特定模型的数据流和依赖关系。我们将在本章后面讨论这一点,并且在"文档"中也有相关内容。
最后,要注意,由于前面的代码可能看起来像是一种反模式,因为CASE WHEN条件重复,但重要的是要澄清整个数据集包括所有订单,而不考虑它们的支付状态。然而,对于此示例,我们选择仅对已达到"success"状态的订单关联的支付进行财务分析。
有了中间表,让我们转到最后一层。考虑到所描述的用例,我们需要从客户的角度分析订单。这意味着我们必须创建一个与我们的事实表相连接的客户维度。由于当前的用例可以满足多个部门,我们将不创建一个特定的部门文件夹,而是创建一个名为core的文件夹。因此,首先在models文件夹中创建marts/core目录。然后,将示例4-17复制到一个名为dim_customers.sql的新文件中,并将示例4-18复制到一个名为fct_orders.sql的新文件中。
sql
-- Example 4-17. dim_customers.sql
with customers as (
select * from {{ ref('stg_jaffle_shop_customers')}}
)
select
customers.customer_id,
customers.first_name,
customers.last_name
from customers
示例4-18。fct_orders.sql
vbnet
with orders as (
select * from {{ ref('stg_jaffle_shop_orders')}}
),
payment_type_orders as (
select * from {{ ref('int_payment_type_amount_per_order')}}
)
select
ord.order_id,
ord.customer_id,
ord.order_date,
pto.cash_amount,
pto.credit_amount,
pto.total_amount,
case
when status = 'completed'
then 1
else 0
end as is_order_completed
from orders as ord
left join payment_type_orders as pto ON ord.order_id = pto.order_id
所有文件创建完成后,让我们在dbt_project.yml中设置默认配置,如示例4-19所示,然后执行dbt run,或者在BigQuery上可能是dbt run --fullrefresh。
示例4-19. 在dbt_project.yml中每个层级的模型配置
yaml
models:
dbt_analytics_engineer_book:
staging:
+materialized: view
intermediate:
+materialized: view
marts:
+materialized: table
如果你收到类似于"Compilation Error in rpc request...depends on a node named int_payment_type_amount_per_order which was not found"(RPC请求中的编译错误...依赖于一个名为int_payment_type_amount_per_order的节点,但未找到该节点)的错误消息,这意味着你有一个模型依赖于你尝试预览的模型,但尚未存在于你的数据平台中,例如我们的情况下的int_payment_type_amount_per_order。要解决此问题,请转到特定的模型并执行dbt run --select MODEL_NAME
命令,将MODEL_NAME
替换为相应的模型名称。
如果一切顺利运行,你的数据平台应该已经完全更新了所有的dbt模型。只需查看BigQuery,它应该类似于图4-36。
最后,打开fct_orders.sql文件,查看信息窗口中的Lineage选项(图4-37)。这是我们将在"Documentation"(第200页)中介绍的一个很好的功能,它为我们提供了关于馈送特定模型的数据流及其上游和下游依赖关系的良好概念。
Sources
在dbt中,源(sources)是在数据平台中提供的原始数据,使用通用的提取和加载(EL)工具捕获。需要区分dbt源和传统数据源。传统数据源可以是内部或外部的。内部数据源提供支持组织日常业务运营的交易数据。客户、销售和产品数据是内部数据源可能包含的内容示例。另一方面,外部数据源提供在组织外部产生的数据,例如从业务合作伙伴、互联网和市场研究中收集的数据等。通常,这是与竞争对手、经济、客户人口统计等相关的数据。
dbt源根据业务需求依赖于内部和外部数据,但在定义上有所不同。正如前面提到的,dbt源是数据平台内的原始数据。这些原始数据通常由数据工程团队使用EL工具带入数据平台,并且将成为支持分析平台运行的基础。
在"模型"(第174页)中的我们的模型中,我们通过硬编码的字符串(例如dbt-tutorial.stripe.payment或dbt-tutorial.jaffle_shop.customers)引用了我们的源。即使这样能够工作,但请考虑如果原始数据发生变化,比如其位置或表名要遵循特定的命名约定,那么在多个文件中进行更改可能会很困难且耗时。这就是dbt源发挥作用的地方。它们允许您在一个YAML文件中记录这些源表,其中您可以引用源数据库、模式和表。
让我们将这个应用到实践中。按照"YAML文件"(第168页)中的推荐最佳实践,让我们在models/staging/jaffle_shop目录中创建一个名为_jaffle_shop_sources.yml的新YAML文件,并复制Example 4-20中的代码。然后在models/staging/stripe目录中创建另一个YAML文件,命名为_stripe_sources.yml,并复制Example 4-21中的代码。
Example 4-20. _jaffle_shop_sources.yml---所有位于Jaffle Shop模式下的表的源参数化文件
yaml
version: 2
sources:
- name: jaffle_shop
database: dbt-tutorial
schema: jaffle_shop
tables:
- name: customers
- name: orders
Example 4-21. _stripe_sources.yml---所有位于stripe模式下的表的源参数化文件
yaml
version: 2
sources:
- name: stripe
database: dbt-tutorial
schema: stripe
tables:
- name: payment
有了我们配置好的YAML文件,我们需要在我们的模型中进行最后一次更改。与其将我们的源硬编码,我们将使用一个名为source()的新函数。这个函数类似于我们在"引用数据模型"(第50页)中介绍的ref()函数,但是现在用于配置源的方式不再是{{ ref("stg_stripe_order_payments") }},而是传递类似{{ source("stripe", "payment") }}这样的内容,这在这种特定情况下将引用我们在Example 4-21中创建的YAML文件。
现在让我们动手操作。将之前创建的所有SQL分层模型代码拿出来,并用Example 4-22中相应的代码替换。 Example 4-22. 带有source()函数的支付、订单和客户分层模型
csharp
sqlCopy code
-- 在 stg_stripe_order_payments.sql 文件中替换
select
id as payment_id,
orderid as order_id,
paymentmethod as payment_method,
case
when paymentmethod in ('stripe'
,'paypal'
, 'credit_card'
, 'gift_card')
then 'credit'
else 'cash'
end as payment_type,
status,
amount,
case
when status = 'success'
then true
else false
end as is_completed_payment,
created as created_date
from {{ source('stripe', 'payment') }}
-- 在 stg_jaffle_shop_customers.sql 文件中替换
select
id as customer_id,
first_name,
last_name
from {{ source('jaffle_shop', 'customers') }}
-- 在 stg_jaffle_shop_orders.sql 文件中替换
select
id as order_id,
user_id as customer_id,
order_date,
status, _etl_loaded_at
from {{ source('jaffle_shop', 'orders') }}
当你用我们的source()函数切换你的模型后,你可以通过运行dbt compile命令或点击IDE中的Compile按钮来检查你的代码在数据平台中的执行情况。在后台,dbt将查找引用的YAML文件,并将source()函数替换为直接的表引用,如Figure 4-38所示。
使用source()函数的另一个好处是,现在你可以在谱系图中看到这些源。例如,只需查看fct_orders.sql的血统图。与Figure 4-37中显示的相同的谱系图现在应该类似于Figure 4-39。
数据源新鲜度
数据的新鲜度是数据质量的一个重要方面。如果数据不是最新的,那么它就是过时的,这可能会导致公司的决策过程中出现重大问题,因为它可能导致不准确的洞察。
dbt允许您通过源新鲜度测试来缓解这种情况。为此,我们需要有一个审计字段,记录在数据平台中特定数据工件的加载时间戳。有了这个字段,dbt将能够测试数据的新旧程度,并根据指定的条件触发警告或错误。
为了实现这一点,让我们回到我们的源YAML文件。在这个特定的示例中,我们将使用我们数据平台中的订单数据,因此,通过推理,我们将在_jaffle_shop_sources.yml中用示例4-23中的代码替换代码。
示例4-23. _jaffle_shop_sources.yml---Jaffle Shop模式下所有表的源参数化文件,带有源新鲜度测试
yaml
version: 2
sources:
- name: jaffle_shop
database: dbt-tutorial
schema: jaffle_shop
tables:
- name: customers
- name: orders
loaded_at_field: _etl_loaded_at
freshness:
warn_after: {count: 12, period: hour}
error_after: {count: 24, period: hour}
如您所见,我们在数据平台中使用了_etl_loaded_at字段。我们不必将其引入到我们的转换过程中,因为它对于后续模型没有附加值。这并不是问题,因为我们正在测试上游数据,而在我们的情况下,这是原始数据。在YAML文件中,我们创建了两个附加属性:loaded_at_field,表示在源新鲜度测试下要监视的字段,以及freshness,其中包含用于监视源新鲜度的实际规则。在freshness属性内部,我们配置了如果数据过时12小时,则通过warn_after属性引发警告,并且如果在过去的24小时内数据没有刷新,则通过error_after属性引发实际错误。
最后,让我们看看如何执行命令dbt source freshness
会发生什么。在我们的情况下,我们收到了一个警告,如图4-40所示。
如果您查看日志详细信息,您可以看到在您的数据平台上执行的查询并进行故障排除。这个特定的警告是预期的。_etl_loaded_at 被设计为从当前时间开始花费 16 小时,因此任何低于这个时间的值都会引发警告。如果您想继续尝试,将您的 warn_after 更改为更高的值,例如 17 小时。所有您的测试应该都会通过。
希望现在源数据新鲜度的概念已经清楚了。我们将在本书的后面回到这个话题,并向您展示如何自动化和快照源数据新鲜度测试。与此同时,理解其在整体测试领域中的目的、如何配置以及这个测试对缓解数据质量问题有多重要是至关重要的。
测试
作为一名分析工程师,您必须确保数据准确可靠,以建立对您提供的分析的信任,并为您的组织提供客观的洞察。尽管每个人都同意这一点,但即使您遵循所有工程领域的最新最佳实践,仍然会存在例外情况------尤其是当您需要处理与数据、其变化、类型、结构等相关的不稳定性时。
有许多捕捉这些异常的方法。然而,当您处理大量数据时,您需要考虑一种可扩展的方法来分析大型数据集并快速识别这些异常。这就是 dbt 发挥作用的地方。dbt 允许您快速轻松地在整个数据工作流中扩展测试,以便在其他人之前识别问题。在开发环境中,您可以使用测试确保您的分析代码产生期望的输出。在部署/生产环境中,您可以自动化测试并设置警报,以告诉您特定测试失败时,您可以迅速做出反应并在它产生更严重后果之前进行修复。
作为数据从业者,了解 dbt 中的测试可以概括为关于您数据的断言是很重要的。当您在数据模型之上运行测试时,您断言这些数据模型生成了预期的输出,这是确保数据质量和可靠性的关键步骤。这些测试是一种验证形式,类似于确认您的数据遵循特定模式并符合预定义标准。
然而,需要注意的是,dbt 测试只是数据测试更广泛领域中的一种测试类型。在软件测试中,测试通常区分为验证和验证两种类型。dbt 测试主要关注验证,通过确认数据遵循已建立的模式和结构来进行验证。它们不适用于测试数据转换中逻辑的更细节的细节,这类似于软件开发中单元测试所做的工作。
此外,dbt 测试在一定程度上可以帮助整合数据组件,特别是当多个组件一起运行时。然而,必须认识到 dbt 测试有其局限性,可能无法涵盖所有测试用例。在数据项目中进行全面测试时,您可能需要采用其他针对特定验证和验证需求定制的测试方法和工具。
考虑到这一点,让我们重点关注可以在 dbt 中使用哪些测试。在 dbt 中有两种主要分类的测试:单一测试和通用测试。让我们更多地了解这两种类型,它们的目的以及我们如何利用它们。
通用测试
在 dbt 中,最简单但高度可扩展的测试是通用测试。通过这些测试,通常您不需要编写任何新的逻辑,尽管自定义通用测试也是一种选择。然而,通常您只需编写几行 YAML 代码,然后根据测试情况测试特定的模型或列。dbt 提供了四种内置的通用测试:
-
唯一性测试 :验证特定列中的每个值是否唯一
-
not_null测试 :验证特定列中的每个值是否不为null
-
accepted_values测试 :确保特定列中的每个值存在于给定的预定义列表中
-
relationships测试 :确保特定列中的每个值存在于另一个模型中的某一列中,从而确保引用完整性
现在我们对通用测试有了一些背景,让我们尝试一下。我们可以选择任何想要的模型,但为了简化,让我们选择一个可以应用所有测试的模型。为此,我们选择了 stg_jaffle_shop_orders.sql 模型。在这里,我们将能够测试像 customer_id 和 order_id 这样的字段的唯一性和非空性。我们可以使用 accepted_values 检查所有订单状态是否在预定义的列表中。最后,我们将使用 relationships 测试来检查所有 customer_id 的值是否在 stg_jaffle_shop_customers.sql 模型中。让我们从在我们的 _jaffle_shop_models.yml 中替换代码开始,如示例 4-24 所示。
示例 4-24. _jaffle_shop_models.yml 中使用通用测试的参数化
yaml
version: 2
models:
- name: stg_jaffle_shop_customers
config:
materialized: view
columns:
- name: customer_id
tests:
- unique
- not_null
- name: stg_jaffle_shop_orders
config:
materialized: view
columns:
- name: order_id
tests:
- unique
- not_null
- name: status
tests:
- accepted_values:
values:
- completed
- shipped
- returned
- placed
- name: customer_id
tests:
- relationships:
to: ref('stg_jaffle_shop_customers')
field: customer_id
现在,在命令行中输入 dbt test
并查看日志。如果在 accepted_values 中测试失败,那么您做得没错。它应该失败的。让我们进行调试,了解失败的潜在根本原因。打开日志并展开失败的测试,然后单击"Details"。您将看到用于测试数据的查询,如图 4-41 所示。
让我们将这个查询复制到您的文本编辑器中,只保留内部查询,然后执行它。您应该会得到类似于图 4-42 中的输出。
而且,我们找到了问题所在。我们的测试列表中缺少额外的状态 return_pending。让我们添加它并重新运行我们的 dbt test
命令。现在,所有的测试应该都通过了,如图 4-43 所示。
单一测试(Singular Tests)
与通用测试不同,单一测试是在 tests 目录下的 .sql 文件中定义的。通常,当您想要测试特定模型内的某个属性,但是 dbt 内置的传统测试不符合您的需求时,这些测试是有帮助的。
查看我们的数据模型,一个好的测试是检查没有订单的总金额为负数。我们可以在三个层级之一(分期、中间或 marts)执行此测试。我们选择了中间层,因为我们进行了一些可能影响数据的转换。首先,在 tests 目录中创建一个名为 assert_total_payment_amount_is_positive.sql 的文件,并复制示例 4-25 中的代码。
示例 4-25. assert_total_payment_amount_is_positive.sql 单一测试,检查 int_payment_type_amount_per_order 模型内的 total_amount 属性是否只包含非负值
csharp
select
order_id,
sum(total_amount) as total_amount
from {{ ref('int_payment_type_amount_per_order') }}
group by 1
having total_amount < 0
现在,您可以执行以下命令之一来运行测试,测试应该通过:
bash
# 执行所有测试
dbt test
bash
#只执行单一测试
dbt test --select test_type:singular
bash
#执行 int_payment_type_amount_per_order 模型的所有测试
dbt test --select int_payment_type_amount_per_order
bash
#只执行我们创建的特定测试
dbt test --select assert_total_payment_amount_is_positive
这些命令提供了根据您的需求有选择地运行测试的能力。无论您是需要运行所有测试、特定类型的测试、特定模型的测试,甚至是单个特定测试,dbt 都允许您在命令中利用各种选择语法选项。这种多样性的选择确保您可以精确地定位要执行的测试,以及其他 dbt 资源。在第209页的"dbt 命令和选择语法"中,我们将提供可用的 dbt 命令的全面概述,并探讨如何有效地使用选择语法来指定资源。
测试数据源
为了在 dbt 项目中测试模型,您还可以将这些测试扩展到数据源。您已经在"Source freshness"(第187页)中使用了源新鲜度测试。尽管如此,您也可以为此目的增强通用和单一测试。在数据源中使用测试功能将使我们确信原始数据构建得符合我们的期望。
与您为模型配置测试的方式相同,您也可以为数据源进行配置。无论是在通用测试的 YAML 文件中,还是在单一测试的 .sql 文件中,规范都保持不变。让我们分别看一下每种类型测试的一个示例。
首先是通用测试,您需要编辑数据源的特定 YAML 文件。让我们保留与 customers 和 orders 分期表相同的唯一性、非空性和接受值测试,但现在您将测试它们的源。因此,为了实现这一点,请将 _jaffle_shop_sources.yml 中的代码替换为示例 4-26 中的代码。
示例 4-26. _jaffle_shop_sources.yml - 具有通用测试的参数化
yaml
version: 2
sources:
- name: jaffle_shop
database: dbt-tutorial
schema: jaffle_shop
tables:
- name: customers
columns:
- name: id
tests:
- unique
- not_null
- name: orders
loaded_at_field: _etl_loaded_at
freshness:
warn_after: {count: 17, period: hour}
error_after: {count: 24, period: hour}
columns:
- name: id
tests:
- unique
- not_null
- name: status
tests:
- accepted_values:
values:
- completed
- shipped
- returned
- placed
- return_pending
一旦您在 YAML 文件中有了新的代码,您可以运行 dbt test
或者更准确地执行只测试我们为其创建了这些测试的源的命令,dbt test --select source:jaffle_shop
。所有测试都应该通过。
最后,您也可以像之前一样实现单一测试。让我们复制之前在示例 4-25 中执行的单一测试。在您的 tests 目录中创建一个名为 assert_source_total_payment_amount_is_positive.sql 的新文件,并复制示例 4-27 中的代码。此测试检查支付源表内每个订单的金额属性之和是否只包含非负值。
示例 4-27. assert_source_total_payment_amount_is_positive.sql 单一测试
csharp
select
orderid as order_id,
sum(amount) as total_amount
from {{ source('stripe', 'payment') }}
group by 1
having total_amount < 0
执行 dbt test
或者 dbt test --select source:stripe
,因为在这种情况下我们查看了 Stripe 源。一切应该通过。
分析
analyses 文件夹可以存储您的临时查询、审计查询、培训查询或重构查询,例如在影响模型之前检查代码的外观。
分析文件是模板化的 SQL 文件,在 dbt 运行期间无法执行,但由于您可以在分析中使用 Jinja,因此您仍然可以使用 dbt compile
查看代码的外观,同时保留代码在版本控制下。考虑到其目的,让我们看看可以如何利用 analyses 文件夹的一个用例。
假设您不想构建一个全新的模型,但仍然希望通过利用代码版本控制保留一部分信息以供将来使用。使用 analyses,您可以做到这一点。对于我们的用例,让我们分析基于"completed"订单状态的总支付金额前 10 名最有价值的客户。要查看此信息,在 analyses 目录中创建一个名为 most_valuable_customers.sql 的新文件,并复制示例 4-28 中的代码。
示例 4-28. most_valuable_customers.sql 分析,输出基于"completed"订单的总金额的前 10 名最有价值的客户
vbnet
with fct_orders as (
select * from {{ ref('fct_orders')}}
),
dim_customers as (
select * from {{ ref('dim_customers' )}}
)
select
cust.customer_id,
cust.first_name,
SUM(total_amount) as global_paid_amount
from fct_orders as ord
left join dim_customers as cust ON ord.customer_id = cust.customer_id
where ord.is_order_completed = 1
group by cust.customer_id, first_name
order by 3 desc
limit 10
现在执行这段代码并检查结果。如果一切顺利,它将给出前 10 名最有价值的客户,如图 4-44 所示。
Seeds(种子数据)
Seeds 是 dbt 平台中的 CSV 文件,包含一小部分非易失性数据,用于在数据平台内作为表的材料化。通过在命令行中简单地输入 dbt seed
,Seeds 可以像其他模型一样以标准方式在模型中使用,使用 ref()
函数。
Seeds 可以应用于多种场景,例如映射国家代码(例如,PT 映射到葡萄牙或 US 映射到美国)、将邮政编码映射到州、要从分析中排除的虚拟电子邮件地址,甚至其他复杂的分析,如价格范围分类。重要的是要记住,Seeds 不应包含大量或频繁更改的数据。如果是这种情况,请重新考虑数据捕获的方法,例如使用 SFTP(SSH 文件传输协议)或 API。
为了更好地理解如何使用 Seeds,让我们跟随下一个用例。考虑到我们在"Analyses"(第197页)中所做的事情,我们不仅想要查看基于已支付的订单完成的前 10 位最有价值的客户,还想根据支付的 total_amount 将所有具有订单的客户分类为常规、青铜、白银或黄金。首先,让我们创建我们的 Seed。为此,在 seeds 文件夹中创建一个名为 customer_range_per_paid_amount.csv 的新文件,并复制示例 4-29 中的数据。
示例 4-29. seed_customer_range_per_paid_amount.csv,具有范围映射
css
csvCopy code
min_range,max_range,classification
0,9.999,Regular
10,29.999,Bronze
30,49.999,Silver
50,9999999,Gold
完成后,执行 dbt seed
。它将在数据平台中将您的 CSV 文件材料化为一个表。最后,在 analyses 目录中,让我们创建一个名为 customer_range_based_on_total_paid_amount.sql 的新文件,并复制示例 4-30 中的代码。
示例 4-30. customer_range_based_on_total_paid_amount.sql,根据已完成的订单和总支付金额,显示了客户分类范围
csharp
with fct_orders as (
select * from {{ ref('fct_orders')}}
),
dim_customers as (
select * from {{ ref('dim_customers' )}}
),
total_amount_per_customer_on_orders_complete as (
select
cust.customer_id,
cust.first_name,
SUM(total_amount) as global_paid_amount
from fct_orders as ord
left join dim_customers as cust ON ord.customer_id = cust.customer_id
where ord.is_order_completed = 1
group by cust.customer_id, first_name
),
customer_range_per_paid_amount as (
select * from {{ ref('seed_customer_range_per_paid_amount' )}}
)
select
tac.customer_id,
tac.first_name,
tac.global_paid_amount,
crp.classification
from total_amount_per_customer_on_orders_complete as tac
left join customer_range_per_paid_amount as crp on tac.global_paid_amount >= crp.min_range
and tac.global_paid_amount <= crp.max_range
现在执行我们的代码并查看结果。它将为每个客户提供已支付的总金额及其相应的范围(图 4-45)。
文档
文档在全球软件工程领域至关重要,然而它似乎是一个禁忌。一些团队会进行文档编写,而另一些则不会,或者文档编写不完整。文档编写可能变得太过繁琐或复杂,或者被视为开发者任务清单的附加负担,因此会被尽量避免。你可能会听到一长串理由,以证明不创建文档或将其推迟到较不紧张的时间是正当的。没有人说文档编写是不必要的。只是说"我们不会做","现在不做",或者"我们没时间"。
以下是创建和使用文档的几个理由:
- 有助于入职、交接和招聘流程。通过适当的文档,任何新团队成员都将确保他们不是"被扔给狼群"。新同事将拥有书面的入职流程和技术文档,从而减少他们在当前团队流程、概念、标准和技术发展方面的学习曲线。同样适用于员工流失和知识共享过渡。
- 它将赋予一个真理的单一来源。从业务定义、流程和操作文章,到让用户自助回答问题,拥有文档将为团队节省时间和精力,避免努力获取这些信息。
- 通过文档分享知识,可以减轻重复或冗余的工作。如果文档已经存在,可以在无需从头开始的情况下重复使用。
- 它促进了共享责任感,确保关键知识不局限于单个个体。在关键团队成员不可用时,这种共享所有权对于防止中断至关重要。
- 在建立质量、流程控制和满足合规法规方面是必不可少的。拥有文档将使您的团队能够在整个公司范围内实现凝聚力和一致性。
一个证明缺乏创建文档动力的原因是,文档编写是与实际开发流程平行的流。就像使用一种工具进行开发,另一种工具用于文档编写。对于 dbt 来说,情况是不同的。您可以在开发分析代码、测试以及连接到数据源等任务时,同时构建项目文档。一切都在 dbt 内部,而不是在一个单独的界面中。
dbt 处理文档的方式使您能够在构建代码的同时创建文档。通常,文档的很大一部分已经是动态生成的,比如我们之前介绍过的血统图,只需要您适当配置 ref()
和 source()
函数。另一部分是部分自动化的,需要您手动输入特定模型或列的含义。然而,再一次强调,所有这些都是在 dbt 中完成的,直接在 YAML 或 Markdown 文件中进行。
让我们开始创建我们的文档。我们想要实现的用例是文档化 fct_orders 和 dim_customers 模型及其相应列。我们将使用模型的 YAML 文件,并为更丰富的文档,我们将在 Markdown 文件中使用文档块。由于我们仍然需要为 marts 目录中的核心模型创建一个 YAML 文件,让我们使用名为 _core_models.yml 的文件来完成。
复制示例 4-31。然后,在相同的目录文件夹中创建一个名为 _code_docs.md 的 Markdown 文件,复制示例 4-32。 示例 4-31. _core_models.yml---带有描述参数的 YAML 文件
yaml
version: 2
models:
- name: fct_orders
description: Analytical orders data.
columns:
- name: order_id
description: Primary key of the orders.
- name: customer_id
description: Foreign key of customers_id at dim_customers.
- name: order_date
description: Date that order was placed by the customer.
- name: cash_amount
description: Total amount paid in cash by the customer with "success" payment status.
- name: credit_amount
description: Total amount paid in credit by the customer with "success" payment status.
- name: total_amount
description: Total amount paid by the customer with "success" payment status.
- name: is_order_completed
description: "{{ doc('is_order_completed_docblock') }}"
- name: dim_customers
description: Customer data. It allows you to analyze customers perspective linked facts.
columns:
- name: customer_id
description: Primary key of the customers.
- name: first_name
description: Customer first name.
- name: last_name
description: Customer last name.
然后,在相同的目录文件夹中创建一个名为 _code_docs.md 的 Markdown 文件,复制示例 4-32。
示例 4-32. _core_doc.md---带有文档块的 Markdown 文件
vbnet
markdownCopy code
{% docs is_order_completed_docblock %}
Binary data which states if the order is completed or not, considering the order
status. It can contain one of the following values:
| is_order_completed | definition |
|--------------------|-----------------------------------------------------------|
| 0 | An order that is not completed yet, based on its status |
| 1 | An order which was completed already, based on its status |
{% enddocs %}
在生成文档之前,让我们尝试理解我们做了什么。通过分析 YAML 文件 _core_models.yml,您可以看到我们添加了一个新属性:description。该基本属性允许您用手动输入补充文档。这些手动输入可以是文本,就像我们在大多数情况下所使用的那样,但也可以引用 Markdown 文件中的文档块,就像在 fct_orders 的列 is_order_completed 中所做的那样。我们首先在 Markdown 文件 _code_docs.md 中创建了文档块,并将其命名为 is_order_completed_docblock。这个名称是我们在描述字段中引用文档块时使用的名称:"{{ doc('is_order_completed_docblock') }}"。
让我们通过在命令行中键入 dbt docs generate
来生成我们的文档。在成功完成后,您可以浏览文档页面。进入文档页面很简单。在成功执行 dbt docs generate
后,在IDE中,在屏幕左上角,您可以点击文档站点旁边的Git分支信息右侧的书籍图标(图 4-46)。
一旦进入文档页面,您将看到概览页面,类似于图 4-47。目前,您有dbt提供的默认信息,但这个页面也是完全可定制的。
在概览页面上,您可以在左侧看到您的项目结构(图 4-48),其中包括测试、种子和模型等,您可以自由导航。
现在选择我们开发的其中一个模型,查看其相应的文档。我们选择了 fct_orders 模型。一旦点击其文件,屏幕将显示有关该模型的多个层次的信息,如图 4-49 所示。
在顶部,"Details" 部分提供有关表元数据的信息,如表类型(也称为物化类型)。使用的语言、行数和近似表大小是其他可用的详细信息。
接着,我们有模型的描述。正如您可能记得的那样,这是我们在 _core_models.yml 文件中为 fct_orders 表配置的描述。
最后,我们有与 fct_orders 相关的 "Columns" 信息。这份文档是部分自动生成的(例如,列类型),但也接受手动输入(例如,列描述)。我们已经通过填写描述属性提供了这些输入,并使用文档块为 is_order_completed 属性提供了全面的信息。要在文档页面上看到编写的文档块,点击 "is_order_completed" 字段,它应该会展开并呈现所需的信息(图 4-50)。
在 "Columns" 信息之后,我们有模型的下游和上游依赖关系,分别是 "Referenced By" 和 "Depends On" 部分。这些依赖关系也显示在图 4-51 中。
在 fct_orders 文档页面的底部是生成特定模型的代码。您可以以原始格式、带有 Jinja 的格式或已编译的代码形式查看源代码。图 4-52 显示了其原始形式。
最后,如果您查看文档页面的右下角,您会看到一个蓝色的按钮。点击此按钮可以访问相应模型的谱系图。我们选择了 fct_orders 的谱系图,您可以看到上游依赖关系,如源表或中间表,以及下游依赖关系,例如图 4-53 中显示的分析文件。谱系图非常强大,因为它提供了一个整体视图,展示了数据从您消耗它的瞬间到您进行转换和服务的整个过程。
dbt文档另一个值得一提的有趣方面是使用 persist_docs
配置可以将列和表级别的描述直接持久化到数据库中。这对您数据仓库的所有用户都很有价值,包括那些可能无法访问dbt Cloud的用户。它确保基本的元数据和描述对数据使用者而言是随时可用的,有助于更好地理解和利用您的数据资产。
dbt 命令和选择语法
我们已经介绍了一些 dbt 命令,如 dbt run
和 dbt test
,以及我们如何通过命令行界面与其进行交互。在本节中,我们将探讨基本的 dbt 命令和选择语法,这些命令允许您执行、管理和控制 dbt 项目的各个方面。无论是运行转换、执行测试还是生成文档,这些命令都是您进行有效项目管理的工具。
让我们从基础开始。在本质上,dbt 是一个设计用于简化数据转换工作流的命令行工具。它提供了一组命令,使您能够高效地与 dbt 项目进行交互。让我们更详细地探讨每个命令。
dbt run
dbt run
命令是执行在 dbt 模型中定义的数据转换的首选工具。它与项目的配置文件(如 dbt_project.yml
)一起工作,了解应该运行哪些模型以及以什么顺序运行它们。该命令将根据模型的依赖关系确定必须执行的模型,并以适当的顺序运行它们。
dbt test
确保数据的质量和可靠性是至关重要的。dbt test
命令允许您定义并执行对数据模型的测试,以验证它们是否符合您的业务规则和期望。
dbt docs
充分的文档对于协作式数据项目至关重要。dbt docs
自动化了您的 dbt 项目的文档生成,包括模型描述、列描述和模型之间的关系。要生成文档,您需要执行 dbt docs generate
。
dbt build
在运行 dbt 项目之前,通常需要进行编译。dbt build
命令执行此任务,创建执行所需的工件。这一步对于优化执行过程并确保一切就绪至关重要。一旦项目成功编译,您就可以更加自信地进行其他命令,如使用 dbt run
。
其他命令 尽管前述命令可能是最常用的,但您还应该了解其他 dbt 命令,例如:
dbt seed
: 将原始数据或参考数据加载到项目中dbt clean
: 删除由dbt build
生成的工件dbt snapshot
: 对数据进行快照以进行版本控制dbt archive
: 将表或模型归档到冷存储dbt deps
: 安装在packages.yml
中定义的项目依赖项dbt run-operation
: 运行在项目中定义的自定义操作dbt source snapshot-freshness
: 检查源数据的新鲜度dbt ls
: 列出在 dbt 项目中定义的资源dbt retry
: 从故障点重新运行上次运行的 dbt 命令dbt debug
: 以调试模式运行 dbt,提供详细的调试信息dbt parse
: 解析 dbt 模型而不运行它们,这对于语法检查很有帮助dbt clone
: 从指定的状态克隆选定的模型dbt init
在当前目录中创建一个新的 dbt 项目
选择语法 随着您的 dbt 项目的发展,您将需要针对特定的模型、测试或其他资源进行定位,以便在执行、测试或生成文档时,而不是每次都运行它们全部。这就是选择语法发挥作用的地方。
选择语法允许您精确指定在运行 dbt 命令时包含或排除哪些资源。选择语法包括各种元素和技术,例如以下内容。
通配符 。星号 ( ) 表示任何字符或字符序列。让我们看一下 Example 4-33。 Example 4-33. 使用 * 通配符的选择语法
arduino
dbt run --select models/marts/core/*
在这里,我们使用 * 通配符与 --select 标志一起,以定位核心目录中的所有资源或模型。此命令将执行该目录中的所有模型、测试或其他资源。
标签。标签是您可以分配给 dbt 项目中的模型、宏或其他资源的标签,特别是在 YAML 文件中。您可以使用选择语法来定位具有特定标签的资源。例如,Example 4-34 显示了如何基于 marketing 标签选择资源。 Example 4-34. 使用标签的选择语法
arduino
dbt run --select tag:marketing
模型名称。您可以通过在选择语法中使用其名称来精确选择单个模型,如 Example 4-35 所示。 Example 4-35. 使用模型的选择语法
arduino
dbt run --select fct_orders
依赖关系。使用 + 和 - 符号选择依赖于或被其他模型依赖的模型。例如,fct_orders+ 选择依赖于 fct_orders 的模型,而 +fct_orders 选择 fct_orders 依赖的模型(Example 4-36)。 Example 4-36. 使用依赖关系的选择语法。
总结
这一章节展示了分析工程是一个不断发展的领域,始终受到创新的影响。dbt不仅仅是这个故事的一个方面;它是该领域中的一个关键工具。
分析工程的主要目标是将原始数据转化为有价值的洞察,而这个工具在简化数据转换的复杂性并促进广泛范围的利益相关者之间的合作方面发挥着关键作用。dbt确保数据转换不仅是技术上的变革,而且还非常强调开放性、包容性和知识共享。
dbt以其轻松与大型数据仓库集成的能力而闻名。它通过确保最佳的可追溯性和准确性,推动了对数据转换的协作方法。此外,它强调了对数据流程进行彻底测试以确保可靠性的重要性。
其用户友好的界面强化了分析工程是一个包容性领域的观念,欢迎所有能力水平的个人做出贡献。
总之,我们强烈鼓励希望保持行业前沿的分析工程师深入研究这个变革性工具。由于dbt变得越来越重要和毫无疑问地有益,精通这个工具不仅可以提升您的技能水平,还可以促进未来更顺畅、更协作的数据转换。