Spark Dataframe Join - 重复列(未加入列)

时间:2018-01-17 08:31:49

标签: scala apache-spark dataframe join apache-spark-sql

我有两个数据帧df1(员工表)& df2(部门表),具有以下架构:

df1.columns
// Arrays(id,name,dept_id)

df2.columns
// Array(id,name)

我在df1.dept_id和df2.id上加入这两个表后:

val joinedData = df1.join(df2,df1("dept_id")===df2("id"))
joinedData.columns
// Array(id,name,dept_id,id,name)

将其保存在文件中,

joined.write.csv("<path>")

它给出错误:

 org.apache.spark.sql.AnalysisException: Duplicate column(s) : "name", "id" found, cannot save to file.;

我读到了使用字符串序列来避免列重复,但这是针对要执行连接的列。我需要为非连接列提供类似的功能。

是否可以直接使用重复列嵌入表名以便保存?

我想出了一个匹配dfs列并重命名重复列的解决方案,以将table-name追加到column-name。但是有直接的方法吗?

注意:这将是一个通用代码,仅包含执行连接的列详细信息。 Rest列仅在运行时才知道。所以我们不能通过硬编码来重命名列。

4 个答案:

答案 0 :(得分:4)

我会保留所有列,确保它们具有不同的名称,例如通过在列名前加一个标识符:

val df1Cols = df1.columns
val df2Cols = df2.columns

// prefixes to column names
val df1pf = df1.select(df1Cols.map(n => col(n).as("df1_"+n)):_*)
val df2pf = df2.select(df2Cols.map(n => col(n).as("df2_"+n)):_*)

df1pf.join(df2pf,
    $"df1_dept_id"===$"df2_id",
 )

答案 1 :(得分:1)

您可以尝试使用数据框的别名

import spark.implicits._

df1.as("df1")
  .join(df2.alias("df2"),df1("dept_id") === df2("id"))
  .select($"df1.*",$"df2.*").show()

答案 2 :(得分:1)

经过进一步研究并获得其他开发者的观点后,确信没有直接的方法。一种方法是更改​​@Raphael指定的所有列的名称。但我通过仅更改重复的列来解决我的问题:

val commonCols = df1.columns.intersect(df2.columns)
val newDf2 = changeColumnsName(df2,commonCols,"df1")

其中changeColumnsName定义为:

@tailrec
def changeColumnsName(dataFrame: DataFrame, columns: Array[String], tableName: String): DataFrame = {
if (columns.size == 0)
  dataFrame
else
  changeColumnsName(dataFrame.withColumnRenamed(columns.head, tableName + "_" + columns.head), columns.tail, tableName)

}

现在,执行加入:

val joinedData = df1.join(newDf2,df1("dept_id")===newDf2("df2_id"))
joinedData.columns
// Array(id,name,dept_id,df2_id,df2_name)

答案 3 :(得分:0)