Azure-数据工程权威指南-三-

88 阅读1小时+

Azure 数据工程权威指南(三)

原文:The Definitive Guide to Azure Data Engineering

协议:CC BY-NC-SA 4.0

十三、增量插入数据

如果你还记得从第 4 到第六章,我演示了如何做到以下几点:

  • 从 SQL 数据库完全加载 Azure 数据湖存储二代。

  • 使用 Azure Data Factory 的复制活动,使用数据湖存储二代 parquet 文件完全加载 Azure Synapse Analytics DW。

这个 ELT 过程由元数据方法驱动,使用 SQL 表中填充的管道参数。虽然这是一种有用的 ELT 方法,但本章将重点推进这一过程,以解决以下问题:

  • 从 SQL 源增量加载 Azure 数据湖存储。

  • 将增量记录更新并插入 Azure Synapse Analytics 数据仓库目标。

在这一章中,我将演示 Azure Data Factory 的映射数据流的内置 upsert 功能,以更新 Azure Data Lake Storage gen 2 parquet 文件中的数据并将其插入 Azure Synapse Analytics DW。值得注意的是,映射数据流目前不支持本地数据源和接收器。因此,本练习将利用 Azure SQL 数据库作为创建数据集的源。此外,我将演示如何使用一种定制方法,根据 Azure SQL 数据库中的创建日期,用 parquet 文件增量填充 Data Lake Storage Gen2。本章假设您熟悉本书前面的章节,这些章节讨论了使用 Azure Data Factory 的元数据驱动的 ETL 方法。

创建参数表

让我们从在 Azure SQL 数据库中创建一个pipeline_parameter表开始这个过程。您已经在前面的章节中创建了它,您只需要添加下面列出的附加列。正如我们在前面章节中回忆的那样,此表将包含用于控制 ADF 管道的参数值:

  • upsert_key_column :这是映射 upsert 流程的数据流必须使用的键列。它通常是一个 ID 列。

  • incremental _ watermark _ value:必须用源 SQL 表的值填充,以驱动增量过程。这通常是主键 ID 或创建/最后更新日期列。它可以通过存储过程进行更新。

  • incremental _ watermark _ column:这只是填充在incremental_watermark_value列中的值的列名。这通常是主键 ID 或创建/最后更新日期列。它可以通过存储过程进行更新。

  • process_type :必须设置为 incremental,ADF 才能知道这个表中哪些记录是增量的。

以下是复制更新后的pipeline_parameter表的 SQL 代码:

SET ansi_nulls ON

go

SET quoted_identifier ON

go

CREATE TABLE [dbo].[pipeline_parameter]
  (
     [parameter_id]                       [INT] IDENTITY(1, 1) NOT NULL,
     [server_name]                        NVARCHAR NULL,
     [src_type]                           NVARCHAR NULL,
     [src_schema]                         NVARCHAR NULL,
     [src_db]                             NVARCHAR NULL,
     [src_name]                           NVARCHAR NULL,
     [dst_type]                           NVARCHAR NULL,
     [dst_name]                           NVARCHAR NULL,
     [include_pipeline_flag]              NVARCHAR NULL,
     [partition_field]                    NVARCHAR NULL,
     [process_type]                       NVARCHAR NULL,
     [priority_lane]                      NVARCHAR NULL,
     [pipeline_date]                      NVARCHAR NULL,
     [pipeline_status]                    NVARCHAR NULL,
     [load_synapse]                       NVARCHAR NULL,
     [load_frequency]                     NVARCHAR NULL,
     [dst_folder]                         NVARCHAR NULL,
     [file_type]                          NVARCHAR NULL,
     [lake_dst_folder]                    NVARCHAR NULL,
     [spark_flag]                         NVARCHAR NULL,
     [dst_schema]                         NVARCHAR NULL,
     [distribution_type]                  NVARCHAR NULL,
     [load_sqldw_etl_pipeline_date]       [DATETIME] NULL,
     [load_sqldw_etl_pipeline_status]     NVARCHAR NULL,
     [load_sqldw_curated_pipeline_date]   [DATETIME] NULL,
     [load_sqldw_curated_pipeline_status] NVARCHAR NULL,
     [load_delta_pipeline_date]           [DATETIME] NULL,
     [load_delta_pipeline_status]         NVARCHAR NULL,
     [upsert_key_column]                  NVARCHAR NULL,
     [incremental_watermark_column]       NVARCHAR NULL,
     [incremental_watermark_value]        [DATETIME] NULL,
     PRIMARY KEY CLUSTERED ( [parameter_id] ASC )WITH (statistics_norecompute =
     OFF, ignore_dup_key = OFF) ON [PRIMARY]
  )
ON [PRIMARY]

go 

为 ADF 管道创建源查询

现在您已经创建了pipeline_parameter,编写一个定制的 SQL 查询,它将被用作 ADF 管道的源。注意添加了SQLCommandWhereValue,它们可以用于根据流程类型是完整的还是增量的来动态创建定制的 SQL 语句和 where 子句。出于本练习的目的,仅对增量值应用过滤器,但是该查询展示了将全部负载合并到同一源查询中的灵活性。我们的疑问是:

SELECT src_schema,
       src_db,
       src_name,
       dst_schema,
       dst_type,
       dst_name,
       dst_folder,
       process_type,
       file_type,
       load_synapse,
       distribution_type,
       upsert_key_column,
       incremental_watermark_column,
       CASE
         WHEN process_type = 'FULL' THEN 'select * from ' + src_schema + '.' +
                                         src_name
                                         + ' where  1 = '
         WHEN process_type = 'Incremental' THEN
         'select * from ' + src_schema + '.' + src_name
         + ' where  ' + incremental_watermark_column
         + ' > '
       END                               AS SQLCommand,
       CASE
         WHEN process_type = 'FULL' THEN '1'
         WHEN process_type = 'incremental' THEN Cast(
         Isnull(incremental_watermark_value, 'yyyy-MM-dd') AS VARCHAR(50))
       END                               AS WhereValue,
       dst_folder + '/' + dst_name + '/' + file_type + '/'
       + Format(Getdate(), 'yyyy-MM-dd') AS FolderName,
       dst_name + '.' + file_type        AS FileName
FROM   dbo.pipeline_parameter
WHERE  load_synapse = 1
       AND process_type = 'incremental'

请注意,在本练习中,源查询将嵌入到 ADF 管道中。作为最佳实践,考虑将查询转换为存储过程,以便更容易地维护 ADF 管道之外的集中式 SQL 数据库中的 SQL 代码。

图 13-1 显示了在 SQL Server Management Studio (SSMS)中,在用一个您想要通过 ADF 管道运行的增量记录填充pipeline_parameter之后,执行查询的结果。请注意,SQLCommand列构建了将由 ADF 管道使用的增量源查询。

img/511918_1_En_13_Fig1_HTML.jpg

图 13-1

将用作 ADF 管道源的自定义 SQL 查询

以下是包含在图 13-1 中的SQLCommand列中的 SQL 查询。这个SQLCommand在与WhereValue结合时动态形成源 SQL 查询,该查询可以作为 ADF 管道中的参数进行集成和调用。创建此流程的目的是展示动态构建源 SQL 查询,然后将它们集成到 ADF 管道中的强大功能:

select * from db.Log where CreatedDt >

添加 ADF 数据集

接下来,转到 ADF 并创建以下小节中描述的数据集。您需要创建三个数据集。您需要 Azure SQL 数据库中的源数据集、用于映射数据流的 Azure Data Lake Storage Gen2 数据集,以及最终作为目标的 Azure Synapse Analytics 数据集。

蓝色数据库

将需要 Azure SQL 数据库作为 ADF 管道中数据集的源。出于本练习的目的,您将需要使用驻留在这个 Azure SQL 数据库上的日志表。图 13-2 很好地展示了这个源连接在创建后在数据集视图中的样子。

img/511918_1_En_13_Fig2_HTML.jpg

图 13-2

ADF Azure SQL DB 源数据集

Azure 数据湖存储第二代

此外,还需要 Azure Data Lake Storage Gen2 数据集在映射数据流中使用,以创建拼花文件。这个 ADLS Gen2 帐户将作为来自 SQL 数据库的拼花文件的登录区。图 13-3 展示了一旦成功创建,该连接和文件路径设置将如何显示。注意参数化的文件夹名称,它来自源查询中的FolderName列。

img/511918_1_En_13_Fig3_HTML.jpg

图 13-3

Azure 数据湖存储第二代数据集

还将以下参数添加到拼花配置部分,如图 13-4 所示。FolderNameFileName都来自前面几节中列出的源 SQL 查询。

img/511918_1_En_13_Fig4_HTML.jpg

图 13-4

拼花地板配置参数

Azure Synapse 分析数据仓库

最后,您将需要一个 Azure Synapse Analytics DW 目标数据集来存储从源系统中识别的初始和增量数据。将使用 ADF 中的映射数据流来构建这个转换步骤。图 13-5 显示了成功连接到 Synapse 分析数据集的情况。注意,表名有一个动态定义,模式将被一致地定义为“etl”。

img/511918_1_En_13_Fig5_HTML.jpg

图 13-5

Azure Synapse 分析数据仓库目标数据集

创建 ADF 管道

现在,您已经创建了所需的数据集,是时候开始配置 ADF 管道活动了,方法是添加一个查找活动来获取表列表,添加一个 ForEach 循环活动来复制每个表,添加一个映射数据流活动来将数据从 ADLS Gen2 增量复制到 Synapse Analytics DW。该管道将展示使用 ADF 的映射数据流将数据从源向上插入到接收器的端到端能力。

添加一个查找活动来获取表的列表

首先,向 ADF 管道画布添加一个查找活动,以获取 ADF 管道所需的表。图 13-6 显示了您需要添加在前面步骤中创建的查询的位置。

img/511918_1_En_13_Fig6_HTML.jpg

图 13-6

ADF 源数据集设置

添加一个 ForEach 活动来迭代和复制每个表

当连接到查找活动时,ForEach 循环活动将遍历每个表,并将该表从 ADLS Gen2 复制到 Synapse Analytics DW。图 13-7 显示了如何在 ADF 管道中配置 ForEach 循环活动设置。

img/511918_1_En_13_Fig7_HTML.jpg

图 13-7

ADF ForEach 循环设置

将 SQL 的数据流映射到 Lake 增量 ADF 管道

现在,您可以开始为从源 Azure SQL 数据库到接收器数据湖存储二代 parquet 文件夹和文件的增量负载构建映射数据流。FolderNameFileName是在源 ADLS Gen2 拼花数据集内创建的,并在制图数据流中用作源,如图 13-8 所示。

img/511918_1_En_13_Fig8_HTML.jpg

图 13-8

ADF SQL 到湖数据流设置

参数为SQLCommandWhereValueFileName,如图 13-9 所示。这些参数将用于生成源增量查询字符串。

img/511918_1_En_13_Fig9_HTML.jpg

图 13-9

ADF SQL 到湖数据流参数

映射数据流的源设置如图 13-10 所示:

img/511918_1_En_13_Fig10_HTML.jpg

图 13-10

ADF SQL 到湖数据流源连接设置

  • 允许模式漂移:如果源列经常改变,则选择允许模式漂移。此设置将允许来自源的所有传入字段通过转换流向接收器。

  • 推断漂移列类型:允许自动检测漂移列类型。

  • 验证模式:如果 Projection 选项卡中定义的任何列和类型与传入数据不匹配,设置该选项将导致数据流失败。

  • 采样:如果投影选项卡中定义的任何列和类型与输入数据不匹配,设置此选项将导致数据流失败。

