公司博客上

处理嵌套数据使用高阶函数在SQL数据砖

分享这篇文章

把这个笔记本砖

嵌套数据类型提供砖客户和Apache引发用户的强大处理结构化数据的方法。特别是,他们允许你把复杂的对象和数组一样,地图和内部结构的列。这可以帮助你模型数据在一个更自然的方式。虽然这个功能肯定是有用的,但它会很麻烦操纵数据的内部复杂的对象,因为SQL(火花)没有原语来处理这些数据。此外,它是耗时的,non-performant和非平凡的。

由于这些原因,我们兴奋地提供高阶函数的SQL砖运行时的3.0版本,允许用户高效地创建函数,在SQL操作基于数组的数据。高阶函数是一个简单的扩展SQL操作嵌套数组等数据。例如,变换下面表达式显示了如何添加一个数字数组中每个元素:

在这篇文章中,我们将讨论以前的方法嵌套SQL数据操作,其次是高阶函数语法我们已经介绍了砖。

过去的方法

在我们介绍数组操作的新语法之前,让我们首先讨论当前操作这类数据在SQL方法:

  • 内置函数(有限的功能)
  • 解压缩数组为单个行,应用你的函数,然后重新打包成数组(很多步骤,因此效率低下)
  • udf(不是一般的或有效)

我们将探讨这些独立,这样你可以理解为什么数组操作是很困难的。让我们开始下面的表的模式(包括看到笔记本容易运行的代码)。

| - - -关键:长(可空=)|——价值观:数组(可空=)| |——元素:整数(containsNull =真正的)|——nested_values:数组(可空=)| |——元素:数组(containsNull =)| | |——元素:整数(containsNull =真正的)

内置函数

火花SQL确实有一些内置函数用于操作数组。例如,您可以创建一个数组,它的大小,得到特定元素,检查如果数组包含一个对象,数组进行排序。SQL还支持发电机(火花爆炸,pos_explode内联),允许您将输入行数组元素,和collect_list聚合。这个功能可以满足您的需要对某些任务,但它是复杂的做任何事不平凡的,如计算每个数组元素的一个定制的表达。

解包和重新打包

非平凡的操作的常用的方法是“打开和重新打包”方法。这是一个“火花SQL原生”的方式解决问题,因为你不需要编写任何自定义代码;您可以简单地编写SQL代码。打开和重新打包方式是通过以下步骤:

  1. 使用侧面图爆炸平数组,输入行与数组中的每个元素相结合;
  2. 应用一个给定的变换,在这个例子中值+ 1爆炸数组中的每个元素;和
  3. 使用collect_listcollect_set创建一个新的数组。

我们可以看到一个这样的例子在SQL代码如下:

选择键,,collect_list (价值+1)作为values_plus_onenested_data横向视图爆炸()T作为价值集团通过键,

虽然这种方法肯定奏效,它有一些问题。首先,你必须绝对确保密钥用于分组是独一无二的,否则结果将是不正确的。第二,没有保证排序数组的火花SQL。指定一个操作,需要一个特定的顺序几乎保证不正确的结果。最后,生成的火花SQL计划可能会非常昂贵。

用户定义的函数(udf)

最后,我们可以编写自定义udf来操作数组的数据。udf必须定义如何遍历一个数组,我们如何处理单个元素。让我们看看一些基本例子在Python和Scala。

(code_tabs)

pyspark.sql.types进口IntegerTypepyspark.sql.types进口ArrayTypedefadd_one_to_els(元素):返回[el +1埃尔元素)spark.udf.register (“plusOneIntPython”、add_one_to_els ArrayType (IntegerType ()))
defaddOneToElements(元素:Seq [Int])=元素地图(= >元素+1)火花udf注册(“plusOneInt”addOneToElements (_:Seq [Int]):Seq [Int])

[/ code_tabs]

一旦注册,我们可以使用这些函数来操纵我们的数据在火花SQL。

选择键,,plusOneInt ()作为values_plus_one,plusOneIntPython ()作为values_plus_one_pynested_data

这种方法有一些优势在过去的版本:例如,它维护元素顺序,与包装和重新打包方法。然而,它有两个主要缺点。首先,你必须编写函数在其他语言比SQL和注册之前运行。第二,数据序列化到Scala和Python可以非常昂贵,减缓udf火花的SQL内置的优化处理

我们的方法:高阶函数

从上面的例子中,观察到传统的方式在SQL繁琐操作嵌套数据。为此,我们建立了一个简单的解决方案在砖:高阶函数的SQL。

