在开发数据科学应用程序的过程中,我经常遇到有关数据的挑战。这些挑战大多数与数据质量,数据可用性和文档编制有关。在本文中,我想向您展示如何使用Fishtown Analytics开发的出色的开源工具Data Build Tool(DBT)来克服其中的一些挑战。在本文中,我将讨论以下内容:
我们的发展过程及其挑战为什么模拟数据很难DBT的附加价值是什么?DBT项目中的关键组件DBT的测试能力血统和文档使用DBT时遇到的一些限制开发过程
首先,我将简要介绍我工作的公司Albert Heijn的数据科学产品的开发过程。当前的开发过程以构建Python软件包为中心,该软件包包含运行数据科学项目所需的一切。
我们有一个自动化的CI / CD流程来测试和构建应用程序。对结果包进行版本控制,并将其推送到Azure Artifacts,以便可以将其用于部署。对于批处理作业,部署会将库运送到Databricks,并通过指定从属库和入口点脚本来配置Databricks作业群集。启动作业后,该库会自动安装在集群上,并且会触发入口点脚本。
此开发过程非常简单,并且效果很好。由于笔记本电脑无法与成熟的IDE相提并论,因此在Databricks之外进行开发和测试。这确实引入了数据在您的开发计算机上不可用的问题。将库的所有更改都交付给Databricks并不是一种选择,因为它很耗时,并且会导致开发过程缓慢。
有一些试图弥合这种差距的集成工具,例如Databricks Connect,但是,这限制了pytest-spark的使用。在不深入研究细节的情况下,大多数集成工具都是以成本为代价的,因此我们寻求另一种方法。由于大多数开发都是在本地或专用计算机上完成的,因此在开发过程中无法直接获得数据。一种替代方法是模拟数据,以便您可以在本地进行开发和测试。此方法最初用于该项目,但有其自身的缺点。
为什么模拟数据很难
随着我们在一个项目中的进一步发展,人们对工具的需求越来越强烈,该工具可以帮助弥合模拟数据与实际数据之间的差距。对于此特定项目,我们严重依赖于Databricks&Spark。通过创建本地spark会话并使用pytest-spark完成测试。
作为测试的输入,我们使用模拟数据。我们也可以从实际数据中提取样本。但是,将这些数据样本存储在代码库中会引发其他问题,例如更大的存储库大小,员工机器上的公司数据以及样本数据存在巨大偏差的风险。
首先,我们为大多数输入源创建模拟数据。上游依赖项的数量还不是很大。模拟我们使用的输入源是可行的,并且我们可以以惊人的速度运行测试。感觉很好,逻辑检查出来了,我们可以开始了。
一个简单的数据转换过程的示例。橙色条表示应该模拟数据的位置。
向上扩展
随着项目规模的扩大以及我们的数据科学家开始增加更多的数据依赖性,创建和维护模拟数据的复杂性迅速增加。在某些时候,维护模拟数据和测试变得困难。Pytest是一个非常灵活的库,使用conftest确实为我们节省了大量工作。但是,在某些时候这还不够。
下游越来越多的数据源相互交互,上游的微小变化可能导致下游的结果截然不同。由于必须考虑许多不同的极端情况,因此更新模拟数据变得很繁琐。
在这一点上,我们甚至还没有讨论文档。每次更新模拟数据时,都必须重新评估测试并更新文档。文档与代码是分开完成的,因此它总是落后于代码。
一个日益复杂的例子。橙色条表示应该模拟数据的位置。
在混合中添加一些DBT
这就是数据构建工具(DBT)出现的地方。DBT的重点是古玩交易数据转换。DBT通过添加模型引用,沿袭,文档和广泛的测试来帮助您改善数据转换过程。
DBT与ELT中的T有关,它是用Python编写的。DBT以两种方式提供,即:免费的开源CLI版本和托管云版本。后者需要订阅。云版本在DBT之上添加了一个额外的接口层,并为您托管了DBT。
DBT不是调度程序,它不会为您执行数据提取或加载。专门用于简化数据转换过程并帮助您一路构建数据沿袭和文档。
DBT如何工作?
DBT允许您通过在混合使用一些Jinja和YAML的情况下编写SQL SELECT语句来建模和编写配置,从而对数据转换进行建模。从模型中推断出关系,然后在YAML中提供其他模型属性,例如测试和描述。一个有向无环图(DAG)从您的DBT项目,该项目在文档中可视化,为您提供有关数据沿袭信息构成。此外,该DAG还提供了并行运行独立数据模型的可能性。
DBT为您处理繁重的工作。当您运行DBT项目时,根据设置,您的模型将以不同的形式实现。您最关心的是编写在表中产生的语句。DBT可以完成创建表,编写插入内容,创建高插入内容或创建快照的全部操作。
首先,由于我是PySpark API的长期用户,因此在PySpark上使用Spark SQL感觉像是退了一步。但是,只要不需要结构化流,就没有限制。我特别喜欢dbt-spark库,该库增加了对Delta Lake的merge语句的支持。此外,组织中可以读取SQL的人员可能比Python多。这使得与利益相关者坐下来讨论现有逻辑变得更加容易。
DBT项目的关键组件
让我们看一下DBT项目的一些关键组件。为此,我们将看看DBT在初始化项目时提供的默认项目框架。由于DBT提供了包含视频说明的分步教程,因此我们不会深入介绍如何创建项目。
我们将看一下以下组件:
profiles.ymldbt_project.yml模型目录模型(SQL)文件schema.ymlref 函数宏profiles.yml
默认情况下,该profile.yml 文件不存储在项目文件夹中。这样做是为了避免将凭据意外提交到您的代码库。除非您进行了周围的更改profile.yml ,~/.dbt/否则您可以找到自己的下属。该文件包含连接到数据存储所需的信息。
dbt_project.yml
该文件描述了DBT项目。第一部分与项目命名,版本控制有关,您可以指定要使用的配置版本。第二部分指定用于运行DBT的配置文件。在第三部分中,您会注意到描述了此目录中的不同文件夹。本节告诉DBT在哪里可以找到特定的文件文件,例如模型,测试或宏。最后,最后一部分与配置模型有关。这些是默认配置,例如实现类型和标签,并已传递到您的DBT模型。
缺省的dbt_project.yml文件。
模型目录
models目录是所有DBT模型的存放位置。DBT模型只是定义为SQL文件。如果您想使事情更有条理,可以在此目录中创建子文件夹。重要的是,确保此文件夹结构与的最后一部分中的结构保持一致dbt_project.yml。
my_first_dbt_model.sql
如果我们仔细看一下DBT提供的玩具示例,我们会注意到DBT模型非常简单。该my_first_dbt_model.sql文件显示一个配置部分,然后显示一个SELECT语句。从config对象可以看到,使用此模型运行DBT将产生一个表。在此文件中,很明显,我们只关心编写SELECT语句,DBT将负责创建表和插入数据。
一个玩具示例DBT模型。
schema.yml文件
让我们仔细看一下schema.yml文件。如您所见,该文件定义了有关两个模型的其他属性:my_first_dbt_model和my_second_dbt_model。这两个条目都提供其他信息,例如模型描述,列描述和测试。
很高兴知道您可以保留一个schema.yml文件,也可以制作多个文件。另外,该文件可以命名为任意名称。一旦您的项目变得更加复杂,您可能希望在模型目录中创建子文件夹,每个子文件夹都有自己的schema.yml文件。
描述我们的DBT模型的其他信息。
‘ref’ 函数
ref函数构成DBT的基础。此功能使您可以引用项目中的其他模型。结果,像我们上面讨论的那样,DBT可以插值模式并推断模型之间的关系。下图演示了引用如何在DBT中工作。您可以根据参考查看DAG更新。
强大的参考功能可更新模型之间的关系。图片由DBT提供。
宏
DBT允许您使用Jinja编写自定义宏,并将其存储在macros文件夹中。结果,您最终将获得DBT项目的可重用组件。
在Albert Heijn,使用整数表示的日期通常在不同的数据源中使用。在SQL中,您将需要使用date_format日期对象来获取此信息。对我们来说幸运的是,我们可以编写一个宏,使我们可以轻松地重用此组件。
在下面的代码中,您可以看到将简短的SQL语句包装在宏中有多么容易。即使此示例非常简单,Jinja仍允许您添加更复杂的宏。
macros/date_macro.sql{%macro current_datekey()%}
date_format(current_date,‘yyyyMMdd’)
{%endmacro%}
在我们的模型中,我们现在可以使用如下所示的功能。
models/sales.sql
SELECT
DateKey,
Store,
Article,
Sales
FROM
{{ ref(‘source_sales’) }}
WHERE
DateKey={{ current_datekey() }}使用DBT进行测试
DBT提供了一种编写和运行测试的好方法。可以通过dbt testCLI运行在dbt中运行测试。(可选)您可以指定仅运行数据测试或架构测试。
DBT提供两种测试:
模式测试(更常见):在YAML中应用,返回未通过断言的记录数-当该数字为0时,所有记录都通过,因此,您的测试通过了数据测试:返回0条记录的特定查询
开箱即用,有一些可用的架构测试,例如:
not_null:检查该列是否包含任何空值。unique:检查列中的值是否唯一。acceptd_values:对照接受值列表检查列内容。Relationships:检查一列中的值是否存在于另一个表中。
对我们来说幸运的是,Fishtown Analytics在其dbt-utils程序包中打包了许多有用的模式测试,这些测试可以轻松添加到您的项目中。这为您的项目添加了许多有用的模式测试。
数据测试通常用于检查特定的业务逻辑。这些测试存储在testsDBT项目的文件夹中。如果数据测试查询返回零记录,则测试通过。
血统和文档
DBT可以直接从项目中生成依赖关系图,它允许您并行运行数据转换。这由您在项目中使用的Ref函数提供支持。
最重要的是,您可以运行以下命令来生成文档:
#生成文档
DBT文档生成#在localhost
dbt docs上服务docs
这将生成一个网页,该网页将您在YAML定义中编写的信息,模型与测试之间的关系合并到单个文档集中。我特别喜欢的一件事是,您将文档与实际的代码一起存储,这使与项目中涉及的其他人坐下来讨论正在发生的事情变得容易。
DBT生成的文档的示例。
要了解文档的外观,可以访问此链接。DBT托管了一个玩具示例的文档,供您查看。
局限性
将DBT添加到堆栈中并不能解决所有问题。这是我在使用DBT时遇到的两个限制。
记录和报告测试
您可以使用DBT定义和运行的测试提供了一种方便的方式来对数据进行质量检查。但是,在撰写本文时,存储和监视这些测试结果并不容易。我认为,这还需要填补一个空白。当前,我们依赖于一个定制解决方案,该解决方案将感兴趣的指标记录到我们的日志记录框架中。理想情况下,我们将存储DBT测试结果并随时间监视数据质量。
打开了一个功能请求以支持测试信息的记录。这是我期待的功能。
整理Jinja SQL代码。
对Linting Jinja SQL代码的支持仍在开发中。SQL Fluff的人们正在做一些工作,但是这仍处于开发的早期阶段。SQL Fluff尚未与dbt-utils等其他依赖项很好地集成。
综上所述
通常,DBT是严重依赖数据转换的项目的重要补充。它轻巧且易于使用。如果您正在寻找一种有助于简化数据转换过程的工具,请查看DBT。此外,DBT允许您在开发过程中添加更多结构。分离的环境,广泛的测试和文档编制都是DBT的一部分。
我期待着允许开箱即用地监视数据质量的新功能。这个空白尚未填补,我认为这将是DBT已经提供的功能的一个很好的补充。