使用Spark 1.5.0并给出以下代码,我希望unionAll基于其列名联合DataFrame
。在代码中,我使用一些FunSuite传递SparkContext sc
:
object Entities {
case class A (a: Int, b: Int)
case class B (b: Int, a: Int)
val as = Seq(
A(1,3),
A(2,4)
)
val bs = Seq(
B(5,3),
B(6,4)
)
}
class UnsortedTestSuite extends SparkFunSuite {
configuredUnitTest("The truth test.") { sc =>
val sqlContext = new SQLContext(sc)
import sqlContext.implicits._
val aDF = sc.parallelize(Entities.as, 4).toDF
val bDF = sc.parallelize(Entities.bs, 4).toDF
aDF.show()
bDF.show()
aDF.unionAll(bDF).show
}
}
输出:
+---+---+
| a| b|
+---+---+
| 1| 3|
| 2| 4|
+---+---+
+---+---+
| b| a|
+---+---+
| 5| 3|
| 6| 4|
+---+---+
+---+---+
| a| b|
+---+---+
| 1| 3|
| 2| 4|
| 5| 3|
| 6| 4|
+---+---+
为什么结果包含混合" b"和"" 列,而不是根据列名对齐列?听起来像一个严重的错误!?
答案 0 :(得分:36)
它根本不像一个bug。您看到的是标准SQL行为,并且每个主要RDMBS(包括PostgreSQL,MySQL,Oracle和MS SQL的行为完全相同。您将找到与名称链接的SQL Fiddle示例。
为了计算两个查询的并集,交集或差异,这两个查询必须是" union compatible",这意味着它们返回相同数量的列,并且相应的列具有兼容的数据类型
列名称(不包括set操作中的第一个表)将被忽略。
此行为直接来自关系代数,其中基本构建块是元组。由于元组是有序的,因此两组元组的并集对于你在这里得到的输出是等价的(忽略重复处理)。
如果您想使用名称进行匹配,可以执行以下操作
import org.apache.spark.sql.DataFrame
import org.apache.spark.sql.functions.col
def unionByName(a: DataFrame, b: DataFrame): DataFrame = {
val columns = a.columns.toSet.intersect(b.columns.toSet).map(col).toSeq
a.select(columns: _*).unionAll(b.select(columns: _*))
}
要检查名称和类型,应该足以将columns
替换为:
a.dtypes.toSet.intersect(b.dtypes.toSet).map{case (c, _) => col(c)}.toSeq
答案 1 :(得分:3)
此问题已在spark2.3中修复。他们在数据集中添加了unionByName的支持。
https://issues.apache.org/jira/browse/SPARK-21043
答案 2 :(得分:1)
没有问题/错误-如果您非常仔细地观察案例B,那么您会很清楚。 案例类A->您提到了顺序(a,b),并且 案例类B->您已经提到了订单(b,a)--->根据订单的预期
案例类A(a:整数,b:整数) 案例B(b:Int,a:Int)
谢谢, 子
答案 3 :(得分:0)
正如SPARK-9813中所讨论的那样,只要数据类型和列数在各帧之间相同,unionAll操作就应该起作用。请参阅评论以获得更多讨论。
答案 4 :(得分:0)
使用unionByName:
文档摘录:
def unionByName(other: Dataset[T]): Dataset[T]
此函数与并集之间的区别在于此函数按名称(而不是按位置)解析列:
val df1 = Seq((1, 2, 3)).toDF("col0", "col1", "col2")
val df2 = Seq((4, 5, 6)).toDF("col1", "col2", "col0")
df1.union(df2).show
// output:
// +----+----+----+
// |col0|col1|col2|
// +----+----+----+
// | 1| 2| 3|
// | 4| 5| 6|
// +----+----+----+