我有两个数据帧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列仅在运行时才知道。所以我们不能通过硬编码来重命名列。
答案 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)