数据流的源选项配置如图 13-11 所示,使用映射数据流 ( https://docs.microsoft.com/en-us/azure/data-factory/concepts-data-flow-expression-builder )内的字符串插值表达式特性。注意,SQLCommandWhereValue字段被连接起来形成一个动态 SQL 查询。

img/511918_1_En_13_Fig11_HTML.jpg

图 13-11

ADF SQL 到湖数据流源选项

接下来,配置映射数据流的目的 sink,如图 13-12 所示。

img/511918_1_En_13_Fig12_HTML.jpg

图 13-12

ADF 数据流目标接收器连接属性

图 13-13 中显示的设置将指示从本章前面章节中列出的 SQL 查询生成的FileName,的单个文件输出。

img/511918_1_En_13_Fig13_HTML.jpg

图 13-13

ADF 数据流目标设置

在优化选项卡中使用单一分区,如图 13-14 所示。

img/511918_1_En_13_Fig14_HTML.jpg

图 13-14

ADF 数据流目标分区优化属性

单一分区将所有分布式数据合并到一个分区中。这是一个非常慢的操作,还会显著影响所有下游转换和写入。Azure Data Factory 强烈建议不要使用此选项,除非有明确的业务原因。

通过选择 Set Partitioning 选项,您将看到以下分区选项。

一系列

循环调度在分区之间平均分配数据。当您没有合适的关键字候选来实现可靠的分区策略时,您可以使用循环法,因为循环法将数据平均分布在各个分区上,并允许您设置物理分区的数量。

混杂

ADF 创建列的散列来产生统一的分区,以便具有相似值的行落在同一个分区中。当您使用 Hash 选项时,测试可能的分区倾斜是很重要的。此外,您可以设置物理分区的数量。

动态量程

动态范围基于您提供的列或表达式使用 Spark 动态范围。您可以设置物理分区的数量。

固定范围

构建一个表达式,为分区数据列中的值提供固定的范围。为了避免分区倾斜,在使用这个选项之前,您应该对您的数据有一个很好的了解。您为表达式输入的值用作分区函数的一部分。您可以设置物理分区的数量。

钥匙

如果您对数据的基数有很好的理解,那么键分区可能是一个不错的策略。键分区为列中的每个唯一值创建分区。您不能设置分区数量,因为该数量基于数据中的唯一值。

默认情况下,选择“使用当前分区”,指示 Azure Data Factory 保持转换的当前输出分区。由于对数据进行重新分区需要时间,因此在大多数情况下,建议使用当前分区。

通过单击映射数据流画布的空白区域,将出现映射数据流参数选项卡。增加如图 13-15 所示的以下参数。

img/511918_1_En_13_Fig15_HTML.jpg

图 13-15

ADF 映射数据流参数

将数据流映射到从 Lake 到 Synapse Analytics 数据仓库的增量插入

既然您已经创建并配置了 SQL 到 lake 的增量映射数据流管道,那么是时候创建并配置 lake 到 Synapse 的增量上插管道了,如图 13-16 所示。

img/511918_1_En_13_Fig16_HTML.jpg

图 13-16

ADF 数据流湖到 Synapse 增量向上插入管道设置

务必为FolderNameupsert_key_column配置以下数据流参数,如图 13-17 所示。这些参数将用于增量数据摄取过程。

img/511918_1_En_13_Fig17_HTML.jpg

图 13-17

ADF 数据流湖到 Synapse 增量向上插入管道参数

该数据流将包含以下三项活动:

  1. SrcLake :这是到 ADLS Gen2 账户的源连接。

  2. AlterRow :这是通过识别哪些行需要向上插入到接收器中来开始向上插入过程的步骤。

  3. dstSynapse :这是 Synapse Analytics DW 的接收连接。

首先配置湖源的设置,如图 13-18 所示。

img/511918_1_En_13_Fig18_HTML.jpg

图 13-18

ADF 数据流源设置

接下来,确保源选项选项卡包含参数化的FolderName,如图 13-19 所示。

img/511918_1_En_13_Fig19_HTML.jpg

图 13-19

ADF 数据流源选项

图 13-20 显示了如何添加一个 AlterRow 转换活动,然后在行条件等于true()时将 alter row 条件设置为 Upsert。

img/511918_1_En_13_Fig20_HTML.jpg

图 13-20

AlterRow 转换活动设置

在图 13-21 所示的优化选项卡中,使用当前分区,但也要注意可能有机会探索为大数据工作负载设置分区并提高性能。

img/511918_1_En_13_Fig21_HTML.jpg

图 13-21

AlterRow 转换活动分区优化选项

最后,配置目标 Synapse Analytics DW 数据集,如图 13-22 所示。

img/511918_1_En_13_Fig22_HTML.jpg

图 13-22

ADF 数据流接收器连接属性

在设置选项卡中,如图 13-23 所示,选择“允许上插”作为更新方法,并添加您创建并填充在管道参数表中的upsert_key_column。在本练习中,您可以选择不启用转移,但这对于性能优化来说可能是一个不错的选择。

img/511918_1_En_13_Fig23_HTML.jpg

图 13-23

ADF 数据流接收器设置

最后,确保映射数据流参数包含图 13-24 所示的FolderNameupsert_key_column,。要获得这些参数,请记住单击映射数据流画布的空白区域。

img/511918_1_En_13_Fig24_HTML.jpg

图 13-24

ADF 数据流参数

运行 ADF 管道

现在 ADF 管道已经构建好了,是时候运行它们了,以便测试和验证 Azure SQL 到 ADLS Gen2 管道和 ADLS Gen2 到 Synapse Analytics DW 管道的结果。此外,作为验证步骤,本节将使用 SSMS 对源数据库和接收数据库运行 SQL 计数,以进一步测试、验证和确认结果的准确性。

验证增量 SQL 到 Lake 管道结果

运行此管道后,注意图 13-25 中端到端管道成功复制了一个表,因为pipeline_parameter表中只有一条记录。

img/511918_1_En_13_Fig25_HTML.jpg

图 13-25

“成功”的 ADF 增量管道状态

图 13-26 显示管道从源 Azure SQL 数据库表复制了 493 行到 ADLS Gen2 中的一个 parquet 文件。

img/511918_1_En_13_Fig26_HTML.jpg

图 13-26

ADF 数据流增量管道处理详细信息

验证增量上插湖到 Synapse ADF 管道结果

是时候验证增量 ADF 管道已经将相关数据从 ADLS Gen2 转移到 Synapse Analytics DW。图 13-27 显示来自 ADLS Gen2 的增量 upsert 复制了超过 493 行到 Synapse Analytics DW。

img/511918_1_En_13_Fig27_HTML.jpg

图 13-27

ADF 数据流增量向上插入管道处理详细信息

验证源 SQL 记录计数

之所以有 493 行,如图 13-28 所示,是因为源包含 493 行,其创建日期大于 2020 年 4 月 1 日,并且由于这是您在pipeline_parameter表中定义的incremental_watermark_value,这就是 ADF 管道预计增量加载的记录数。

img/511918_1_En_13_Fig28_HTML.jpg

图 13-28

用于验证的 SSMS 记录计数

以下是图 13-28 中显示的 SQL 查询:

SELECT Count(logid) AS IncrementalRecordCount
FROM   [dbo].[log]
WHERE  createddt > '04-01-2020'

验证湖文件夹和拼花文件路径

还要确认 ADLS Gen2 文件夹和一个拼花文件已经创建,如图 13-29 所示。

img/511918_1_En_13_Fig29_HTML.jpg

图 13-29

包含来自 ADF 管道的拼花文件的 ADLS Gen2 文件夹

验证目标 Synapse 记录计数

最后,在目标 Synapse Analytics DW 表上运行 SQL count 语句后,图 13-30 中显示的计数确认有 493 条记录,证明增量管道按预期工作。

img/511918_1_En_13_Fig30_HTML.jpg

图 13-30

接收器中增量管道记录的 SSMS 计数

以下是图 13-30 中显示的 SQL 查询:

SELECT Count(logid) AS IncrementalRecordCount
FROM   [etl].[log]
WHERE  createddt > '04-01-2020'

插入源 SQL 记录

既然您已经确认了 Synapse Analytics DW 管道的增量 SQL 按预期工作,那么还需要通过向源 SQL 表添加一条创建日期大于 2020 年 4 月 1 日的额外记录来验证 Upsert 命令的插入部分是否按预期工作。

添加记录并运行计数后,请注意查询现在返回 494 条记录,而不是 493 条,如图 13-31 所示。

img/511918_1_En_13_Fig31_HTML.jpg

图 13-31

插入源记录的 SQL 计数

以下是图 13-31 中显示的 SQL 查询:

SELECT Count(logid) AS IncrementalRecordCount
FROM   [dbo].[log]
WHERE  createddt > '04-01-2020'

验证 Lake ADF 管道结果的增量 SQL

再次运行管道,注意新的管道日志结果从 SQL 到 lake 返回计数 494,如图 13-32 所示。

img/511918_1_En_13_Fig32_HTML.jpg

图 13-32

ADF 数据流增量管道执行详细信息

验证增量上插湖到 Synapse ADF 管道结果

此外,请注意,新的管道日志结果从 lake 向 Synapse Analytics DW 返回 494 的计数,如图 13-33 所示。

img/511918_1_En_13_Fig33_HTML.jpg

图 13-33

ADF 数据流增量向上插入管道执行详细信息

验证目标 Synapse Analytics 数据仓库记录计数

最后,图 13-34 中所示的目标 Synapse Analytics DW 表也包含 494 条记录,这证实了插入按预期工作。

img/511918_1_En_13_Fig34_HTML.jpg

图 13-34

目标 Synapse Analytics 数据仓库记录的 SQL 计数

以下是图 13-34 中显示的 SQL 查询:

SELECT Count(logid) AS IncrementalRecordCount
FROM   [etl].[log]
WHERE  createddt > '04-01-2020'

更新源 SQL 记录

运行最后一个测试,以确保映射数据流 upsert 的更新命令按预期工作。对于这个测试,更新表,将FacilityId设置为等于 100,其中创建日期大于 2020 年 4 月 1 日。图 13-35 显示了这个脚本如何更新源 SQL 表中的两行。

img/511918_1_En_13_Fig35_HTML.jpg

图 13-35

更新源记录的 SQL

验证目标 Synapse Analytics 数据仓库记录计数

正如所料,目标 Synapse Analytics DW 表当前没有FacilityID = 100 的记录,如图 13-36 所示。

img/511918_1_En_13_Fig36_HTML.jpg

图 13-36

验证目标表上的预更新的 SQL

以下是图 13-36 中显示的 SQL 查询:

SELECT Count(logid) AS IncrementalRecordCount
FROM   [etl].[log]
WHERE  facilityid = 100

再次运行管道后,请注意图 13-37 中的目标 Synapse Analytics DW 表仍然包含 494 行,并且有两条记录的FacilityId已经更新为 100。这最终确认了更新和插入命令以及从源 SQL 表到 ADLS Gen2 并最终到 Synapse Analytics DW 的增量加载都按预期工作。

img/511918_1_En_13_Fig37_HTML.jpg

图 13-37

验证目标表的更新记录的 SQL

以下是图 13-37 中显示的 SQL 查询:

SELECT Count(logid) AS IncrementalRecordCount
FROM   [etl].[log]

SELECT Count(logid) AS IncrementalRecordCount
FROM   [etl].[log]
WHERE  facilityid = 100

摘要

在这一章中,我展示了 Azure Data Factory 的 Mapping Data Flows upsert 特性的一些功能,这些功能用于更新数据并将数据从 Azure Data Lake Storage gen 2 parquet 文件插入 Azure Synapse Analytics DW。我向您展示了如何构建一个定制方法,根据 Azure SQL 数据库中的创建日期用 parquet 文件增量填充 Data Lake Storage Gen2,并测试和验证结果。值得一提的是,这种从源到接收器递增加载数据的定制方法是可以使用的许多可能方法之一。Microsoft、ADF 产品团队和各种社区贡献者经常在博客上讨论使用 ADF 从源到接收器增量加载数据的替代方法。

十四、将 Excel 表加载到 Azure SQL 数据库表中

将 Excel 电子表格中的数据加载到 SQL 数据库中是许多组织多年来的一项长期需求。以前,诸如 VBA、SSIS、C#等工具被用来执行这个数据摄取编排过程。微软 Azure 的Excel connector(https://docs.microsoft.com/en-us/azure/data-factory/format-excel)for Azure Data Factory(ADF)是一个很有前途的基于云的连接器,它允许使用 Excel 的易用、低代码体验,很像内部部署的 SSIS Excel 连接器。

Azure Data Factory 中的 Excel 连接器提供了利用动态和参数化管道的能力,以便使用 ADF 将 Excel 电子表格加载到 Azure SQL 数据库表中。在这一章中,我将演示如何动态地将包含多个工作表的 ADLS Gen2 帐户中的 Excel 电子表格加载到单个 Azure SQL 表中,以及每个工作表的多个表中。

先决条件

成功创建端到端 ADF 管道以将 Excel 文件加载到关系 SQL 数据库需要几个设置步骤。首先,您需要做一些准备工作来创建所需的 Excel 电子表格。然后你需要把它上传到 ADLS 第二代账户。最后,您需要在 ADF 中创建相应的链接服务和数据集,为 ADF 管道的创建做准备。

创建 Excel 电子表格

图 14-1 中的图像显示了一个包含四个工作表的 Excel 电子表格示例,每个工作表都包含相同的标题和模式,您将需要在 ADF 管道中使用它们来加载 Azure SQL 表中的数据。期望这四个表都有相同的模式、列顺序和标题。该过程不测试极限情况,例如模式漂移、Excel 文件中的嵌入图像等等。你可以在我的 GitHub repo 中找到一个样本 Excel 文件,SampleExcelFiles,在下面: https://github.com/ronlesteve/SampleExcelFiles

img/511918_1_En_14_Fig1_HTML.jpg

图 14-1

包含四张数据工作表的 Excel 电子表格示例

上传到 Azure 数据湖存储二代

创建 Excel 电子表格后,将电子表格上传至您的 ADLS Gen2 账户,如图 14-2 所示。

img/511918_1_En_14_Fig2_HTML.jpg

图 14-2

Excel 文件已加载到 ADLS Gen2

创建链接的服务和数据集

在数据工厂中,为 Excel 电子表格的文件路径添加一个 ADLS Gen2 链接服务,该服务已经添加到data/raw/ExcelSpreadSheet文件夹路径中,如图 14-3 所示。提醒一下,由于 ADLS Gen2 是一个分层的文件系统,ADF 管道将能够轻松地遍历多个文件夹层次结构来定位文件。

img/511918_1_En_14_Fig3_HTML.jpg

图 14-3

Excel 电子表格位置的 ADLS Gen2 链接服务

图 14-4 显示了 ADLS 第二代连接的正确配置属性。确保 ADLS 第二代链接服务凭据配置准确。

img/511918_1_En_14_Fig4_HTML.jpg

图 14-4

ADLS 第二代链接服务凭据

创建新数据集时,注意图 14-5 中我们有一个 Excel 格式的选项,可以选择。

img/511918_1_En_14_Fig5_HTML.jpg

图 14-5

Excel 数据集格式

Excel 数据集的连接配置属性可在图 14-6 中找到。工作表名称属性需要用动态参数化的@dataset().SheetName值进行配置。此外,由于文件中存在标题,请选中“第一行作为标题”同样,本练习假设电子表格中没有浮动图像。此外,本练习中没有测试模式漂移和额外的头。

img/511918_1_En_14_Fig6_HTML.png

图 14-6

Excel 数据集连接属性

在参数页签内,添加SheetName,如图 14-7 所示。该参数将在 Excel 文件中存储工作表的名称,该文件提供 ForEach 循环活动,该循环活动遍历每个工作表并将它们加载到 SQL 数据库中。

img/511918_1_En_14_Fig7_HTML.jpg

图 14-7

Excel 数据集参数属性

接下来,将一个接收数据集添加到目标 Azure SQL 表,并连接到适当的链接服务,如图 14-8 所示。请注意,虽然您已经指定了包括模式和表名的硬编码表路径,但是您不需要担心在 SQL 数据库中创建这个对应的表。在 ADF 中,当在管道中配置接收器数据集属性时,您需要启用一个属性,以便根据源 Excel 文件的传入架构“自动创建”表,您将在本章后面了解该属性。

img/511918_1_En_14_Fig8_HTML.png

图 14-8

Azure SQL 接收器数据集连接属性

概括地说,在本节中,您已经创建了必要的先决条件,包括创建 Excel 电子表格并将其上传到 ADLS Gen2,以及创建数据集和链接服务。至此,您已经准备好进入下一部分,在这里您将学习如何创建实际的 ADF 管道来将 Excel 电子表格加载到 Azure SQL 数据库表中。

创建一个管道,将电子表格中的多个 Excel 表加载到单个 Azure SQL 表中

现在,让我们创建一个管道,将单个电子表格文件中的多个 Excel 表加载到单个 Azure SQL 表中。在 ADF 窗格中,创建一个新管道,然后将 ForEach 循环活动添加到管道画布中。接下来,单击管道中画布的空白区域,添加一个名为SheetName的新数组变量,该变量包含电子表格中从 Sheet1 到 Sheet4 的所有工作表的默认值,如图 14-9 所示。

img/511918_1_En_14_Fig9_HTML.jpg

图 14-9

ADF ForEach 循环连接变量

接下来,点击 ForEach 循环活动将其启用,然后将@variables('SheetName')添加到 ForEach 循环活动的设置页签的 Items 属性中,如图 14-10 所示。

img/511918_1_En_14_Fig10_HTML.jpg

图 14-10

ADF ForEach 连接设置

接下来,点击图 14-10 中的 Activities 选项卡,导航至 ForEach 循环活动。或者,您可以通过单击 ForEach 循环活动中显示的铅笔图标来访问活动。添加一个带有源配置的复制数据活动,如图 14-11 所示。

img/511918_1_En_14_Fig11_HTML.png

图 14-11

ADF 复制数据源数据集连接属性

在图 14-12 所示的水槽配置中,将表格选项属性设置为“自动创建表格”,因为表格尚未创建。

img/511918_1_En_14_Fig12_HTML.jpg

图 14-12

ADF 复制活动接收器连接属性

在执行管道之后,注意图 14-13 中的四张表已经被加载到 Azure SQL 表中。

img/511918_1_En_14_Fig13_HTML.jpg

图 14-13

成功的 ADF Excel 到 SQL 管道执行状态

导航到 Azure SQL 表并查询它。注意在图 14-14 中,所有 Excel 表中的数据都被加载到一个 Azure SQL 表中。

以下是在图 14-14 中执行的 SQL 查询:

SELECT [orderdate],
       [region],
       [rep],
       [item],
       [units],
       [unit cost],
       [total]
FROM   [dbo].[orders]

img/511918_1_En_14_Fig14_HTML.jpg

图 14-14

从 SSMS 查询 Azure SQL 表以确认数据可用

创建一个管道将电子表格中的多个 Excel 表加载到多个 Azure SQL 表中

在下一个示例中,让我们测试将多个 Excel 工作表从一个 Excel 电子表格加载到同一个数据库中的多个 Azure SQL 表中。首先,创建一个新的 Excel 查找表,如图 14-15 所示,包含SheetNameTableName,将被动态 ADF 管道参数使用。

img/511918_1_En_14_Fig15_HTML.jpg

图 14-15

创建包含 SheetName 和 TableName 的 Excel 查找表

以下脚本用于创建图 14-15 中的查找表:

SET ansi_nulls ON

go

SET quoted_identifier ON

go

CREATE TABLE [dbo].[exceltablelookup]
  (
     [sheetname] NVARCHAR NULL,
     [tablename] NVARCHAR NULL
  )
ON [PRIMARY]
textimage_on [PRIMARY]

表格创建完成后,将SheetNames和相应的TableNames插入表格,如图 14-16 所示。

img/511918_1_En_14_Fig16_HTML.jpg

图 14-16

将工作表名称和相应的表格名称插入表格

以下是已经在图 14-16 中执行的 SQL 查询:

SELECT [sheetname],
       [tablename]
FROM   [dbo].[exceltablelookup]

接下来,添加一个连接到 Excel 查找表的新数据集,如图 14-17 所示。

img/511918_1_En_14_Fig17_HTML.jpg

图 14-17

查找表的 ADF 数据集连接属性

图 14-18 显示 Excel 电子表格的连接属性将类似于之前我们参数化SheetName的管道。

img/511918_1_En_14_Fig18_HTML.jpg

图 14-18

ADF Excel 数据集连接属性

在这个场景中,为 Azure SQL 数据库数据集连接中的TableName添加一个参数,如图 14-19 所示。

img/511918_1_En_14_Fig19_HTML.jpg

图 14-19

Azure SQL 数据库连接参数

在 Azure SQL DB Connection 选项卡中,将模式保留为硬编码,并为TableName添加参数,如图 14-20 所示。

img/511918_1_En_14_Fig20_HTML.jpg

图 14-20

Azure SQL 数据库参数化连接

在这个管道中,将需要一个查找表,它将通过对表的select *查找来服务于在 SQL 查找表中查找值的目的,如图 14-21 所示。

img/511918_1_En_14_Fig21_HTML.jpg

图 14-21

ADF 查找设置

Note

出于本练习的目的,已经选择了查询选项,并且嵌入了源 SQL 查询。作为 ADF 管道中低嵌入式 SQL 代码维护的替代选项,可以考虑使用表或存储过程查询选项类型。

图 14-22 显示了如何将查找的值传递给设置选项卡的 ForEach 循环活动的项目属性。

img/511918_1_En_14_Fig22_HTML.jpg

图 14-22

ADF ForEach 循环设置

接下来,在 ForEach 循环活动中,添加一个复制数据活动,其源数据集属性包含参数化的SheetName值,如图 14-23 所示。

img/511918_1_En_14_Fig23_HTML.jpg

图 14-23

ADF 复制数据源数据集连接属性

接下来,sink 数据集属性还需要包含参数化的TableName值,如图 14-24 所示。请注意,表选项再次设置为“自动创建表”,这将基于源 Excel 文件的传入模式创建表。

img/511918_1_En_14_Fig24_HTML.jpg

图 14-24

ADF 接收器数据集连接属性

在您完成这个 ADF 管道的执行之后,请注意图 14-25 中的管道成功了,并且在您的 Azure SQL 数据库中创建了四个表。

img/511918_1_En_14_Fig25_HTML.jpg

图 14-25

成功的 ADF Excel 到 SQL 管道状态

导航到 Azure SQL 数据库,注意在图 14-26 中,所有四个表都是基于您在 SQL 查找表中定义的TableName值用适当的名称创建的。

img/511918_1_En_14_Fig26_HTML.jpg

图 14-26

从 Excel 表加载到 Azure SQL 数据库的表格的 SSMS 视图

作为最后一项检查,查询图 14-27 中所示的所有四个表格,注意它们都包含来自 Excel 表格的数据,这确认了管道成功执行,表格到多个表格的正确映射在查找表中定义。

img/511918_1_En_14_Fig27_HTML.jpg

图 14-27

所有表的 SSMS 视图,以验证数据是否存在

以下是已经在图 14-27 中执行的 SQL 查询:

SELECT [orderdate],
       [region],
       [rep],
       [item],
       [units],
       [unit cost],
       [total]
FROM   [dbo].[table1]

SELECT [orderdate],
       [region],
       [rep],
       [item],
       [units],
       [unit cost],
       [total]
FROM   [dbo].[table2]

SELECT [orderdate],
       [region],
       [rep],
       [item],
       [units],
       [unit cost],
       [total]
FROM   [dbo].[table3]

摘要

在本章中,我演示了如何使用 Azure Data Factory 的 Excel 连接器以及参数化管道,将位于 ADLS Gen2 中的包含多个工作表的 Excel 电子表格动态加载到单个 Azure SQL 表中,以及每个工作表的多个表中。

十五、DeltaLake

在使用 Azure Data Lake Storage Gen2 和 Apache Spark 时,用户已经了解了 Apache Spark 的局限性和许多数据湖实现挑战。在数据湖环境中,对 ACID 兼容功能集的需求至关重要,Delta Lake 针对标准 Azure 数据湖存储二代帐户的当前限制提供了许多解决方案。

Delta Lake 是一个开源存储层,它保证了湖中数据的原子性、一致性、隔离性和持久性。简而言之,DeltaLake 泊是酸性的。除了提供 ACID 事务、可伸缩的元数据处理等等,Delta Lake 运行在现有的数据湖之上,并且与 Apache Spark APIs 兼容。DeltaLake 有几种入门方法。Databricks 提供笔记本以及兼容的 Apache Spark APIs 来创建和管理 DeltaLake 泊。或者,Azure Data Factory 的映射数据流(使用向外扩展的 Apache Spark 集群)可用于通过 GUI 设计的 ETL 管道执行符合 ACID 的 CRUD 操作。本章将通过如何在 Delta Lake 中创建、插入、更新和删除的示例,演示如何使用 Azure Data Factory 的 Delta Lake 连接器开始使用 Delta Lake。

为什么是酸性 DeltaLake

将 Delta Lake 引入现代云数据架构有许多优势。传统上,数据湖和 Apache Spark 不符合 ACID。Delta Lake 引入了这种酸性合规性,以解决以下许多酸性合规性问题:

  1. 原子性 : 要么写全部数据,要么什么都不写。Apache Spark 保存模式不使用任何锁定,并且不是原子的。这样,失败的作业可能会留下不完整的文件,并可能会损坏数据。此外,失败的作业可能会删除旧文件并损坏新文件。虽然这似乎令人担忧,但 Spark 确实有内置的数据帧编写器 API,这些 API 不是原子的,但对于追加操作却是如此。然而,使用云存储会带来性能开销。当前可用的 Apache Spark 保存模式包括 ErrorIfExists、Append、Overwrite 和 Ignore。

  2. 一致性 : 数据始终处于有效状态。如果 Spark API writer 删除一个旧文件并创建一个新文件,并且该操作不是事务性的,那么在删除旧文件和创建新文件之间总会有一段时间文件不存在。在这种情况下,如果覆盖操作失败,这将导致旧文件的数据丢失。此外,可能无法创建新文件。这是一个典型的与一致性相关的 Spark 覆盖操作问题。

  3. 隔离 : 多个交易独立发生,互不干扰。这意味着写入数据集时,同一数据集上的其他并发读取或写入不应受到写入操作的影响。典型的事务数据库提供多种隔离级别,如未提交读、提交读、可重复读、快照和可序列化。虽然 Spark 有任务级和作业级提交,但由于它缺乏原子性,所以它没有隔离类型。

  4. 耐久性 : *提交的数据永不丢失。*当 Spark 没有正确执行提交时,它会覆盖云存储选项提供的所有强大的持久性功能,并损坏和/或丢失数据。这违反了数据持久性。

先决条件

现在,您已经了解了当前的数据湖,了解了 Spark 挑战以及符合 ACID 的 Delta 湖的好处,让我们开始练习吧。

对于本练习,请确保成功创建以下先决条件:

img/511918_1_En_15_Fig1_HTML.jpg

图 15-1

ADLS 第二代区域/文件夹

  1. 创建数据工厂 V2 :数据工厂将用于执行 ELT 编排。此外,ADF 的地图数据流 DeltaLake 连接器将用于创建和管理 DeltaLake。

  2. 创建数据湖存储二代 : ADLS Gen2 将是数据湖存储,在其之上将创建 Delta 湖。

  3. 创建 Data Lake Storage Gen2 容器和区域:创建 Data Lake Storage Gen2 帐户后,还要创建适当的容器和区域。再次访问第三章,了解有关设计 ADLS 第二代区域的更多信息,我将在其中讨论如何设计 ADLS 第二代存储客户。本练习将使用原始区域来存储示例源拼花文件。此外,临时区域将用于增量更新、插入、删除和其他转换。尽管在本练习中不会使用策划区域,但有一点很重要,即该区域可能包含最终的 ETL、高级分析或数据科学模型,这些模型是从临时区域进一步转换和策划的。一旦在你的 ADLS 第二代账户中创建了不同的区域,它们看起来将类似于图 15-1 中的图示。

img/511918_1_En_15_Fig2_HTML.jpg

图 15-2

示例 userdata1.parquet 文件

  1. 上传数据到原始区域:最后,这个练习你需要一些数据。通过在网上或公开可用的数据集中搜索“样本拼花文件”,您将获得大量免费样本拼花文件。对于本练习,您可以在下面的GitHub repo(https://github.com/Teradata/kylo/tree/master/samples/sample-data/parquet)中下载示例拼花文件,然后将其上传到您的 ADLS Gen2 存储帐户,如图 15-2 所示。

img/511918_1_En_15_Fig3_HTML.jpg

图 15-3

ADF 中的 userData1 连接设置

  1. 创建一个指向原始区域的数据工厂拼花数据集:最后一个先决条件是在新创建的 ADF V2 实例中创建一个拼花格式数据集,如图 15-3 所示,指向原始区域中存储的样本拼花文件。

创建并插入 DeltaLake

现在,所有先决条件都已就绪,您可以创建初始增量表,并将原始区域中的数据插入到增量表中。

通过创建一个新的数据工厂管道并向其添加一个新的“映射数据流”来开始这个过程。还记得命名管道和数据流的合理名称,很像图 15-4 中所示的示例。

img/511918_1_En_15_Fig4_HTML.jpg

图 15-4

映射用于插入的数据流画布

在数据流中,添加一个源,其配置设置如图 15-5 所示。此外,选中“允许模式漂移”选项当与字段、列和类型相关的元数据频繁更改时,这被称为模式漂移。如果没有适当的过程来处理模式漂移,ETL 管道可能会失败。ADF 支持经常变化的灵活模式。ADF 将模式漂移视为后期绑定。因此,您将无法在数据流中查看漂移的架构。

当启用模式漂移时,所有传入的字段都在执行期间从源中读取,并通过整个流传递到接收器。默认情况下,所有新检测到的列都是字符串数据类型。如果需要自动推断漂移列的数据类型,则需要在源设置中启用推断漂移列类型。

允许自动检测漂移的色谱柱类型。采样提供了一种限制源中行数的方法,主要用于测试和调试目的。

img/511918_1_En_15_Fig5_HTML.jpg

图 15-5

为插入操作映射数据流 ETL 流源设置

由于 Delta Lake 利用了 Spark 的分布式处理能力,它能够适当地对数据进行分区。然而,为了探索手动设置分区的能力,在 ID 列上配置 20 个散列分区,如图 15-6 所示。

img/511918_1_En_15_Fig6_HTML.jpg

图 15-6

优化 MDF 分区的设置

添加目的地活动后,确保在 Azure 数据工厂 ( https://docs.microsoft.com/en-us/azure/data-factory/format-delta )中将如图 15-7 所示的 sink 类型设置为 Delta 格式。请注意,DeltaLake 在绘制数据流图时既可以作为源,也可以作为汇。此外,一旦选择了 Delta Lake 的汇类型,您将需要选择链接的服务。

img/511918_1_En_15_Fig7_HTML.jpg

图 15-7

MDF 接收器设置

在图 15-8 所示的设置选项卡下,确保暂存文件夹被选中,并选择允许插入作为更新方法。此外,如果需要在加载前截断增量表,请选择 Truncate table 选项。

在湖( https://docs.databricks.com/spark/latest/spark-sql/language-manual/delta-vacuum.html )中清空增量表的过程将删除增量表不再引用的文件以及超过保留阈值(小时)的文件。如果该值保留为 0 或为空,则默认值为 30 天。

img/511918_1_En_15_Fig8_HTML.jpg

图 15-8

在 MDF 中插入水槽的设置

最后,在图 15-9 所示的优化选项卡中,使用当前分区,因为源分区将向下游流向接收器。

img/511918_1_En_15_Fig9_HTML.jpg

图 15-9

用于优化接收器的分区选项

正如预期的那样,一旦您触发了管道,并且在它完成运行之后,从图 15-10 中可以注意到,在 20 个不同的分区中创建了 13 个新列。

img/511918_1_En_15_Fig10_HTML.jpg

图 15-10

ADF MDF 管道运行详细信息

在查看 ADLS Gen2 暂存文件夹时,请注意图 15-11 中的一个 delta_log 文件夹以及 20 个快速压缩的拼花文件已经创建。

img/511918_1_En_15_Fig11_HTML.jpg

图 15-11

DeltaLake 分区文件

打开 delta_log 文件夹查看两个事务日志文件,如图 15-12 所示。事务日志捕获了许多重要的特性,包括 ACID 事务、可伸缩的元数据处理、时间旅行,以及更多的( https://databricks.com/blog/2019/08/21/diving-into-delta-lake-unpacking-the-transaction-log.html )

img/511918_1_En_15_Fig12_HTML.jpg

图 15-12

增量日志文件

在检查了 Staging Delta Lake 中的新数据后,注意到有新的记录被插入。要通过绘制数据流图从 ADF 轻松探索 DeltaLake,只需切换数据预览选项卡即可查看数据流的详细信息,如图 15-13 所示。

img/511918_1_En_15_Fig13_HTML.jpg

图 15-13

插入从拼花文件读取的数据结果

更新 DeltaLake

到目前为止,在上一节中已经介绍了到 Delta Lake 的插入。接下来,让我们看看 Data Factory 如何处理对增量表的更新。类似于您在上一节中对插入所做的,创建一个新的 ADF 管道,带有用于更新的映射数据流,如图 15-14 所示。

img/511918_1_En_15_Fig14_HTML.jpg

图 15-14

MDF 更新 DeltaLake

在这个更新练习中,更新用户的名字和姓氏,并将其转换为小写。为此,向更新映射数据流画布添加一个派生的 column 和 AlterRow 转换活动,如图 15-15 所示。

img/511918_1_En_15_Fig15_HTML.jpg

图 15-15

用于更新映射数据流拼花的源设置

在图 15-16 所示的源选项选项卡中,源数据仍然是您的暂存 Delta Lake,它也是为插入而配置的。ADF 中的 Delta Lake source 连接器还为大规模数据湖引入了 delta time travel,以审计数据更改、重现结果、处理回滚等。时光旅行可以按时间戳或版本查询数据( https://databricks.com/blog/2019/02/04/introducing-delta-time-travel-for-large-scale-data-lakes.html ) )。

img/511918_1_En_15_Fig16_HTML.jpg

图 15-16

更新源选项

派生的列转换活动使用表达式lower(first_name)lower(last_name)将名字和姓氏转换成小写,如图 15-17 所示。映射数据流能够在这个阶段处理极其复杂的转换。

img/511918_1_En_15_Fig17_HTML.jpg

图 15-17

用于更新的派生列设置

对于更改行设置,您需要指定一个更新 if 条件true()来更新所有符合条件的行,如图 15-18 所示。

img/511918_1_En_15_Fig18_HTML.jpg

图 15-18

AlterRow 更新的设置

确保您验证了 Sink 选项卡的配置设置,如图 15-19 所示。

img/511918_1_En_15_Fig19_HTML.jpg

图 15-19

更新 MDF 的接收器设置

确保接收器仍然指向暂存的 DeltaLake 数据。另外,选择“允许更新”作为更新方法。为了显示可以同时选择多个键列,在图 15-20 中选择了三列。

img/511918_1_En_15_Fig20_HTML.jpg

图 15-20

更新 MDF 接收器的方法设置

保存并触发管道后,注意 ADF 数据预览选项卡的结果,如图 15-21 所示。名字和姓氏已更新为小写值。

img/511918_1_En_15_Fig21_HTML.png

图 15-21

显示预期更新的数据

从 DeltaLake 删除

概括地说,到目前为止,已经讨论了插入和更新。接下来,让我们看一个映射数据流如何处理 Delta Lake 中的删除的例子。类似于建立插入和更新 MDF 管道的过程,创建一个新的数据工厂映射数据流,如图 15-22 所示。

img/511918_1_En_15_Fig22_HTML.jpg

图 15-22

用于从 Delta Lake 删除的 MDF

根据需要配置增量源设置,如图 15-23 所示。

img/511918_1_En_15_Fig23_HTML.jpg

图 15-23

mdf_delete_deltalake 的源设置

由于您仍在使用相同的暂存 DeltaLake,这些源设置(如图 15-24 所示)将按照您在前面章节中配置插入和更新的方式进行配置。

img/511918_1_En_15_Fig24_HTML.jpg

图 15-24

mdf_delete_deltalake 的源选项

对于本例,删除所有gender = male处的记录。为此,您需要将更改行条件配置为 Delete if gender == 'Male' ,如图 15-25 所示。

img/511918_1_En_15_Fig25_HTML.jpg

图 15-25

更改 mdf_delete_deltalake delta 的行设置

最后,图 15-26 显示了 sink delta 配置设置。

img/511918_1_En_15_Fig26_HTML.jpg

图 15-26

mdf_delete_deltalake 的接收器设置

选择 sink 的 Staging Delta Lake,选择*【允许删除】*,同时选择需要的id``registration_dttm``and ip_address按键栏,如图 15-27 所示。

img/511918_1_En_15_Fig27_HTML.jpg

图 15-27

mdf_delete_deltalake 的目标

发布并触发该管道后,请注意图 15-28 中gender = Male处的所有记录是如何被删除的。

img/511918_1_En_15_Fig28_HTML.jpg

图 15-28

按预期删除数据文件

浏览增量日志

最后,让我们看一下增量日志,以简要了解日志是如何创建和填充的。主提交信息文件生成并存储在插入、更新和删除 JSON 提交文件中。此外,还会创建 CRC 文件。CRC 是一种用于检查数据完整性的流行技术,因为它具有出色的错误检测能力,使用很少的资源,并且易于使用。从 ADF 增量插入、更新和删除 MDF 管道创建的增量日志存储在您的 ADLS Gen2 帐户的 _delta_log 文件夹中,如图 15-29 所示。

img/511918_1_En_15_Fig29_HTML.jpg

图 15-29

插入、更新和删除后的增量日志

插入

打开图 15-30 所示的插入 JSON 提交文件,注意它包含插入操作的提交信息,由以单词*“添加”*开头的行项目引用。在构建 ETL 管道和过程时,通常不需要使用或打开这些文件。但是,日志总是以 JSON 格式保存在这个文件夹中,所以您总是可以选择在需要时打开日志。对于本练习,打开这些日志将使您更深入地了解这些日志是如何捕获信息的,从而有助于更好地理解该过程的机制。

img/511918_1_En_15_Fig30_HTML.jpg

图 15-30

增量日志插入

{"commitInfo":{"timestamp":1594782281467,"operation":"WRITE","operationParameters":{"mode":"Append","partitionBy":"[]"},"isolationLevel":"WriteSerializable","isBlindAppend":true}}

更新

类似于插入增量日志,打开图 15-31 所示的更新 JSON 提交文件,注意它包含更新操作的提交信息。以*“删除”开头的行项目显示了已删除数据文件的路径,以“添加”*开头的行项目显示了更新过程中添加的数据。此外,这些日志中还提供了与提交信息、时间戳等相关的重要细节。同样,在常规的 ADF 管道过程中,您不需要研究这些增量日志,这意味着是一个信息性和探索性的练习。

img/511918_1_En_15_Fig31_HTML.jpg

图 15-31

增量日志更新

{"commitInfo":{"timestamp":1594782711552,"operation":"MERGE","operationParameters":{"predicate":"(((source.`id` = target.`id`) AND (source.`registration_dttm` = target.`registration_dttm`)) AND (source.`ip_address` = target.`ip_address`))","updatePredicate":"((NOT ((source.`ra2b434a305b34f2f96cd5b4b4149455e` & 2) = 0)) OR (NOT ((source.`ra2b434a305b34f2f96cd5b4b4149455e` & 8) = 0)))","deletePredicate":"(NOT ((source.`ra2b434a305b34f2f96cd5b4b4149455e` & 4) = 0))"},"readVersion":0,"isolationLevel":"WriteSerializable","isBlindAppend":false}}

删除

最后,打开图 15-32 所示的删除 JSON 提交文件,注意它包含了删除操作的提交信息。已删除的文件由以*“删除”*开头的行项目捕获。现在您已经了解了这些 delta 事务日志,以及如何打开和解释它们,您将更好地理解 Delta Lake 的相关性,以及它在处理数据湖中符合 ACID 的事务方面的定位。

img/511918_1_En_15_Fig32_HTML.jpg

图 15-32

增量日志删除

"commitInfo":{"timestamp":1594783812366,"operation":"MERGE","operationParameters":{"predicate":"(((source.`id` = target.`id`) AND (source.`registration_dttm` = target.`registration_dttm`)) AND (source.`ip_address` = target.`ip_address`))","updatePredicate":"((NOT ((source.`ra079d97a688347b581710234d2cc4b63` & 2) = 0)) OR (NOT ((source.`ra079d97a688347b581710234d2cc4b63` & 8) = 0)))","deletePredicate":"(NOT ((source.`ra079d97a688347b581710234d2cc4b63` & 4) = 0))"},"readVersion":1,"isolationLevel":"WriteSerializable","isBlindAppend":false}}

摘要

在这一章中,我通过使用 Azure Data Lake Storage Gen2 作为存储帐户在 Delta Lake 中创建、插入、更新和删除的示例,演示了如何使用 Azure Data Factory 的 Delta Lake 连接器开始使用 Delta Lake。由于 Delta Lake 是一个开源项目,旨在支持在现有存储系统的基础上构建 lakehouse 架构,因此它当然可以用于其他存储系统,如亚马逊 S3、谷歌云存储、HDFS 等。此外,通过在 Databricks 笔记本中编写 Spark、Python 和/或 Scala 代码,您可以轻松地使用 Delta Lake。

有了这样的灵活性,lakehouse 数据管理范式正在获得动力,它有望成为行业标准,并推动数据湖和数据仓库的发展。数据湖的低成本存储使得这种选择对于那些对成本敏感和追求增长的组织来说非常有吸引力。data lakehouse 的其他优势包括减少数据冗余、消除简单的 ETL 作业、将计算与存储分离、实时流支持、简化数据管理以及直接连接到现代 BI 工具的能力。虽然还处于起步阶段,但 data lakehouse 和 Delta Lake 确实有一定的局限性,使它们无法完全取代传统的数据仓库设备,如 SQL Server 数据库和仓库。然而,本章展示了以无代码方式直接使用 Delta Lake 的能力,并展示了如何轻松地使用 Delta Lake 开始探索数据湖库的构建块。

十六、流分析异常检测

许多企业越来越需要处理大数据实时流。众多行业的客户都在寻求利用实时大数据的力量来获得有价值的见解。他们正在寻求一种易于使用、灵活、可靠且可扩展的解决方案来处理和转换其物联网项目的实时数据流。此外,伴随这些大型实时数据流而来的是数据中的异常。各行各业的客户都对使用机器学习算法和运算符进行实时异常检测的概念感兴趣。

Azure Stream Analytics 是一个事件处理引擎,允许检查来自设备、传感器、网站、社交媒体源、应用等的大量数据流。它易于使用并且基于简单的 SQL。此外,它是 Azure 上的一个完全托管(PaaS)产品,可以运行针对成本进行了优化的大规模分析作业,因为用户只需为所消耗的流单元付费。

Azure Stream Analytics 现在提供内置的基于机器学习的异常检测功能,以监控临时和持久的异常。这种异常检测功能与 Power BI 的实时流服务相结合,形成了一种强大的实时异常检测服务。在这一章中,我将展示一个实例,展示如何使用 Azure Stream Analytics 创建实时异常检测来处理流,并使用 Power BI 来可视化数据。

先决条件

要开始实现本章的示例解决方案,您需要创建并运行一些 Azure 资源。这些是

  • 流分析工作 : Azure Stream Analytics 是一个实时分析和复杂事件处理引擎,旨在同时分析和处理来自多个来源的大量快速流数据。

  • 物联网中心:物联网中心是托管在云中的托管服务,充当物联网应用和其管理的设备之间双向通信的中央消息中心。

  • Power BI 服务:对于中小型企业而言,Power BI Pro 是向所有用户提供全面商业智能功能的最佳选择。Power BI Premium 最适合需要大量人员使用 Power BI 查看仪表板和报告的大型企业组织。请重新阅读第一章,我在这一章的最后讨论了 Power BI Pro 与 Premium 的优缺点。在本练习中,将使用 Power BI Premium。

  • 设备模拟器:设备模拟器 app,这是一个 Visual Studio 项目,可以从以下 GitHub 位置( https://github.com/Azure/azure-stream-analytics/tree/master/Samples/DeviceSimulator )下载,用于模拟从设备发送到物联网 Hub 的异常。一旦你下载并打开这个设备模拟器 Visual Studio 项目,你将能够运行它来查看设备模拟器 UI,它可以被配置为将事件从模拟器传递到你将在 Azure 中创建的物联网中心。模拟器数据的模式使用温度和传感器 ID。然后,这些事件可以由 Azure 流分析作业使用,该作业被配置为从该物联网中心读取。

下面几节将带您创建这些先决条件。

创建 Azure 流分析作业

让我们通过简单地搜索流分析,在 Azure Portal 中创建新的流分析作业,如图 16-1 所示。

img/511918_1_En_16_Fig1_HTML.jpg

图 16-1

Azure 门户中的新流分析作业

图 16-2 说明你需要将作业命名为asa-001。另外,选择相应的订阅、资源组和位置。我建议在一个资源组中为这个项目创建所有的资源。也就是说,您可以为此流分析作业创建一个新的资源组。此外,尽量在同一位置创建所有资源,以减少数据和网络延迟,尤其是因为这是一个实时流解决方案。对于本练习,选择“Cloud”将作业部署到 Azure cloud,因为这是典型的选择。选择“边缘”将作业部署到内部物联网网关边缘设备。做出选择后,单击创建。

img/511918_1_En_16_Fig2_HTML.jpg

图 16-2

新流分析作业详细信息

您现在已经创建了一个流分析作业。您还需要创建一个物联网中心,它将用于弥合设备模拟器和流分析作业之间的差距。

创建物联网中心

物联网中心是托管在云中的托管服务,充当物联网应用及其管理的设备之间双向通信的中央消息中心。物联网中心本质上是一个事件中心,具有额外的功能,包括每设备身份、云到设备的消息传递以及其他一些功能。在第一章中,我已经更详细地讨论了物联网和活动中心之间的异同。图 16-3 展示了如何从 Azure 门户创建物联网中心。

img/511918_1_En_16_Fig3_HTML.jpg

图 16-3

创建 Azure 门户物联网中心

在图 16-4 所示的基本选项卡中,为您的物联网中心命名,并确保订阅、资源组和区域配置正确。回想一下上一节,最好让物联网中心与流分析作业位于相同的资源组和区域。

img/511918_1_En_16_Fig4_HTML.jpg

图 16-4

物联网中心基础选项卡

还可以选择调整物联网中心的大小和规模,如图 16-5 所示。对于本练习,使用自由层,因为它最适合测试场景。物联网集线器的标准层支持所有功能,并且是任何想要利用双向通信功能的物联网解决方案所必需的。基本层支持部分功能,适用于仅需要从设备到云的单向通信的物联网解决方案。两层都提供相同的安全和身份验证功能。阅读微软的文档,了解何时以及如何根据能力需求选择合适的层( https://docs.microsoft.com/en-us/azure/iot-hub/iot-hub-scaling )。

img/511918_1_En_16_Fig5_HTML.jpg

图 16-5

物联网中心管理选项卡

选择所需的层后,查看图 16-6 中显示的选择,然后单击创建以部署物联网资源。

img/511918_1_En_16_Fig6_HTML.jpg

图 16-6

物联网中心审查+创建

部署物联网中心资源后,导航至图 16-7 所示的资源管理器下的物联网设备,然后单击物联网中心导航菜单下的新建,添加一个新设备,然后我们可以使用它来配置设备模拟器,该模拟器将向该物联网设备发送模拟事件。

img/511918_1_En_16_Fig7_HTML.jpg

图 16-7

物联网中心物联网设备

然后添加一个设备 ID,点击保存,如图 16-8 所示。设备 ID 只是设备的标识,用于设备认证和访问控制。对称密钥必须是有效的 base-64 格式,密钥长度在 16 到 64 字节之间。通过将证书指纹或证书颁发机构(CA)上传到 Azure IoT Hub,您可以使用任何 X.509 证书通过 IoT Hub 对设备进行身份验证。使用证书指纹的身份验证验证提供的指纹是否与配置的指纹匹配。选择“自动生成密钥”为该设备自动生成对称密钥。最后,支持设备与物联网中心的交互。

img/511918_1_En_16_Fig8_HTML.jpg

图 16-8

创建物联网中枢设备

一旦设备被添加,它将显示“启用”状态,如图 16-9 所示。单击设备以打开设备详细信息,包括密钥、身份和附加配置。

img/511918_1_En_16_Fig9_HTML.jpg

图 16-9

ASA 设备状态和 ID

接下来,复制如图 16-10 所示主键的连接字符串,它将被用作物联网设备的连接。

img/511918_1_En_16_Fig10_HTML.jpg

图 16-10

ASA 物联网设备的连接详细信息

创建 Power BI 服务

要开始使用 Power BI,请从以下网址下载免费桌面版: https://powerbi.microsoft.com/en-us/downloads/ 。在考虑生产就绪型 Power BI 服务时,请探索专业版和高级版选项。在第一章中,我简单地比较了专业版和高级版。Pro 的每用户许可费为 9.99 美元,Premium 的每用户许可费为 20 美元。在本练习中,使用了 Power BI Premium。请检查各种选项,并选择最适合您和您的组织的选项。

下载设备模拟器

设备模拟器用于模拟从设备发送到物联网集线器的异常情况。该模式使用温度和传感器 ID。然后,这些事件可以被配置为从该物联网中心读取的 Azure 流分析作业消费。从下面的 URL ( https://github.com/Azure/azure-stream-analytics/tree/master/Samples/DeviceSimulator )下载设备模拟器,然后打开相应的 Visual Studio 解决方案文件并运行模拟器。打开设备模拟器解决方案文件时,该文件应类似于图 16-11 。

img/511918_1_En_16_Fig11_HTML.jpg

图 16-11

设备模拟器项目的 VS 视图

当设备模拟器开始运行时,请注意各种可用的设置。请务必查看 readme.md GitHub 文件,以了解可用的各种配置和设置。例如,模拟模式是一种用模拟器和各种异常模式进行实验的方法,无需向实时物联网中心发送数据。

一旦您有了可用的物联网集线器名称空间(例如 rl-iothub-001)、设备 ID (ASAIoTDevice)和设备密钥(主键),在运行模拟器之前,在物联网集线器配置部分输入这些信息,如图 16-12 所示,以确保消息和数据被发送到物联网设备。

img/511918_1_En_16_Fig12_HTML.jpg

图 16-12

设备模拟器

创建流分析输入和输出

流分析作业由输入、查询和输出组成。需要对其进行定义和运行,以便获取物联网中枢设备输入,使用查询对其进行处理,并将其输出到 Power BI 实时流仪表板。

添加流输入

您的第一步是捕获输入。首先添加一个物联网集线器流输入,如图 16-13 所示。请注意,还有其他选项可以使用事件中心、Blob 存储和 ADLS gen 2——它们也是流输入。

img/511918_1_En_16_Fig13_HTML.jpg

图 16-13

添加物联网集线器流输入

接下来,图 16-14 显示了如何配置输入流细节。以下是高级配置选项的一些附加详细信息:

img/511918_1_En_16_Fig14_HTML.jpg

图 16-14

配置输入流详细信息

  • 消费群体:物联网枢纽将一个消费群体内的阅读器数量限制在 5 个。Microsoft 建议对每个作业使用单独的组。将此字段留空将使用' $Default '使用者组。

  • 共享访问策略名称:当您创建物联网集线器时,您也可以在物联网集线器设置中创建共享访问策略。每个共享访问策略都有一个名称、您设置的权限和访问密钥。

  • 共享访问策略键:当您创建物联网中心时,您也可以在物联网中心设置中创建共享访问策略。每个共享访问策略都有一个名称、您设置的权限和访问密钥。

  • 端点:对从设备到云的消息使用“消息”端点。将“操作监控”端点用于设备遥测和元数据。

  • 分区键:如果你的输入被一个属性分区,你可以在这里添加这个属性的名称。这是可选的,如果在该属性中包含 PARTITION BY 或 GROUP BY 子句,则用于提高查询的性能。如果此作业使用 1.2 或更高的兼容级别,则默认情况下会添加“PartitionId”,因此您无需在此处显式添加它。

  • 事件序列化格式:为了确保您的查询按照您期望的方式工作,Stream Analytics 需要知道您对传入的数据流使用哪种序列化格式。

  • 编码 : UTF-8 是目前唯一支持的编码格式。

  • 事件压缩类型:压缩选项使您能够指定压缩类型 Gzip、Deflate 或无压缩。

一旦指定了输入流的详细信息并获得了您想要的信息,请单击 Save 按钮。您将被带到如图 16-15 所示的屏幕,在这里您可以看到已经为您创建了物联网中心源流。

img/511918_1_En_16_Fig15_HTML.jpg

图 16-15

物联网中心源流

添加流输出

同样,也添加一个输出流,如图 16-16 所示。这将定义事件需要流向的接收器。请注意各种可用的接收器选项,包括 ADLS Gen2、SQL 数据库、Cosmos DB、Power BI 等等。在本练习中,选择 Power BI。

img/511918_1_En_16_Fig16_HTML.jpg

图 16-16

到 PBI 的物联网输出流

接下来,授权 Power BI 访问流分析作业,如图 16-17 所示。

img/511918_1_En_16_Fig17_HTML.jpg

图 16-17

授权 Power BI 访问 ASA

这将显示输入您的 Azure 门户凭据的提示,然后单击下一步,如图 16-18 所示。考虑使用服务帐户进行生产授权和身份验证,而不是简单地使用个人帐户。

img/511918_1_En_16_Fig18_HTML.jpg

图 16-18

登录到 Azure 门户网站

配置数据集和表,并将验证模式设置为“用户令牌”,因为这将在开发/演示模式下临时运行,如图 16-19 所示。

img/511918_1_En_16_Fig19_HTML.jpg

图 16-19

配置数据集和表,并设置身份验证模式

您还可以使用托管身份来认证您的 Azure 流分析作业,以支持 BI用于输出到 Power BI 的托管身份认证使流分析作业能够直接访问您的 Power BI 帐户中的工作区。该特性允许流分析作业的部署完全自动化,因为用户不再需要通过 Azure Portal 交互式登录 Power BI。此外,写入 Power BI 的长期运行的作业现在得到了更好的支持,因为您将不再需要定期重新授权作业( https://docs.microsoft.com/en-us/azure/stream-analytics/powerbi-output-managed-identity )

最后,图 16-20 显示 IoTPowerBIOutput 接收流已经创建。

img/511918_1_En_16_Fig20_HTML.jpg

图 16-20

IoTPowerBIOutput 接收器流

编写流分析查询

创建流分析作业的最后一步是为异常检测编写 SQL 查询。在这个场景中,让我们使用峰值和下降函数。Azure Stream Analytics 提供内置的基于机器学习的异常检测功能,可用于监控两种最常见的异常:暂时的和持久的。使用 AnomalyDetection _ SpikeAndDip 和 AnomalyDetection_ChangePoint 函数,您可以直接在流分析作业中执行异常检测。Azure Stream Analytics 中的异常检测采用基于机器学习的异常检测运算符,如 Spike 和 Dip 以及 Change Point。图 16-21 显示了在哪里添加包含内置异常检测峰值和下降函数的 SQL 查询。

img/511918_1_En_16_Fig21_HTML.png

图 16-21

异常检测的 ASA SQL 查询

这是用作图 16-21 所示的源流分析查询的代码。此源查询将获取传入的流事件,并对其应用 SQL 查询,其中包括添加别名、转换以及使用峰值和下降异常检测功能,该功能是流分析 SQL 查询功能的一部分:

WITH anomalydetectionstep AS
(
       SELECT eventenqueuedutctime
AS time,
              Cast(temperature AS FLOAT)
AS temp,
              anomalydetection_spikeanddip(Cast(temperature AS FLOAT), 95, 120, 'spikesanddips') OVER(limit duration(second, 120)) AS spikeanddipscores
       FROM   iothub )
SELECT time,
       temp,
       cast(getrecordpropertyvalue(spikeanddipscores, 'Score') AS float)       AS spikeanddipscore,
       cast(getrecordpropertyvalue(spikeanddipscores, 'IsAnomaly') AS bigint) AS isspikeanddipanomaly
INTO   iotpowerbioutput
FROM   anomalydetectionstep

启动流分析作业

创建成功的流分析作业的最后一步是启动作业。这将确保从物联网集线器设备接收事件,并实时传递给 Power BI 服务。配置完作业的所有必要组件后,启动流分析作业,如图 16-22 所示。请注意,有一个物联网集线器输入和一个电源 BI 输出。

img/511918_1_En_16_Fig22_HTML.jpg

图 16-22

从 Azure 门户启动 ASA 作业

开始作业时,系统会提示您设置作业输出开始时间,如图 16-23 所示。此作业将从特定数量的流单元开始。您可以在缩放部分下更改流单位。作业将默认为 3 个流单位。您可以将配置为在流分析提供的标准多租户环境或您拥有的专用流分析集群中运行此作业。该作业将默认为标准环境。作业可能需要提前读取输入数据,以确保结果的准确性。要恢复停止的作业而不丢失数据,请选择上次停止。请注意,如果您是第一次运行作业,此选项不可用。在本练习中,确保作业输出开始时间设置为“Now ”,然后单击“start”。

img/511918_1_En_16_Fig23_HTML.jpg

图 16-23

ASA 开始作业详细信息

一旦工作开始,注意“运行”状态,如图 16-24 所示。

img/511918_1_En_16_Fig24_HTML.jpg

图 16-24

处于运行状态的 ASA 作业

创建实时电源 BI 仪表板

一旦作业开始运行,就可以使用 Power BI 开始构建实时仪表板。在这个控制面板上,您将能够看到您的监控查询的结果。密切关注仪表板是您知道异常情况何时出现的方法。

创建数据集

首先导航到包含图 16-25 所示数据集部分中的 IoTPowerBIDataSet 的工作空间。请注意,流分析作业必须正在运行,并且必须为要创建的数据集处理了至少一个事件。

img/511918_1_En_16_Fig25_HTML.jpg

图 16-25

PBI 创建数据集

创建仪表板

验证数据集已创建后,还要创建一个新的仪表板,如图 16-26 所示。

img/511918_1_En_16_Fig26_HTML.jpg

图 16-26

PBI 创建了一个仪表板

为仪表板命名。在本练习中,它被称为 IoTPowerBIDashboard,如图 16-27 所示。

img/511918_1_En_16_Fig27_HTML.jpg

图 16-27

PBI 命名仪表板

添加单幅图块

图块是数据的快照,固定在仪表板上。可以从报表、数据集、仪表板等创建切片。仪表板和仪表板磁贴是 Power BI 服务的一项功能,而不是 Power BI Desktop 的功能,因此您需要确保启动并运行 Power BI 服务。为实时自定义流数据添加一个图块,如图 16-28 所示。

img/511918_1_En_16_Fig28_HTML.jpg

图 16-28

PBI 添加一个瓷砖

选择数据集,如图 16-29 所示。请注意,数据集是您导入或连接到的数据的集合。Power BI 允许您连接和导入各种数据集,并将它们集中在一个地方。数据集与工作空间相关联,单个数据集可以是许多工作空间的一部分。

img/511918_1_En_16_Fig29_HTML.jpg

图 16-29

PBI 添加了一个自定义的流数据块

卡片可视化是 Power BI 仪表板中唯一的数字,也是您需要在仪表板或报告中跟踪的最重要的东西。在本练习中,异常是需要跟踪的最重要的指标。添加卡片可视化以跟踪峰值和谷值异常的计数,如图 16-30 所示。

img/511918_1_En_16_Fig30_HTML.jpg

图 16-30

PBI 添加了一个卡片可视化

折线图是由点表示并由直线连接的一系列数据点。折线图可以有一条或多条线。折线图有一个 X 轴和一个 Y 轴。还要添加一个折线图可视化来跟踪峰值和谷值,如图 16-31 所示。

img/511918_1_En_16_Fig31_HTML.jpg

图 16-31

PBI 瓷砖详情

运行设备模拟器

现在回到设备模拟器,配置您在本章前几节中积累的物联网集线器详细信息。详细配置完成后,点击设备模拟器中的“更新物联网集线器配置”,如图 16-32 所示。

img/511918_1_En_16_Fig32_HTML.jpg

图 16-32

物联网集线器配置详细信息

选择正常事件的异常设置,如图 16-33 所示,启动装置模拟器。这将简单地启动模拟器,并开始生成一组正常的事件,这些事件将被传递到物联网中心和 Power BI 仪表板。

img/511918_1_En_16_Fig33_HTML.jpg

图 16-33

正常事件的设备模拟器异常设置

监控实时电源 BI 流

一旦设备启动,回到您的 Power BI 仪表板开始监控流。请注意图 16-34 中的流细节现在可以在 Power BI 仪表板上看到。还要注意 SpikeandDip 异常卡仍然为 0,因为我们目前只流式传输正常事件。

img/511918_1_En_16_Fig34_HTML.jpg

图 16-34

带有正常事件的 PBI 实时流仪表板

然后回到模拟器,将异常设置改为峰值/下降,每 2 秒重复一次。从图 16-35 中注意到模拟器中已经开始出现异常。

img/511918_1_En_16_Fig35_HTML.jpg

图 16-35

设备模拟器创建异常事件

回到实时功率 BI 仪表板后,请注意尖峰和下降异常已经开始流入仪表板,并且尖峰和下降异常卡开始显示进入的异常,如图 16-36 所示。

img/511918_1_En_16_Fig36_HTML.jpg

图 16-36

PBI 尖峰和倾斜异常

装置模拟器中还有一些额外的异常设置,可作为下一步探索,如液位变化和缓慢趋势,如图 16-37 所示。

img/511918_1_En_16_Fig37_HTML.jpg

图 16-37

设备模拟器中的 PBI 异常设置

一旦测试完成,确保你回到 Azure Portal 并停止流分析作业和设备模拟器,如图 16-38 所示。

img/511918_1_En_16_Fig38_HTML.jpg

图 16-38

停止流式作业

摘要

在本章中,我展示了一个实际的端到端示例,说明如何使用设备模拟器创建实时事件并将这些事件发送到物联网中心,该中心将收集这些事件,并使用 Azure Stream Analytics 的内置峰值和谷值异常检测功能进行下游异常检测。最后,您学习了如何使用 Power BI 将实时流数据可视化到仪表板中。您还了解了 Azure 中实时异常检测和报告的一些功能。

十七、使用 Apache Spark 的实时物联网分析

实时物联网分析、高级分析和实时机器学习洞察都是许多组织渴望推进其业务和目标的领域。Apache Spark 先进的 API 产品为大数据工作负载的高级流分析带来了许多机会。Apache Spark 提供的一个这样的 API 以结构化流为中心,支持大数据和实时高级分析功能。

如图 17-1 所示,Apache Spark 的结构化流适合整个 Databricks 统一数据分析平台,是一个基于 Spark SQL 引擎构建的流处理框架。一旦指定了计算以及源和目的地,结构化流引擎将随着新数据的可用而递增并连续地运行查询。结构化流将数据流视为一个表,并不断追加数据。在本章中,我将带您完成一个端到端的练习,使用一个设备模拟器来实现一个结构化的流解决方案,该模拟器将生成随机的设备数据,这些数据将被馈送到 Azure IoT Hub,并由 Apache Spark 通过 Databricks 笔记本进行处理,然后进入一个 Delta Lake 来持久存储数据。此外,我将向您展示如何定制结构化的流输出模式,比如 append vs. update vs. complete,并向您介绍代码中的触发器。

img/511918_1_En_17_Fig1_HTML.jpg

图 17-1

Apache Spark 的结构化流和 DeltaLake 框架

先决条件

作为本练习的基础,请确保您已经阅读并理解了第十六章,该章讨论了如何完成以下步骤:

  1. 安装并运行物联网设备模拟器 Visual Studio 解决方案文件。该设备模拟器将创建一个随机设备数据流,该数据流将被输入物联网中枢设备,并由 Spark 结构化流使用。

  2. 创建和配置物联网集线器设备。这项服务将弥合设备模拟器和 Spark 结构化流服务之间的鸿沟。

  3. 此外,Databricks 服务需要在 Azure Portal 中创建。Databricks 的 Spark 计算集群将用于结构化流处理。或者,Synapse Analytics 也可以用于这一过程。

创建物联网中心

一旦创建了物联网中心,并向该中心添加了物联网设备,则向物联网中心的内置端点部分添加一个新的消费群,如图 17-2 所示。应用使用消费者群体从物联网中心获取数据。因此,当您开始编写结构化流代码时,拥有一个可识别的别名将非常有用。

img/511918_1_En_17_Fig2_HTML.jpg

图 17-2

内置端点事件中心详细信息

创建数据块集群

接下来,需要创建一个 Databricks 集群。出于本练习的目的,使用图 17-3 所示的配置创建一个标准集群。

img/511918_1_En_17_Fig3_HTML.jpg

图 17-3

标准数据块集群

安装 Maven 库

在开始在 Databricks 笔记本中编写结构化流代码之前,还有一个设置和配置步骤。用下面列出的坐标安装一个 Maven 库。这些坐标取自 MvnRepository,可以通过以下网址找到: https://mvnrepository.com/artifact/com.microsoft.azure/azure-eventhubs-spark

在集群库配置界面输入 Maven 库中的坐标com.microsoft.azure:azure-eventhubs-spark_2.12:2.3.15,如图 17-4 所示。请注意,有各种库源选项可供选择和安装。对于这个场景,您将使用 Maven。或者,您还可以指定要排除的源存储库和依赖项。

img/511918_1_En_17_Fig4_HTML.jpg

图 17-4

安装 Databricks Maven 库

一旦选定的 Maven 库被安装到集群上,它将显示“已安装”状态,如图 17-5 所示。重新启动群集,以便在群集上正确安装库。

img/511918_1_En_17_Fig5_HTML.jpg

图 17-5

查看 Databricks 集群上安装的库

创建笔记本并运行结构化流查询

在下一节中,您将了解如何在 Databricks 笔记本中实现 Scala 代码,该笔记本将连接到您的物联网中心,并启动一个结构化的传入设备模拟器事件流。这些实时流事件将显示在您笔记本电脑的仪表板上,并保存在增量表中,以便为进一步的处理和转换准备数据。此外,您将了解触发器的概念以及如何在事件流处理代码中实现它们。

配置笔记本连接

现在,您已经准备好创建一个新的 Databricks 笔记本,如图 17-6 所示,并将安装了 Maven 库的标准集群附加到它上面。此外,使用 Scala 作为将在本 Databricks 笔记本中实现的代码的语言。

img/511918_1_En_17_Fig6_HTML.jpg

图 17-6

创建新的数据块笔记本

以下代码将使用 IoT Hub 连接详细信息构建连接字符串,并启动结构化流。在本节中,您将需要改进这个通用代码,它目前包括连接配置的占位符。在运行代码之前,替换以下示例中的物联网集线器连接。此外,记得根据 Azure Portal 中的 IoT Hub 中定义的内容来验证代码中的消费者组:

import org.apache.spark.eventhubs._
import org.apache.spark.eventhubs.{ ConnectionStringBuilder, EventHubsConf, EventPosition }
import org.apache.spark.sql.functions.{ explode, split }

// To connect to an Event Hub, EntityPath is required as part of the connection string.
// Here, we assume that the connection string from the Azure portal does not have the EntityPath part.
val connectionString = ConnectionStringBuilder("—Event Hub Compatible Endpoint--")
  .setEventHubName("—Event Hub Compatible Name--")
  .build
val eventHubsConf = EventHubsConf(connectionString)
  .setStartingPosition(EventPosition.fromEndOfStream)
  .setConsumerGroup("delta")

val eventhubs = spark.readStream
  .format("eventhubs")
  .options(eventHubsConf.toMap)
  .load()

在 Azure Portal 的物联网中心的内置端点部分,复制图 17-7 中所示的事件中心兼容名称,并将其替换在提供的代码块的—Event Hub Compatible Name--部分。

img/511918_1_En_17_Fig7_HTML.jpg

图 17-7

事件中心-内置端点中兼容的名称

接下来,复制图 17-8 所示的事件中枢兼容端点,并将其替换到代码块的—Event Hub Compatible Endpoint--部分。

img/511918_1_En_17_Fig8_HTML.jpg

图 17-8

事件中心–内置端点中兼容的端点

开始结构化流

本 Databricks 笔记本的第二部分将添加下面提供的代码,该代码旨在获取上一部分中定义的连接,读取流,然后将数据保存到增量表中。图 17-9 中的结果表明流已被成功读取。

img/511918_1_En_17_Fig9_HTML.jpg

图 17-9

用于读取和验证流细节的笔记本代码

接下来,运行以下代码来显示流的详细信息:

display(eventhubs)

图 17-10 显示流正在初始化。

img/511918_1_En_17_Fig10_HTML.jpg

图 17-10

正在初始化流

启动物联网设备模拟器

完成上一步后,前往设备模拟器,输入与集线器名称空间、设备 ID 和设备密钥相关的物联网集线器设备详细信息,然后运行设备模拟器。一旦设备产生事件,这些事件将开始出现在图 17-11 所示设备模拟器底部的折线图中。请注意,正常事件正在生成,因此事件数据在整个过程中相当一致。

img/511918_1_En_17_Fig11_HTML.jpg

图 17-11

设备模拟器详细信息

显示实时流数据

在导航回 Databricks 笔记本并展开display(eventhubs)代码块的仪表板部分后,请注意与输入相关的输入流的处理指标与处理速率、批处理持续时间和聚集状态,如图 17-12 所示。

img/511918_1_En_17_Fig12_HTML.jpg

图 17-12

显示流的处理度量的仪表板

导航至原始数据选项卡,注意数据流的结构和数据,如图 17-13 所示。

img/511918_1_En_17_Fig13_HTML.jpg

图 17-13

流的结构和数据

创建 Spark SQL 表

由于数据现在是流式的,因此通过在同一个 Databricks 笔记本中的新代码块中运行以下代码来创建一个 Spark SQL 表。请记住根据您的物联网设备数据定义列。在本练习中,使用设备模拟器中的列bodysequenceNumber:

import org.apache.spark.sql.types._
import org.apache.spark.sql.functions._
val schema = (new StructType)
    .add("body", DoubleType)
    .add("sequence_number", DoubleType)
val df = eventhubs.select(($"enqueuedTime").as("Enqueued_Time"),($"systemProperties.iothub-connection-device-id")
                  .as("Device_ID"),(from_json($"body".cast("string"), schema)
                  .as("telemetry_json"))).select("Enqueued_Time","Device_ID", "telemetry_json.*")

预期输出将显示spark.sqlDataFrame的结果,如图 17-14 所示。

img/511918_1_En_17_Fig14_HTML.jpg

图 17-14

spark.sqlDataFrame 的结果

运行以下代码,创建 Spark SQL 表来存储设备遥测数据:

df.createOrReplaceTempView("device_telemetry_data")

图 17-15 显示了该代码在 Databricks 笔记本中的执行结果。

img/511918_1_En_17_Fig15_HTML.jpg

图 17-15

创建 Spark SQL 表

将流写入增量表

将流写入增量表,并开始运行以下代码来定义最终数据帧:

val finalDF = spark.sql("Select Date(Enqueued_Time) Date_Enqueued, Hour(Enqueued_Time) Hour_Enqueued, Enqueued_Time, Device_ID, body AS Body,sequence_number as Sequence_Number from device_telemetry_data")

图 17-16 显示了 Databricks 笔记本中代码的执行结果。

img/511918_1_En_17_Fig16_HTML.jpg

图 17-16

定义最终数据帧的代码

将图 17-17 中所示的下一个代码块复制并粘贴到同一个 Databricks 笔记本中的一个新单元格中。这段代码将把流写入增量表。请注意,您可以定义分区、格式、检查点位置和输出模式。正在使用默认的检查点位置,该位置由 Databricks 定义和管理,但是您也可以轻松地自己定义该位置,并将数据保存到不同的文件夹中:

finalDF.writeStream
  .outputMode("append")
  .option("checkpointLocation", "/delta/events/_checkpoints/device_delta")
  .format("delta")
  .partitionBy("Date_Enqueued", "Hour_Enqueued")
  .table("delta_telemetry_data")

图 17-17 显示了 Databricks 笔记本中代码的执行结果。

img/511918_1_En_17_Fig17_HTML.jpg

图 17-17

将流写入增量表的代码

注意,在图 17-17 中,输出模式被设置为附加。支持以下输出模式:

  • 追加(仅向输出接收器添加新记录)

  • 更新(就地更新已更改的记录)

  • 完成(重写完整输出)

还可以将触发器添加到写入流中,以定义流数据的处理时间,以及该查询是作为具有固定批处理间隔的微批处理查询还是作为连续处理查询来执行。

这里有几个触发器的例子。Apache Spark 的文档包含更多关于触发器的细节,可以在下面的 URL 中找到: https://spark.apache.org/docs/2.3.0/structured-streaming-programming-guide.html#triggers

.trigger(Trigger.ProcessingTime("2 seconds"))
.trigger(Trigger.Once())
.trigger(Trigger.Continuous("1 second"))

请注意图 17-18 所示的原始数据选项卡,设备数据持续流入,您现在可以查看样本流数据及其结构。

img/511918_1_En_17_Fig18_HTML.jpg

图 17-18

显示设备数据持续流动的原始数据选项卡

最后,编写并执行图 17-19 所示的以下 SQL 查询,以检索结构化流数据正在写入的增量表。然后,该表可用于执行额外的高级分析和/或构建机器学习模型,以获得对物联网设备数据的更有价值的实时洞察:

%sql
SELECT *
FROM   delta_telemetry_data

图 17-19 显示了 Databricks 笔记本中代码的执行结果。

img/511918_1_En_17_Fig19_HTML.jpg

图 17-19

查询结构化流数据正在写入的增量表

摘要

在这一章中,我演示了如何使用设备模拟器实现结构化的流解决方案,该模拟器将随机设备数据生成到 Azure IoT Hub 中,由 Apache Spark 通过 Databricks 笔记本进行处理,并流入 Delta Lake 以持久存储数据。我还向您展示了如何定制结构化的流输出模式,包括追加、更新和完成。最后,我介绍了触发器的概念以及如何在您的 Databricks 笔记本代码中实现它们。

在 Databricks 中使用 Apache Spark 进行实时分析是流分析的替代方案,最适合大数据场景或数据非常非结构化的情况,需要 Databricks 中提供的一些高级功能,如模式进化等。它也非常适合将您的实时流与高级分析和机器学习工作流相集成。潜力是无限的,这一章仅仅触及了其中一些功能的表面。

十八、用于 Cosmos DB 的 Azure Synapse 链接

对存储在诸如 Cosmos DB 之类的事务系统中的数据进行近乎实时的洞察,是许多组织的长期目标和需求。Azure Synapse Link for Azure Cosmos DB 是一种云原生混合事务和分析处理(HTAP)功能,允许用户对 Azure Cosmos DB 中的运营数据进行近实时分析。数据工程师、业务分析师和数据科学家现在能够使用 Spark 或 SQL 池获得对其数据的近乎实时的洞察,而不会影响其在 Cosmos DB 中的事务性工作负载的性能。

Azure Synapse Link for Azure Cosmos DB 有许多优势,包括降低复杂性,因为接近实时的分析存储减少或消除了对复杂 ETL 或更改 feed 作业流程的需求。此外,对运营工作负载几乎没有影响,因为分析工作负载是独立于事务工作负载呈现的,不会消耗调配的运营吞吐量。此外,它还通过利用 Spark 和 SQL 按需池的功能,针对大规模分析工作负载进行了优化,由于具有高度弹性的 Azure Synapse 分析计算引擎,这使得它具有成本效益。Azure Synapse Link for Azure Cosmos DB 针对运营数据上的工作负载(包括聚合等)提供了一个面向列的分析存储,以及分析工作负载的解耦性能,支持对交易数据的自助式、近实时洞察,如图 18-1 所示。

img/511918_1_En_18_Fig1_HTML.png

图 18-1

Azure Synapse Link 的架构图

在本章中,您将通过实际的端到端练习了解如何实现以下目标:

  1. 创建一个支持分析存储的基本 Azure Cosmos DB 帐户。

  2. 在 Azure Synapse Analytics 中创建 Cosmos DB 链接服务。

  3. 使用 Synapse Workspace 笔记本中的 Spark 来聚合和查询 Cosmos DB 数据。

创建一个 Azure Cosmos DB 帐户

Azure Cosmos DB 是一个完全托管的 NoSQL 数据库服务,用于现代应用开发。你需要从 Azure Portal 创建一个 Azure Cosmos DB 帐户,如图 18-2 所示。

img/511918_1_En_18_Fig2_HTML.jpg

图 18-2

创建一个宇宙数据库

如图 18-3 所示,确保帐户详细信息配置正确,并创建 Azure Cosmos DB 帐户。

img/511918_1_En_18_Fig3_HTML.jpg

图 18-3

配置 Cosmos DB 帐户详细信息

概括地说,在本节中,您使用核心(SQL) API 创建了一个 Azure Cosmos DB 帐户。有许多 API 可供选择,包括 native Core (SQL) API、MongoDB API、Cassandra API、Gremlin API 和 Table API。此外,选择调配吞吐量作为容量模式,因为它最适合具有持续流量、需要可预测性能的工作负载,而无服务器最适合具有间歇或不可预测流量以及较低的平均峰值流量比的工作负载。有关容量模式的更多详情,请参见 https://docs.microsoft.com/en-us/azure/cosmos-db/throughput-serverless .

启用 Azure Synapse 链接

一旦创建了 Cosmos DB 帐户,您将需要启用 Azure Synapse 链接,默认设置为“关闭”这可以通过首先点击图 18-4 所示的 Azure Synapse 链接功能来实现。

img/511918_1_En_18_Fig4_HTML.jpg

图 18-4

为 Cosmos DB 启用 Synapse Link 的步骤

然后点击“启用”,如图 18-5 所示。

img/511918_1_En_18_Fig5_HTML.jpg

图 18-5

启用 Synapse 链接

图 18-6 显示一旦 Azure Synapse Link 被启用,状态将变为“开启”

img/511918_1_En_18_Fig6_HTML.jpg

图 18-6

Synapse 链接已打开

创建一个 Cosmos DB 容器和数据库

既然已经为 Azure Synapse Link 启用了 Azure Cosmos DB 帐户,那么就创建一个数据库和容器。首先,Cosmos DB 中的 Quick start 部分可以让您更轻松地选择平台、创建数据库和容器,然后开始使用 Cosmos DB 笔记本来运行代码以导入数据。

出于本练习的目的,请使用 Python 平台。然而,请注意可供选择的更多平台选项,如图 18-7 所示。

img/511918_1_En_18_Fig7_HTML.jpg

图 18-7

用 Python 创建新笔记本

图 18-8 显示了如何通过用户界面创建一个数据库和容器。还有一些选项可用于从一个新的笔记本或带有预定义代码的样本笔记本开始。

img/511918_1_En_18_Fig8_HTML.jpg

图 18-8

创建新的 Cosmos DB 容器

您需要配置数据库名称、吞吐量、容器名称和分区键,如图 18-9 所示。您总是可以从包含 400 RU/s 和 5 GB 存储的空闲层开始,然后相应地纵向扩展。

img/511918_1_En_18_Fig9_HTML.jpg

图 18-9

配置容器数据库 id 和吞吐量详细信息

最后,一定要记住设置分区键并打开分析存储器,如图 18-10 所示。分区键用于跨多个服务器自动分区数据,以实现可伸缩性。它是一个分析商店,允许您对数据进行实时分析。

img/511918_1_En_18_Fig10_HTML.jpg

图 18-10

配置剩余的容器详细信息

将数据导入 Azure Cosmos DB

既然您已经创建并配置了数据库和容器的细节,那么创建一个新的笔记本来将数据导入到 Cosmos 数据库容器中,如图 18-11 所示。

img/511918_1_En_18_Fig11_HTML.jpg

图 18-11

在 Cosmos DB 中添加新笔记本

首先读取您在上一步中创建的数据库和容器,如图 18-12 所示。 Azure Cosmos DB Python 示例 ( https://docs.microsoft.com/en-us/azure/cosmos-db/sql-api-python-samples )有额外的 API 引用命令,可以在笔记本代码中使用。请访问前面的 URL,了解有关为 Azure Cosmos DB 配置和使用 Azure Synapse Link 的更多信息,并查看其他代码片段,包括如何使用analytical_storage_ttl命令定义和更新分析存储生存时间。

img/511918_1_En_18_Fig12_HTML.jpg

图 18-12

创建或读取新的数据库和容器

下面是如图 18-12 所示的代码,用于读取您在上一节中创建的数据库和容器名称:

import azure.cosmos
from azure.cosmos.partition_key import PartitionKey

database = cosmos_client.get_database_client('RetailDemo')
print('Database RetailDemo Read')

container = database.get_container_client('WebsiteData')
print('Container WebsiteData Read')

一旦数据被读取,您可以通过使用图 18-13 所示的代码来更新容器的吞吐量,以允许更快的上传。

img/511918_1_En_18_Fig13_HTML.jpg

图 18-13

加载前扩大吞吐量

以下是图 18-13 中所示的代码,用于更新容器的吞吐量,以加快上传速度:

old_throughput = container.read_offer().offer_throughput
new_throughput = container.replace_throughput(1000).offer_throughput
print("Container WebsiteData's throughput updated from {} RU/s to {} RU/s".format(old_throughput, new_throughput))

接下来,使用图 18-14 所示的%%upload magic 函数将物品插入容器。

img/511918_1_En_18_Fig14_HTML.jpg

图 18-14

将数据加载到 Cosmos DB

下面是图 18-14 所示的代码,它使用%%upload 魔法函数将项目插入容器:

%%upload --databaseName RetailDemo --containerName WebsiteData --url https://cosmosnotebooksdata.blob.core.windows.net/notebookdata/websiteData.json

图 18-15 显示了一旦数据加载完成,如何通过编程降低容器的吞吐量。

img/511918_1_En_18_Fig15_HTML.jpg

图 18-15

加载完成后,缩减吞吐量

下面是图 18-15 所示的代码,用于在数据加载完成后按比例降低容器的吞吐量:

lowered_throughput = container.replace_throughput(400).offer_throughput
print("Container WebsiteData's throughput lowered from {} RU/s to {} RU/s".format(new_throughput, lowered_throughput))

在 Azure Synapse Analytics 中创建 Cosmos DB 链接服务

在 Cosmos DB 数据库容器中提供数据后,按照图 18-16 中所示的步骤,在 Azure Synapse Analytics 工作区中创建一个链接服务。

img/511918_1_En_18_Fig16_HTML.jpg

图 18-16

在 Synapse Analytics 中创建 Cosmos DB 链接

记得选择 Azure Cosmos DB (SQL API),如图 18-17 所示,因为这是 Azure Cosmos DB API 的配置。注意,还有一个 MongoDB API 选项。

img/511918_1_En_18_Fig17_HTML.jpg

图 18-17

创建到 Cosmos DB 的链接的步骤

填写图 18-18 中所示的所需连接配置细节,并创建新的链接服务。

img/511918_1_En_18_Fig18_HTML.jpg

图 18-18

创建新的链接服务

使用 Synapse Spark 加载和查询数据

从 Azure Synapse Analytics 创建一个新的链接到 Cosmos DB 的服务后,按照图 18-19 所示的步骤创建一个新的笔记本并将数据加载到数据框中。

img/511918_1_En_18_Fig19_HTML.jpg

图 18-19

将数据加载到数据框进行分析

我想说明支持分析存储的容器和不支持分析存储的容器之间的视觉差异。基本上,启用分析存储的容器将有额外的三行,代表分析工作负载的列存储,如图 18-20 所示。

img/511918_1_En_18_Fig20_HTML.jpg

图 18-20

启用非分析存储

创建链接服务后,运行以下代码,该代码将在数据加载到上一步中的数据框时自动创建。在运行代码之前,记得创建一个 Synapse Spark pool 并将其连接到笔记本:

# Read from Cosmos DB analytical store into a Spark DataFrame and display 10 rows from the DataFrame
# To select a preferred list of regions in a multi-region Cosmos DB account, add .option("spark.cosmos.preferredRegions", "<Region1>,<Region2>")

df = spark.read\
    .format("cosmos.olap")\
    .option("spark.synapse.linkedService", "LS_CosmosDb_RetailDemo")\
    .option("spark.cosmos.container", "WebsiteData")\
    .load()

display(df.limit(10))

请注意图 18-21 中的插图,代码运行成功,并使用了两个执行器和八个内核来完成任务。请注意,这可以进行定制,以适应您所需的工作负载。此外,可以在 Spark UI 中查看作业细节。

img/511918_1_En_18_Fig21_HTML.jpg

图 18-21

要加载到数据框的代码

图 18-22 显示了数据框中前十条记录的预览,这证实了实时查询功能处于活动状态。

img/511918_1_En_18_Fig22_HTML.jpg

图 18-22

返回的样本数据的图像

接下来,使用以下代码聚合数据集以获得价格列的总和,然后显示数据框:

from pyspark.sql.functions import *
df = df.agg(sum(col('Price')))

df.show()

在作业完成运行后,图 18-23 显示了操作性 Cosmos DB 数据上成功聚合的价格列,而无需利用任何定制的 ETL 过程。这展示了利用这种 Azure Synapse Link for Cosmos DB 功能的未来方法的能力,以使自助服务数据用户能够以接近实时的速度获得对其数据的洞察。

img/511918_1_En_18_Fig23_HTML.jpg

图 18-23

汇总价格数据

摘要

在本章中,我向您展示了如何创建一个支持分析存储的基本 Azure Cosmos DB 帐户,如何在 Azure Synapse Analytics 中创建一个 Cosmos DB 链接服务,以及如何使用 Synapse Workspace 笔记本中的 Spark 来聚合和查询 Cosmos DB 数据。

通过设置这一流程,您的组织能够从对事务性数据的实时分析中获得有价值的见解,这使得业务分析师、数据科学家、数据工程师和其他公民开发人员能够分析大型数据集,而不会影响事务性工作负载的性能。除了其他各种好处之外,这个过程减少了构建和管理复杂 ETL 作业的需要。