运行下面的例子在这个笔记本上。

我们的解决方案引入了两个SQL函数编程结构:高阶函数和匿名(λ)函数。这些共同允许您定义的函数操作数组在SQL。的高阶函数,如变换,和一个数组lambda函数从用户运行。然后调用这个lambda函数数组中的每个元素。

一个简单的例子:变换

让我们说明前面的概念与我们之前的转换的例子。在这种情况下,高阶函数,变换将遍历该数组,相关的lambda函数适用于每一个元素,并创建一个新数组。lambda函数,元素+ 1,指定每个元素是如何被操纵的。

选择键,,变换(,价值- - - - - ->价值+1)作为values_plus_onenested_data

清晰的说明,转换变换(价值观、价值- >价值+ 1)有两个组件:

  1. 变换值. .)是高阶函数。这需要一个数组和一个匿名函数作为输入。内部变换将照顾设置一个新数组,每个元素应用匿名函数,分配结果输出数组。
  2. 值- >值+ 1是一个匿名函数。的功能分为两个组件分离- >符号:
    一个。参数列表。在这种情况下,我们只有一个论点:价值。我们也支持多个参数通过创建一个逗号分隔的参数列表包围括号,例如:(x, y) - > x + y
    b。身体。这是一个表达式,可以使用参数和外部变量计算新值。在这种情况下,我们的值加1的论点。

捕获变量

我们还可以使用其他比lambda函数中的参数变量;这就是所谓的捕捉。我们可以用变量定义在顶层,或在中间lambda函数定义的变量。例如,下面的改变增加了关键(顶级)变量值数组中的每个元素:

选择键,,变换(,价值- - - - - ->价值+键)作为values_plus_keynested_data

嵌套调用

有时数据是深度嵌套。如果你想改变这样的数据,你可以可以使用嵌套的lambda函数。下面的例子将整数数组,数组并添加关键(顶级)列和中间数组的大小嵌套数组中的每个元素。

选择键,nested_values,变换(nested_values- - - - - ->变换(,价值- - - - - ->价值+关键+大小()))作为new_nested_valuesnested_data

支持功能

我们有下面的高阶函数添加到3.0版本的砖运行时

变换(数组 、功能 ):数组

这产生一个数组通过应用函数一个输入的每个元素数组

注意,函数式编程操作映射。这已经被转换为了防止混乱的地图表达(从一个键值表达式创建一个地图)。

下面的查询转换的值数组每个元素通过添加键值:

选择键,,变换(,价值- - - - - ->价值+键)transformed_valuesnested_data

存在(数组 、功能 ):布尔

返回true,如果谓词函数适用于任何元素输入数组

下面的示例检查数组包含一个元素的值模10 = 1:

选择键,,存在(,价值- - - - - ->价值%10==1)filtered_valuesnested_data

过滤器(数组 、功能 ):数组

生成一个输出数组从输入数组只有只有谓词添加元素函数成立。

下面的例子过滤器与一个值只数组元素的值> 50允许:

选择键,,过滤器(,价值- - - - - ->价值>50)filtered_valuesnested_data

总(数组 B函数、功能R):

减少的元素数组成一个单一的值R通过合并元素到一个缓冲区B使用函数并通过应用finish函数在最后一个缓冲区。初始值B是由一个零的表达式。完成的功能是可选的,如果你不指定函数确定函数恒等函数(id - > id)使用。

这是唯一的高阶函数,取两个lambda函数。

下面的例子总结(骨料)数组的值到一个(总和)值。两个版本完成函数(summed_values)和一个没有完成的功能summed_values_simple显示:

选择键,,减少(,0,(价值,acc)- - - - - ->价值+acc, acc- - - - - ->acc) summed_values,减少(,0,(价值,acc)- - - - - ->价值+acc) summed_values_simplenested_data

你也可以计算更复杂的聚合。下面的代码显示了计算几何平均数的数组元素。

选择键,,聚合(,(1.0作为产品,0作为N),(缓冲区,价值)- - - - - ->(价值*缓冲区。产品,buffer.N+1),缓冲- - - - - ->权力(buffer.product1.0/buffer.N) geomeannested_data

结论

高阶函数将可用砖3.0运行时。如果你有任何嵌套的数据,一定要试一试!

这项工作增加了初始支持使用高阶函数嵌套数组数据。额外的功能和支持地图数据已经在路上了。一定要检查出砖的博客文档

免费试着砖

相关的帖子

看到所有公司博客上的帖子