Spark 的数组/映射字段的“爆炸”如何是 SELECT 操作?

How is Spark's "exploding" of array/map fields a SELECT operation?

提问人:user2153235 提问时间:10/3/2023 最后编辑:user2153235 更新时间:10/5/2023 访问量:78

问:

我是 Python a Spark 的新手,目前正在解决这个问题 有关 Spark 对 DataFrame 的数组/映射字段的操作的教程。explode

基于第一部分 1(PySpark 分解数组或映射 列到行),非常直观。最小工作示例 DataFrame 在下面的附件中创建。架构和 DataFrame 表是:

>>> df.printSchema()
root
 |-- name: string (nullable = true)
 |-- knownLanguages: array (nullable = true)
 |    |-- element: string (containsNull = true)
 |-- properties: map (nullable = true)
 |    |-- key: string
 |    |-- value: string (valueContainsNull = true)

>>> df.show(truncate=False)
+----------+-------------------+-----------------------------+
|name      |knownLanguages     |properties                   |
+----------+-------------------+-----------------------------+
|James     |[Java, Scala]      |{eye -> brown, hair -> black}|
|Michael   |[Spark, Java, null]|{eye -> null, hair -> brown} |
|Robert    |[CSharp, ]         |{eye -> , hair -> red}       |
|Washington|null               |null                         |
|Jefferson |[1, 2]             |{}                           |
+----------+-------------------+-----------------------------+

该功能如下图所示:explode

>>> df \
... .select(df.name,explode(df.knownLanguages)) \
... .show()
+---------+------+
|name     |col   |
+---------+------+
|James    |Java  |
|James    |Scala |
|Michael  |Spark |
|Michael  |Java  |
|Michael  |null  |
|Robert   |CSharp|
|Robert   |      |
|Jefferson|1     |
|Jefferson|2     |
+---------+------+

该函数显示在 SELECT 查询的上下文中, 但是,我发现这非常不直观。SELECT 修剪掉行 并且从不增加数据框的高度。仅联接 可能会增加高度,但即使在那里,行的过滤也是 应用于笛卡尔连接 [1],因此仍然是 高度而不是增加。如果我错了,请纠正我,但是 上面的 SELECT 未应用于联接,因为它是作为 的方法。explodeDataFramedf

我试图更好地了解如何通过后者的 SELECT doc string: “投影一组表达式并返回一个新的 :class:“。投影是指选择列 表达式。我没有成功 试图深入了解上述代码如何适合 SELECTion 通过检查其内容:explodeDataFrameexplode

explode(df.knownLanguages) # Shows no columnar data
Out[114]: Column<'explode(knownLanguages)'>

后来,我发现无法检查列式数据 对象的内容,如此所述。Column

原型返回一个对象,而 doc string 说它“为给定的每个元素返回一个新行 数组或映射”。很难想象这样的专栏,因为没有 “给定数组或映射” -- 异构数组/映射的数量与 中有记录。explodeColumnDataFramedf

即使我们接受该对象包含这样的 列式数据,它是 有必要描绘这样一个专栏在概念上会是什么样子 为了了解 SELECT 的意义。 我想不出这样一列有意义的数据 SELECT 查询,因为无论列如何构造,它都将是 的高度与 不同。ColumnexplodeDataFramedf

得出 explode() 不会产生任何列的结论是否正确 适合 SELECT 的投影/选择操作的表达式 作为应用的 DataFrame df,它只是 select() 方法的一个信号,通过复制每个 按 $n_i$ 次记录 $i$,其中 $n_i$ 是 记录的数组/映射?

我刚刚开始找到可能绕过 Spark 的方法。但是,我预计,如果破坏了 SELECT 的预测/选择模型,则可能很难根据设计行为的知识来制作比教程中更复杂的查询。explode()

笔记

[1] SELECT过滤了笛卡尔连接的概念,当然, 不在执行中。这反映在早期 SQL 使用的事实中 WHERE 代替 ON。所有 WHERE 子句都是(概念上) 应用于笛卡尔连接。

附件:创建最小工作示例 DataFrame 表

import pyspark
from pyspark.sql import SparkSession
spark = SparkSession.builder.appName('pyspark-by-examples').getOrCreate()

arrayData = [
        ('James',['Java','Scala'],{'hair':'black','eye':'brown'}),
        ('Michael',['Spark','Java',None],{'hair':'brown','eye':None}),
        ('Robert',['CSharp',''],{'hair':'red','eye':''}),
        ('Washington',None,None),
        ('Jefferson',['1','2'],{})
]

df = spark.createDataFrame(data=arrayData, schema = ['name','knownLanguages','properties'])
apache-spark pyspark 爆炸

评论

0赞 samkart 10/4/2023
explode不是 select 操作,而是返回新列的列操作。如 doc - 中所示。您可以在 中使用它。所有这些都是投影,因为生成了新列。pyspark.sql.functions.explode(col: ColumnOrName) → pyspark.sql.column.ColumnwithColumn
0赞 user2153235 10/5/2023
@samkart:我认为投影是在 $n 维空间中获取一组点,并将它们压缩到一个由一些 $n 维表示的子空间中,但不是全部。例如,在 3D 空间中获取一组轴为 $x、y、$ 和 $z$ 的点,并通过放置 $z$ 坐标将它们展平到 $xy$ 平面上。当您从关系数据表中选择某些列时,就会发生这种情况(请参阅此处)。当您说“所有这些都是一个投影”时,它所应用的关系数据表是什么?
0赞 user2153235 10/5/2023
似乎 SELECT 投影应用于 DataFrame,因为它被调用为其方法,但这不可能是正确的,因为该列甚至与 的高度不匹配。关系代数中的 SELECT 运算指定单个关系数据表中的列,并且仅当列高度相同时才有意义。即使从 JOIN 中进行选择,SELECTion 也是从 JOIN 生成的单个表中完成的。DataFrame.select() 方法被描述为投影,因此这个投影概念仍然适用。dfexplode()df
0赞 samkart 10/5/2023
DataFrame的方法可以在一定程度上为您提供帮助。尝试一下explain()
0赞 samkart 10/5/2023
我相信你在这里想多了。这里的“投影”是指选择列(或投影具有很少或更多列的数据帧)。我不相信它与代数有任何关系。

答: 暂无答案