Scala Spark SQL Dataframe API-动态生成筛选器条件

Scala Spark SQL Dataframe API-动态生成筛选器条件,scala,apache-spark,apache-spark-sql,Scala,Apache Spark,Apache Spark Sql,我有两个Spark数据帧,df1和df2: +-------+-----+---+ |姓名| empNo |年龄| +-------+-----+---+ |尚卡尔| 12121 | 28| |拉梅什| 1212 | 29| |苏雷什| 1111 | 30| |阿鲁什| 0707 | 15| +-------+-----+---+ +------+-----+---+-----+ |埃纳姆|埃诺|年龄|城市| +------+-----+---+-----+ |阿鲁什| 12121 | 15

我有两个Spark数据帧,
df1
df2

+-------+-----+---+
|姓名| empNo |年龄|
+-------+-----+---+
|尚卡尔| 12121 | 28|
|拉梅什| 1212 | 29|
|苏雷什| 1111 | 30|
|阿鲁什| 0707 | 15|
+-------+-----+---+
+------+-----+---+-----+
|埃纳姆|埃诺|年龄|城市|
+------+-----+---+-----+
|阿鲁什| 12121 | 15 |马尔默|
|拉梅什| 1212 | 29 |马尔默|
+------+-----+---+-----+
我需要根据另一个文件中指定的许多列,从
df1
获取非匹配记录

例如,列查找文件如下所示:

df1col,df2col
名字,艾娜
恩普诺
预期输出为:

+-------+-----+---+
|姓名| empNo |年龄|
+-------+-----+---+
|尚卡尔| 12121 | 28|
|苏雷什| 1111 | 30|
|阿鲁什| 0707 | 15|
+-------+-----+---+

其思想是如何为上述场景动态构建where条件,因为查找文件是可配置的,因此它可能有1到n个字段。

如果您是从SQL查询执行此操作,我将使用类似的内容重新映射SQL查询本身中的列名。您可以在查询中进行简单的文本替换,将它们规范化为df1或df2列名

一旦你有了它,你就可以用类似


如果您需要更多不在差异中使用的列(例如年龄),您可以根据您的差异结果重新选择数据。这可能不是最好的方法,但它可能会起作用。

如果您是从SQL查询执行此操作,我会在SQL查询本身中重新映射列名,如下所示。您可以在查询中进行简单的文本替换,将它们规范化为df1或df2列名

一旦你有了它,你就可以用类似


如果您需要更多不在差异中使用的列(例如年龄),您可以根据您的差异结果重新选择数据。这可能不是最好的方法,但它可能会起作用。

您可以使用
方法,但
数据帧方法除外。为了简单起见,我假设要使用的列在两个列表中。两个列表的顺序必须正确,列表中相同位置上的列将被比较(无论列名称如何)。在
except
之后,使用
join
从第一个数据帧中获取缺少的列

val df1 = Seq(("shankar","12121",28),("ramesh","1212",29),("suresh","1111",30),("aarush","0707",15))
  .toDF("name", "empNo", "age")
val df2 = Seq(("aarush", "12121", 15, "malmo"),("ramesh", "1212", 29, "malmo"))
  .toDF("eName", "eNo", "age", "city")

val df1Cols = List("name", "empNo")
val df2Cols = List("eName", "eNo")

val tempDf = df1.select(df1Cols.head, df1Cols.tail: _*)
  .except(df2.select(df2Cols.head, df2Cols.tail: _*))    
val df = df1.join(broadcast(tempDf), df1Cols)
生成的数据帧将如所需:

+-------+-----+---+
|   name|empNo|age|
+-------+-----+---+
| aarush| 0707| 15|
| suresh| 1111| 30|
|shankar|12121| 28|
+-------+-----+---+

您可以使用
数据帧方法之外的方法。为了简单起见,我假设要使用的列在两个列表中。两个列表的顺序必须正确,列表中相同位置上的列将被比较(无论列名称如何)。在
except
之后,使用
join
从第一个数据帧中获取缺少的列

val df1 = Seq(("shankar","12121",28),("ramesh","1212",29),("suresh","1111",30),("aarush","0707",15))
  .toDF("name", "empNo", "age")
val df2 = Seq(("aarush", "12121", 15, "malmo"),("ramesh", "1212", 29, "malmo"))
  .toDF("eName", "eNo", "age", "city")

val df1Cols = List("name", "empNo")
val df2Cols = List("eName", "eNo")

val tempDf = df1.select(df1Cols.head, df1Cols.tail: _*)
  .except(df2.select(df2Cols.head, df2Cols.tail: _*))    
val df = df1.join(broadcast(tempDf), df1Cols)
生成的数据帧将如所需:

+-------+-----+---+
|   name|empNo|age|
+-------+-----+---+
| aarush| 0707| 15|
| suresh| 1111| 30|
|shankar|12121| 28|
+-------+-----+---+

如果数据集很大怎么办。。这是一种有效的方法吗。。还是我们可以在连接本身中做些什么?@Shankar对于这个问题,我相信某种类型的
join
总是必要的,所以它不会比这更有效。但是,由于
tempDf
的大小总是等于或小于
df1
,因此我更改了它们在连接中的位置,并为
tempDf
添加了一个
广播。这将暗示Spark,广播数据帧是一个好主意,在大多数情况下会提高效率。为此,我的问题是,我们是否可以在join中添加条件,而不是except first then join,我完全同意您的解决方案是可行的,我喜欢它,我只是想了解连接本身,我们能不能创建一个where条件并实现同样的效果。@Shankar啊,我明白了。我不认为你能用where解决这个问题,因为你有一个可变的列数。在任何情况下,Spark都会优化执行计划,因此我相信结果会大致相同。如果数据集很大会怎么样。。这是一种有效的方法吗。。还是我们可以在连接本身中做些什么?@Shankar对于这个问题,我相信某种类型的
join
总是必要的,所以它不会比这更有效。但是,由于
tempDf
的大小总是等于或小于
df1
,因此我更改了它们在连接中的位置,并为
tempDf
添加了一个
广播。这将暗示Spark,广播数据帧是一个好主意,在大多数情况下会提高效率。为此,我的问题是,我们是否可以在join中添加条件,而不是except first then join,我完全同意您的解决方案是可行的,我喜欢它,我只是想了解连接本身,我们能不能创建一个where条件并实现同样的效果。@Shankar啊,我明白了。我不认为你能用where解决这个问题,因为你有一个可变的列数。在任何情况下,Spark都会优化执行计划,因此我相信结果大致相同。