加入后如何避免重复列?

Nee*_*eel 41 scala apache-spark apache-spark-sql

我有两个包含以下列的数据框:

df1.columns
//  Array(ts, id, X1, X2)
Run Code Online (Sandbox Code Playgroud)

df2.columns
//  Array(ts, id, Y1, Y2)
Run Code Online (Sandbox Code Playgroud)

我之后

val df_combined = df1.join(df2, Seq(ts,id))
Run Code Online (Sandbox Code Playgroud)

我最终得到以下列:Array(ts, id, X1, X2, ts, id, Y1, Y2).我可以预期公共列将被删除.有什么额外的东西需要做吗?

sta*_*010 31

简单的答案(来自关于此问题Databricks FAQ)是执行连接,其中连接列表示为字符串数组(或一个字符串)而不是谓词.

下面是一个改编自Databricks FAQ的示例,但有两个连接列,以回答原始海报的问题.

这是左侧数据帧:

val llist = Seq(("bob", "b", "2015-01-13", 4), ("alice", "a", "2015-04-23",10))

val left = llist.toDF("firstname","lastname","date","duration")

left.show()

/*
+---------+--------+----------+--------+
|firstname|lastname|      date|duration|
+---------+--------+----------+--------+
|      bob|       b|2015-01-13|       4|
|    alice|       a|2015-04-23|      10|
+---------+--------+----------+--------+
*/
Run Code Online (Sandbox Code Playgroud)

这是正确的数据框:

val right = Seq(("alice", "a", 100),("bob", "b", 23)).toDF("firstname","lastname","upload")

right.show()

/*
+---------+--------+------+
|firstname|lastname|upload|
+---------+--------+------+
|    alice|       a|   100|
|      bob|       b|    23|
+---------+--------+------+
*/
Run Code Online (Sandbox Code Playgroud)

这是一个不正确的解决方案,其中连接列被定义为谓词left("firstname")===right("firstname") && left("lastname")===right("lastname").

不正确的结果是firstnamelastname列在连接的数据框中重复:

left.join(right, left("firstname")===right("firstname") &&
                 left("lastname")===right("lastname")).show

/*
+---------+--------+----------+--------+---------+--------+------+
|firstname|lastname|      date|duration|firstname|lastname|upload|
+---------+--------+----------+--------+---------+--------+------+
|      bob|       b|2015-01-13|       4|      bob|       b|    23|
|    alice|       a|2015-04-23|      10|    alice|       a|   100|
+---------+--------+----------+--------+---------+--------+------+
*/
Run Code Online (Sandbox Code Playgroud)

正确的解决方案是定义连接列作为一个字符串数组Seq("firstname", "lastname").输出数据框没有重复的列:

left.join(right, Seq("firstname", "lastname")).show

/*
+---------+--------+----------+--------+------+
|firstname|lastname|      date|duration|upload|
+---------+--------+----------+--------+------+
|      bob|       b|2015-01-13|       4|    23|
|    alice|       a|2015-04-23|      10|   100|
+---------+--------+----------+--------+------+
*/
Run Code Online (Sandbox Code Playgroud)

  • 实际上输出DF*使用以下内容*具有重复项; `val joined = sampledDF.join(idsDF,idColumns,"inner")`.并且`idColumns`是包含连接列的Seq [String] (6认同)
  • 如果两个数据集中的列名不同,我认为这不起作用。 (2认同)
  • 当 4 个连接表达式中,有 2 个在两个表中具有不同的列,但 2 个引用两个表中的相同列时该怎么办。改名? (2认同)

zer*_*323 24

这是预期的行为.DataFrame.join方法相当于这样的SQL连接

SELECT * FROM a JOIN b ON joinExprs
Run Code Online (Sandbox Code Playgroud)

如果您想忽略重复的列,只需删除它们或之后选择感兴趣的列.如果您想消除歧义,可以使用父级访问这些DataFrames:

val a: DataFrame = ???
val b: DataFrame = ???
val joinExprs: Column = ???

a.join(b, joinExprs).select(a("id"), b("foo"))
// drop equivalent 
a.alias("a").join(b.alias("b"), joinExprs).drop(b("id")).drop(a("foo"))
Run Code Online (Sandbox Code Playgroud)

或使用别名:

// As for now aliases don't work with drop
a.alias("a").join(b.alias("b"), joinExprs).select($"a.id", $"b.foo")
Run Code Online (Sandbox Code Playgroud)

对于equi-joins,存在一种特殊的快捷语法,它采用一系列字符串:

val usingColumns: Seq[String] = ???

a.join(b, usingColumns)
Run Code Online (Sandbox Code Playgroud)

或者作为单个字符串

val usingColumn: String = ???

a.join(b, usingColumn)
Run Code Online (Sandbox Code Playgroud)

它只保留连接条件中使用的列的一个副本.

  • @Darryl`coalesce`并放下两者. (3认同)

tin*_*tin 8

我已经坚持了一段时间,直到最近我想出了一个非常简单的解决方案.

说是的

scala> val a  = Seq(("a", 1), ("b", 2)).toDF("key", "vala")
a: org.apache.spark.sql.DataFrame = [key: string, vala: int]

scala> a.show
+---+----+
|key|vala|
+---+----+
|  a|   1|
|  b|   2|
+---+----+
and 
scala> val b  = Seq(("a", 1)).toDF("key", "valb")
b: org.apache.spark.sql.DataFrame = [key: string, valb: int]

scala> b.show
+---+----+
|key|valb|
+---+----+
|  a|   1|
+---+----+
Run Code Online (Sandbox Code Playgroud)

我可以这样做只选择数据帧中的值a:

scala> a.join(b, a("key") === b("key"), "left").select(a.columns.map(a(_)) : _*).show
+---+----+
|key|vala|
+---+----+
|  a|   1|
|  b|   2|
+---+----+
Run Code Online (Sandbox Code Playgroud)

  • “ a.columns.map(a(_)) : _* ”有什么作用? (2认同)

小智 6

尝试这个,

val df_combined = df1.join(df2, df1("ts") === df2("ts") && df1("id") === df2("id")).drop(df2("ts")).drop(df2("id"))
Run Code Online (Sandbox Code Playgroud)


Abu*_*oeb 5

你可以简单地使用这个

df1.join(df2, Seq("ts","id"),"TYPE-OF-JOIN")
Run Code Online (Sandbox Code Playgroud)

在这里TYPE-OF-JOIN可以是

  • 剩下
  • 外表

例如,我有两个这样的数据框:

// df1
word   count1
w1     10   
w2     15  
w3     20

// df2
word   count2
w1     100   
w2     150  
w5     200
Run Code Online (Sandbox Code Playgroud)

如果您进行完全外部连接,则结果如下所示

df1.join(df2, Seq("word"),"fullouter").show()

word   count1  count2
w1     10      100
w2     15      150
w3     20      null
w5     null    200
Run Code Online (Sandbox Code Playgroud)

  • 我认为你可以做类似`df1.join(df2, Seq("word"),"fullouter").filter($"count1">10).show()`这样的事情。如果它不起作用,请告诉我。 (2认同)