云服务器价格_云数据库_云主机【优惠】最新活动-搜集站云资讯

轻量服务器_天翼云桌面下载_怎么买

小七 141 0

使用SQL中的高阶函数处理嵌套数据

在数据块上查看此笔记本嵌套数据类型为Databricks客户和apachespark用户提供了操作结构化数据的强大方法。特别是,它们允许您将数组、映射和结构等复杂对象放入列中。这可以帮助您以更自然的方式建模数据。虽然这个特性确实很有用,但是在复杂对象内部操作数据可能有点麻烦,因为SQL(和Spark)没有处理此类数据的原语。此外,它是耗时的,非性能的,非琐碎的。基于这些原因,我们很高兴在Databricks Runtime 3.0版本中提供更高阶的SQL函数,允许用户在SQL中高效地创建函数来操作基于数组的数据。高阶函数是SQL的一个简单扩展,用于操作嵌套数据(如数组)。例如,下面的转换表达式显示了如何向数组中的每个元素添加数字:在这篇文章中,我们将介绍以前在SQL中进行嵌套数据操作的方法,然后介绍在Databricks中引入的高阶函数语法。过去的方法在介绍数组操作的新语法之前,让我们首先讨论在SQL中操作这类数据的当前方法:内置功能(功能有限)将数组解压成单独的行,应用您的函数,然后将它们重新打包到一个数组中(步骤很多,因此效率低下)自定义项(非通用或高效)我们将独立地研究每一个,以便您能够理解为什么数组操作很困难。让我们从一个具有下面模式的表开始(请参阅随附的笔记本以获取易于运行的代码)。根|--键:long(可为null=false)|--值:数组(可为null=false)||——元素:整数(containsAll=true)|--嵌套的_值:数组(null=false)||——元素:数组(containsAll=false)|| |——元素:整数(containsAll=true)内置函数sparksql确实有一些用于操作数组的内置函数。例如,可以创建一个数组,获取其大小,获取特定元素,检查数组是否包含对象,并对数组进行排序。sparksql还支持生成器(explode、pos_explode和inline),允许您将输入行与数组元素以及collect_list聚合结合起来。此功能可能满足某些任务的需要,但执行任何非琐碎的操作都很复杂,例如计算每个数组元素的自定义表达式。拆包并重新包装非平凡操作的常见方法是"解包并重新打包"方法。这是一种解决问题的"sparksql原生"方法,因为您不必编写任何自定义代码;您只需编写SQL代码。解包和重新包装方法通过应用以下步骤工作:使用侧视图分解将数组展平,并将输入行与数组中的每个元素组合起来;对分解数组中的每个元素应用给定的转换(在本例中为值+1);以及使用collect_list或collect_set创建新数组。我们可以在下面的SQL代码中看到这样一个示例:选择键,价值观,收集_列表(值+1)作为值加上1从嵌套的数据侧视图分解(值)T作为值按键分组,价值观虽然这种方法确实有效,但也有一些问题。首先,必须绝对确保用于分组的键是唯一的,否则最终结果将不正确。第二,sparksql中没有保证的数组顺序。指定一个需要特定顺序的操作几乎可以保证不正确的结果。用户定义函数(UDF)最后,我们可以编写定制的udf来操作数组数据。我们的udf必须定义如何遍历数组以及如何处理单个元素。让我们看看Python和Scala中的一些基本示例。蟒蛇斯卡拉从pyspark.sql.types导入IntegerType从pyspark.sql.types导入ArrayTypedef将"一个"添加到"元素":return[el+1表示元素中的el]spark.udf.register("plusOneIntPython",将\u one_添加到\u els,ArrayType(IntegerType()))def addOneToElements(元素:Seq[Int])=元素.map(元素=>元素+1)spark.udf.register("plusOneInt",addOneToElements(:Seq[Int]):Seq[Int])一旦注册,我们就可以使用这些函数来操作sparksql中的数据。选择键,价值观,plusOneInt(values)作为值加1,plusOneIntPython(值)作为值从嵌套的数据与以前的版本相比,这种方法有一些优点:例如,它维护元素顺序,不同于pack和repack方法。然而,它有两个主要缺点。首先,必须用SQL以外的语言编写函数,并在运行前注册它们。第二,将数据序列化到Scala和Python可能非常昂贵,这会使udf慢于Spark的SQL优化内置处理。我们的方法:高阶函数从上面的例子中可以看出,在SQL中操作嵌套数据的传统方法很麻烦。为此,我们在Databricks中构建了一个简单的解决方案:SQL中的高阶函数。在本笔记本中运行以下示例。我们的解决方案为SQL引入了两种函数编程结构:高阶函数和匿名(lambda)函数。它们一起工作,允许您定义在SQL中操作数组的函数。更高阶的函数,如TRANSFORM,从用户那里获取一个数组和一个lambda函数在上面运行。然后对数组中的每个元素调用这个lambda函数。一个简单的例子:变换让我们用前面例子中的转换来说明前面的概念。在本例中,高阶函数TRANSFORM将遍历数组,将关联的lambda函数应用于每个元素,并创建一个新数组。lambda函数element+1指定如何操作每个元素。选择键,价值观,转换(值,值->值+1)为值加1从嵌套的数据要非常清楚,转换转换(值,值->值+1)有两个组件:TRANSFORM(values..)是高阶函数。它以一个数组和一个匿名函数作为输入。内部转换将负责设置一个新数组,对每个元素应用匿名函数,并将结果分配给输出数组。value->value+1是一个匿名函数。函数分为两个部分,用->符号分隔:a、 参数列表。在本例中,我们只有一个参数:value。我们还通过创建一个逗号分隔的参数列表来支持多个参数,例如:(x,y)->x+y。b、 尸体。这是一个表达式,可以使用参数和外部变量来计算新值。在本例中,我们向value参数添加1。捕获变量我们也可以使用lambda函数中参数以外的其他变量;这称为捕获。我们可以使用在顶层定义的变量,或者在中间lambda函数中定义的变量。例如,以下转换将key(顶层)变量添加到values数组中的每个元素:选择键,价值观,转换(值,值->值+键)为值+键从嵌套的数据嵌套调用有时数据嵌套得很深。如果要转换这些数据,可以使用嵌套lambda函数。以下示例转换整数数组的数组,并将键(顶层)列和中间数组的大小添加到嵌套数组中的每个元素。选择键,嵌套的_值,转换(嵌套的_值,值->转换(值,value->value+key+SIZE(values)))作为新的\u嵌套的_值从嵌套的数据支持的功能我们在Databricks运行时的3.0版本中添加了以下高阶函数。变换(数组,函数):数组这通过对输入数组的每个元素应用函数来生成数组。注意,函数编程的等价操作是map。为了防止与映射表达式(从键值表达式创建映射)混淆,将其命名为transform。以下查询通过向每个元素添加键值来转换值数组:选择键,价值观,转换(值,值->值+键)转换后的值从嵌套的数据存在(数组,函数):布尔值如果谓词函数对输入数组中的任何元素有效,则返回true。以下示例检查values数组是否包含模10等于1的元素:选择键,价值观,存在(值,值->值%10==1)筛选的_值从嵌套的数据过滤器(array,function):array通过只添加谓词函数保存的元素,从输入数组生成输出数组。以下示例过滤值数组仅允许值大于50的元素:选择键,价值观,过滤(值,值->值>50)过滤的_值从嵌套的数据聚合(数组,B,函数,函数):R通过使用函数将数组元素合并到缓冲区B中,并在最终缓冲区上应用finish函数,将数组的元素减少为一个值R。初始值B由零表达式确定。finalize函数是可选的,如果不指定finalize函数,则使用identity函数(id->id)。这是唯一接受两个lambda函数的高阶函数。下面的示例将values数组相加(聚合)为一个(sum)值。显示了带有finalize函数(summated_values)和没有finalize函数summated_values_simple的版本:选择键,价值观,减少(values,0,(value,acc)->value+acc,acc->acc)合计值,减少(值,0,(value,acc)->value+acc)总和的值从嵌套的数据你呢