Как указано в решении @Elmar Macek, объединение объединений left_semi
имитирует условие OR
предложений exists
.Однако left_semi
объединение не создает соответствующие столбцы из right
DataFrame.Чтобы сгенерировать результат, эквивалентный вашему SQL, который включает left join
s, вы можете сначала выполнить left_outer
объединения перед применением логики фильтрации, которая имитирует функцию exists
.
Ниже приведены несколько методов:
МЕТОД 1: Выполнение left_outer
объединений, затем left_semi
объединений
val foo = Seq(
(1, "f1"), (2, "f2"), (3, "f3"), (4, "f4"), (5, "f5")
).toDF("id", "name")
val a = Seq(
(1, "a1"), (3, "a3")
).toDF("id", "desc")
val b = Seq(
(1, "b1"), (4, "b4")
).toDF("id", "desc")
val bar = foo.
join(a, Seq("id"), "left_outer").
join(b, Seq("id"), "left_outer")
bar.join(a, Seq("id"), "left_semi").
union(
bar.join(b, Seq("id"), "left_semi")
).
distinct.
show
// +---+----+----+----+
// | id|name|desc|desc|
// +---+----+----+----+
// | 4| f4|null| b4|
// | 1| f1| a1| b1|
// | 3| f3| a3|null|
// +---+----+----+----+
МЕТОД 2: Выполнение left_outer
объединений, затем null
проверок неключевых столбцов
val aNonKeyCols = a.columns.filter(_ != "id")
val a2 = a.withColumn("aCols", struct(aNonKeyCols.map(col): _*)).
select("id", "aCols")
val bNonKeyCols = b.columns.filter(_ != "id")
val b2 = b.withColumn("bCols", struct(aNonKeyCols.map(col): _*)).
select("id", "bCols")
val bar = foo.
join(a2, Seq("id"), "left_outer").
join(b2, Seq("id"), "left_outer").
where($"aCols".isNotNull || $"bCols".isNotNull).
select("id", "name", "aCols.*", "bCols.*")
Обратите внимание, что при условии, что столбцов может быть много, неключевые столбцы a
и b
помещаются в struct
, чтобы упростить проверку null
.