Как я могу использовать ограничение OR для нескольких полусоединений? - PullRequest
0 голосов
/ 18 сентября 2018

Как я могу реализовать приведенный ниже SQL, используя semijoin в SparkSQL или API Dataframe?

select * 
from foo
left join a on foo.id = a.id
left join b on foo.id = b.id
where exists (select 1 from a x where foo.id = x.id)
or exists (select 1 from b x where foo.id = x.id)
;

Я пробовал это, но он работает как AND

.join(loincDF, foo("id") <=> a("id"), "leftsemi")
.join(loincDF, foo("id") <=> b("id"), "leftsemi")

Ответы [ 2 ]

0 голосов
/ 18 сентября 2018

Как указано в решении @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.

0 голосов
/ 18 сентября 2018

Вы можете попробовать что-то вроде этого:

foo.join(a, Seq("id"), "leftsemi")
   .union( foo.join(b, Seq("id"), "leftsemi") )
   .distinct
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...