如何按多列过滤数据框?

时间:2016-04-30 16:55:56

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

我遇到如下问题:

我有两个数据帧

Dataframe DF1:

ID, Name, age
1   name1  18
2   name2  20

DataFrame DF2:

ID, Name, age
1   name1 18
3   name3 19

我正在尝试过滤DF2以按ID和名称排除DF1中包含的记录,以便我可以获得新的DF2

ID, Name, age
3   name3  19

然后联合这两个数据帧以获得最终结果:

ID, Name, age
1   name1  18
2   name2  20
3   name3  19

要在T-SQL中执行此操作,我可以编写类似

的语句
INSERT INTO DF1 
SELECT ID, Name, age FROM DF2 WHERE NOT EXISTS
(SELECT 1 FROM DF1 WHERE DF1.ID = DF2.ID AND DF1.Name = DF2.Name)

但我发现sparkSQL中的数据框架不支持“insert”。 所以我的问题是:

如何基于多列过滤数据框?

如何将两个数据帧组合在一起? 我很感激任何解决方案。

1 个答案:

答案 0 :(得分:2)

UNION后跟DISTINCT

假设记录是唯一的,实现目标的最简单方法是UNION并按DISTINCT跟进:

val df1 = Seq((1, "name1", 18), (2, "name2", 20)).toDF("ID", "Name", "age")
val df2 = Seq((1, "name1", 18), (3, "name3", 19)).toDF("ID", "Name", "age")

df1.unionAll(df2).distinct.show

// +---+-----+---+
// | ID| Name|age|
// +---+-----+---+
// |  1|name1| 18|
// |  2|name2| 20|
// |  3|name3| 19|
// +---+-----+---+

<强>特性

  • 只需访问df1
  • 根据尺寸
  • df1df2进行随机播放

除了UNION

之外

另一种方法是使用EXCEPT后跟UNION

df1.unionAll(df2.except(df1)).show  // df2.distinct.except to drop duplicates

// +---+-----+---+
// | ID| Name|age|
// +---+-----+---+
// |  1|name1| 18|
// |  2|name2| 20|
// |  3|name3| 19|
// +---+-----+---+

<强>属性

  • 必须两次访问df1
  • 将两个帧混洗,与大小无关(?)
  • 可以与三个框架(df3.unionAll(df2.except(df1))
  • 一起使用

LEFT OUTER JOIN,然后是SELECT with filter,后跟UNION

最后,如果您只希望部分匹配LEFT OUTER JOIN,后跟UNION过滤器应该可以解决问题:

df2.as("df2")
  .join(
    df1.select("id", "name").as("df1"),
    // join on id and name
    $"df1.id" === $"df2.id" && $"df1.name" === $"df2.name",
    "leftouter")
  // This could be replaced by .na.drop(...)
  .where($"df1.id".isNull && $"df1.Name".isNull)
  .select($"df2.id", $"df2.name", $"df2.age")
  .unionAll(df1)
  .show

// ---+-----+---+
// | ID| Name|Age|
// +---+-----+---+
// |  3|name3| 19|
// |  1|name1| 18|
// |  2|name2| 20|
// +---+-----+---+

<强>属性

  • 必须两次访问df1
  • 如果一个数据帧足够小以进行广播,则可能不需要shuflle
  • 可以与三个数据框一起使用
相关问题