Hive SQL单元测试介绍

动机

Hive被广泛应用大数据领域。它经常用于大型数据集的临时查询和用于实现ETL类型的进程。与即席查询(Ad Hoc )不同,为ETL编写的Hive SQL具有一些不同的属性:

  • 通常按计划重复执行。
  • 它通常是一个庞大而复杂的代码体。
  • 更长的寿命,长期坚持组织的代码库。
  • 经常随着时间的推移对其进行修改
  • 对组织的运作至关重要,因为它可以生成有价值的数据。

展示此类属性的代码是单元测试覆盖的强有力候选者,因为它很容易出现错误,错误和意外破坏,所有这些都可能对组织构成风险。

挑战

Hive和Hive SQL都存在许多挑战,这使得构建基于Hive的ETL系统的单元测试变得困难。这些可以概括地描述如下:

  • 组件边界不清晰
  • 环境
  • 执行速度

模块化

通过模块化使用Hive实现的流程,它们变得更容易有效地测试并且更容易适应变化。尽管Hive提供了许多用于模块化的向量,但并不总是清楚如何分解大型过程。将查询逻辑封装到组件中的功能分为两个垂直问题:列级逻辑和设置级逻辑。列级逻辑是指应用于查询中各列或列组的表达式,通常称为“函数”。设置级别逻辑涉及操纵数据分组的Hive SQL构造,例如:列投影与 SELECTGROUP BY 聚合, JOIN s, ORDER BY 排序等。在任何一种情况下,我们都希望单个组件存在于自己的源文件或可部署artifact中并导入根据构图的需要。对于基于Hive SQL的组件, SOURCE 命令提供此功能。

列级逻辑的封装

在列级逻辑的情况下,Hive提供 UDFsmacros ,允许用户提取和重用应用于列的表达式。一旦定义,UDF和宏可以很容易地隔离进行测试。 UDF可以使用现有的Java / Python单元测试工具(如JUnit)进行简单测试,而宏需要Hive命令行界面来执行宏声明,然后使用一些示例 SELECT 语句来练习它。

设置级逻辑的封装

与列级逻辑不同,如何最好地封装和组合基于集合的逻辑集合是不太明显的。请考虑以下包含联接,分组和列投影的复杂查询示例:

SELECT ... FROM (                  -- Query 1
  SELECT ... FROM (                --  Query 2
    SELECT ... FROM (              --   Query 3
      SELECT ... FROM a WHERE ...  --    Query 4
    ) A LEFT JOIN (                --   Query 3
      SELECT ... FROM b            --    Query 5
    ) B ON (...)                   --   Query 3
  ) ab FULL OUTER JOIN (           --  Query 2
    SELECT ... FROM c WHERE ...    --   Query 6
  ) C ON (...)                     --  Query 2
) abc LEFT JOIN (                  -- Query 1
  SELECT ... FROM d WHERE ...      --  Query 7
) D ON (...)                       -- Query 1
GROUP BY ...;                      -- Query 1

此查询具有无法单独验证。它似乎实际上是由至少7个不同的查询组成的。为了有效地对这个过程进行单元测试,我们必须将每个子查询封装到单独的组件中,以便可以独立测试它们。为实现这一目标,我们可以采取多种方法,包括:

  • 使用中间表顺序执行组件。
  • 视图
  • 查询片段的变量替换。
  • SQL 函数/过程。

有限的测试表明,VIEW比使用具有中间表的组件的顺序执行更有效。中间表解决方案(包括 TEMPORARY 表)运行时间更长,生成更多I / O,并限制查询优化机会。VIEW似乎没有经常预言的性能问题。

变量替换也被建议作为模块化大型查询的方法,但是在检查时发现它不合适,因为需要额外的bash文件会使测试更复杂。还可考虑了HPL/SQL,但它没有查询模块化所需的必要流水线功能。

参考资料

工具和框架

简化测试声明和执行的框架是有帮助的。通常,这些工具允许指定以下许多方法:

  • 执行环境配置:通常为 hiveconfhivevar 参数。
  • 声明输入测试数据:创建或选择支持某些源表的文件。
  • 测试的可执行组件的定义:通常是测试中的SQL脚本。
  • 期望:这些可以是参考数据文件的形式,或者可以使用进一步的查询进行细粒度断言。

精确的细节当然是特定于框架的,但一般而言,工具通过将开发人员提供的工件组合成如下序列来管理测试的整个生命周期:

  • 配置Hive执行环境。
  • 设置测试输入数据。
  • 执行测试中的SQL脚本。
  • 提取执行脚本写入的数据。
  • 对提取的数据进行断言。

目前有许多具体方法可供选择:

  • HiveRunner :使用Java,Hive SQL和JUnit声明测试用例,并且可以在IDE中本地执行。该库侧重于易用性和执行速度。无需安装本地Hive / Hadoop。提供完整的测试隔离,细粒度断言和无缝UDF集成(它们只需要在项目类路径上)。 Metastore由内存数据库支持,以提高测试性能。

  • beetest :使用Hive SQL和“预期”数据文件声明测试用例。使用命令行上的脚本执行测试套件。显然需要在执行测试的环境中安装HDFS。

  • hive_test :使用Java,Hive SQL和JUnit声明测试用例,并且可以在IDE中本地执行。

  • HiveQLUnit: 在您喜欢的IDE中测试您的Hive脚本。使用Spark来执行测试。

  • How to utilise the Hive project’s internal test framework

有用的做法

以下Hive特定实践可用于使过程更适合单元测试,并有助于简化单个测试。

  • 将大型或复杂查询模块化为多个较小的组件。这些更容易理解,维护和测试。
  • 使用宏或UDF来封装重复或复杂的列表达式。
  • 使用 Hive variables 将SQL脚本与特定环境分离。例如,使用 LOCATION ${myTableLocation} 优先于 LOCATION /hard/coded/path 可能是明智之举。
  • 缩小测试范围。对表的整个内容进行粗略断言是脆弱的并且具有高维护要求。
  • 使用 SOURCE 命令组合多个较小的SQL脚本。
  • 通过创建简单的测试表并将函数应用于这些表中的列来测试宏和UDF的集成。
  • 通过在标准测试框架(如JUnit)中直接调用生命周期方法( initializeevaluate 等)来测试UDF。

相关问题

  • HIVE-12703 :CLI不可知的HQL导入命令实现

其他Hive单元测试问题

虽然没有与Hive SQL特别相关,但是存在用于测试Hive其他方面的工具生态系统。特别是 BeeJU 项目提供了JUnit规则,以简化与Hive Metastore和HiveServer2服务的集成测试。如果您正在开发旨在利用Hive元数据功能的替代数据处理框架或工具,这些都很有用。

    原文作者:python人工智能命理
    原文地址: https://www.jianshu.com/p/2c7631ab6cea
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