Scala 如何按多列筛选数据帧?
我有一个问题如下: 我有两个数据帧 数据帧DF1:Scala 如何按多列筛选数据帧?,scala,apache-spark,apache-spark-sql,Scala,Apache Spark,Apache Spark Sql,我有一个问题如下: 我有两个数据帧 数据帧DF1: ID, Name, age 1 name1 18 2 name2 20 数据帧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
ID, Name, age
1 name1 18
2 name2 20
数据帧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中实现这一点,我可以编写如下语句
插入到DF1中
从不存在的DF2中选择ID、名称、年龄
从DF1中选择1,其中DF1.ID=DF2.ID,DF1.Name=DF2.Name
但我发现sparkSQL中的dataframe不支持insert。
因此,我的问题是:
如何基于多列过滤数据帧
如何将两个数据帧合并在一起?
非常感谢您提供的任何解决方案。联合,然后是不同的解决方案
假设记录是唯一的,实现您想要的最简单的方法是采用UNION并遵循DISTINCT:
特点:
只能访问df1一次
洗牌df1和df2,与大小无关
除非后面跟着工会
另一种方法是使用除UNION外的其他方法:
特性:
必须访问df1两次
洗牌两帧独立于大小
可用于三帧df3.unionAlldf2.exceptdf1
左外部联接,后跟选择,带有过滤器,后跟并集
最后,如果您只希望部分匹配左外部联接,则应使用过滤器后跟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两次
如果其中一个数据帧小到可以广播,则可能不需要Shufle
可与三个数据帧一起使用
看到不同的解决方案后,我想知道它们的性能。哪种解决方案在性能方面是最好的?为什么?@JacekLaskowski我自己也在考虑,其中涉及到不同的权衡。假设我们只使用两个帧,并且两个帧都很大,我会使用第一种方法,因为只有在没有分支和合并的情况下,它才能访问df1。如果有3帧涉及我们合并不同的帧,而不是我们减去,那么这是根本不适用的。如果其中一个帧足够小,可以进行广播以避免混洗,则基于连接的解决方案更可取。@JacekLaskowski老实说,我不确定,除了。看起来它不能使用广播,所以当你想和第三帧合并时,我只能用它作为第一个解决方案的替代方案。你知道如何测量它吗?我会从web UI和SparkListener开始,但也许还有更多的专业工具/方法?@JacekLaskowski UI用于简单案例,Docker+Munin用于测量对整个管道的影响通常对我来说已经足够好了。一个问题是,有很多运动部件可以单独测量这样的东西。
df1.unionAll(df2.except(df1)).show // df2.distinct.except to drop duplicates
// +---+-----+---+
// | ID| Name|age|
// +---+-----+---+
// | 1|name1| 18|
// | 2|name2| 20|
// | 3|name3| 19|
// +---+-----+---+
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|
// +---+-----+---+