我正在尝试比较具有相同模式的两个DataFrame(在Spark 1.6.0中,使用Scala)来确定更新表中的哪些行已添加(即,旧表中不存在)。
我需要通过ID 执行(即检查单个列,而不是整行,以查看新内容)。某些行可能在版本之间发生了变化,因为它们在两个版本中都具有相同的 id ,但其他列已更改 - 我不希望这些在输出中,所以我不能简单地减去这两个版本。
根据各种建议,我在所选ID列上进行左外连接,然后从连接右侧的列中选择带空值的行(表示它们不存在于旧版本的表中):
def diffBy(field:String, newer:DataFrame, older:DataFrame): DataFrame = {
newer.join(older, newer(field) === older(field), "left_outer")
.select(older(field).isNull)
// TODO just select the leftmost columns, removing the nulls
}
然而,这不起作用。 (第3行仅存在于较新版本中,因此应输出):
scala> newer.show
+---+-------+
| id| value|
+---+-------+
| 3| three|
| 2|two-new|
+---+-------+
scala> older.show
+---+-------+
| id| value|
+---+-------+
| 1| one|
| 2|two-old|
+---+-------+
scala> diffBy("id", newer, older).show
+---+-----+---+-----+
| id|value| id|value|
+---+-----+---+-----+
+---+-----+---+-----+
联接按预期工作:
scala> val joined = newer.join(older, newer("id") === older("id"), "left_outer")
scala> joined.show
+---+-------+----+-------+
| id| value| id| value|
+---+-------+----+-------+
| 2|two-new| 2|two-old|
| 3| three|null| null|
+---+-------+----+-------+
所以问题在于选择用于过滤的列。
joined.where(older("id").isNull).show
+---+-----+---+-----+
| id|value| id|value|
+---+-----+---+-----+
+---+-----+---+-----+
也许是因为联接中的重复id
列名称?但是,如果我使用value
列(也是重复的)来检测空值,它会按预期工作:
joined.where(older("value").isNull).show
+---+-----+----+-----+
| id|value| id|value|
+---+-----+----+-----+
| 3|three|null| null|
+---+-----+----+-----+
这里发生了什么 - 为什么id
和value
的行为有所不同?
答案 0 :(得分:1)
您可以使用名为“ leftanti”的特殊火花联接解决问题。它等于减号(在Oracle PL SQL中)。
val joined = newer.join(older, newer("id") === older("id"), "leftanti")
这只会从newer
中选择列。
答案 1 :(得分:0)
我找到了解决问题的方法,但不解释为什么会出现问题。
似乎有必要创建一个别名,以便明确地引用最右边的id
列,然后使用文本WHERE
子句,以便我可以替换来自的合格列名称变量field
:
newer.join(older.as("o"), newer(field) === older(field), "left_outer")
.where(s"o.$field IS NULL")