我有以下爆炸查询,工作正常:
data1 = sqlContext.sql("select explode(names) as name from data")
我想要爆炸另一个字段“颜色”,因此最终输出可能是名称和颜色的笛卡尔积。所以我做了:
data1 = sqlContext.sql("select explode(names) as name, explode(colors) as color from data")
但我得到了错误:
Only one generator allowed per select but Generate and and Explode found.;
有人有任何想法吗?
我实际上可以通过两个步骤来实现它:
data1 = sqlContext.sql("select explode(names) as name from data")
data1.registerTempTable('data1')
data1 = sqlContext.sql("select explode(colors) as color from data1")
但我想知道是否有可能一步到位?非常感谢!
答案 0 :(得分:20)
正确的语法是
select name, color
from data
lateral view explode(names) exploded_names as name
lateral view explode(colors) exploded_colors as color
Rashid的答案不起作用的原因是它没有“命名”LATERAL VIEW
生成的表格。
以这种方式思考:LATERAL VIEW
的工作方式类似于隐式JOIN
,并为来自“已查看”的集合中的structs
的每一行创建一个临时表。因此,解析语法的方法是:
LATERAL VIEW table_generation_function(collection_column) table_name AS col1, ...
如果您使用表生成函数,例如posexplode()
,那么您仍然有一个输出表,但有多个输出列:
LATERAL VIEW posexplode(orders) exploded_orders AS order_number, order
您还可以通过反复展开嵌套集合来“嵌套”LATERAL VIEW
,例如,
LATERAL VIEW posexplode(orders) exploded_orders AS order_number, order
LATERAL VIEW posexplode(order.items) exploded_items AS item_number, item
虽然我们讨论LATERAL VIEW
的主题,但重要的是要注意通过SparkSQL使用它比通过DataFrame
DSL使用它更有效,例如myDF.explode()
。原因是SQL可以准确地推断出模式,而DSL API必须在语言类型和数据帧行之间执行类型转换。但是,在性能方面,DSL API会失败,因为您可以从explode
返回任何支持的类型,从而获得灵活性,这意味着您可以在一个步骤中执行更复杂的转换。
答案 1 :(得分:2)
尝试侧视图爆炸。
select name, color from data lateral view explode(names) as name lateral view explode(colors) as color;
答案 2 :(得分:0)
spark sql中不允许多次爆炸,因为它太混乱了。这是因为你得到了你正在爆炸的两件事的隐含笛卡尔积。如果你想做多个爆炸,你必须使用更多 比一个选择。 Hive有一个侧视图,可以达到你所需要的(Rashid Ali在他的回答中解释)。我个人会推荐两个带有数据帧的选择,因为它在spark方面效率很高。现在假设'data'是一个数据框。
val data1 = data.select($"id",$"names",$explode($"colors").alias("colors"))
//select required columns from colors
.select($"id",$"colors.field1",explode($"names").alias("names"))
//now select required cols from names
.select($"id",$"field1",$"names.col1",$"names.col2")
你可以在多个数据帧中或在上面的单个数据帧中进行上述选择,但它对性能没有任何影响。
答案 3 :(得分:0)
有一种简单的方法可以使df.withColumn
在多列上爆炸。
scala> val data = spark.sparkContext.parallelize(Seq((Array("Alice", "Bob"), Array("Red", "Green", "Blue"))))
.toDF("names", "colors")
data: org.apache.spark.sql.DataFrame = [names: array<string>, colors: array<string>]
scala> data.show
+------------+------------------+
| names| colors|
+------------+------------------+
|[Alice, Bob]|[Red, Green, Blue]|
+------------+------------------+
scala> data.withColumn("name", explode('names))
.withColumn("color", explode('colors))
.show
+------------+------------------+-----+-----+
| names| colors| name|color|
+------------+------------------+-----+-----+
|[Alice, Bob]|[Red, Green, Blue]|Alice| Red|
|[Alice, Bob]|[Red, Green, Blue]|Alice|Green|
|[Alice, Bob]|[Red, Green, Blue]|Alice| Blue|
|[Alice, Bob]|[Red, Green, Blue]| Bob| Red|
|[Alice, Bob]|[Red, Green, Blue]| Bob|Green|
|[Alice, Bob]|[Red, Green, Blue]| Bob| Blue|
+------------+------------------+-----+-----+