【问题标题】:spark scala conditional join replace null valuesspark scala 条件连接替换空值
【发布时间】:2021-09-22 22:25:16
【问题描述】:

我有两个数据框。我想使用来自col1df2 的值替换col1df1 中的值为空的值。请记住,df1df2 类似,可以有 > 10^6 行,并且df1 有一些额外的列,这些列与df2 的一些额外列不同。

我知道如何加入,但我不知道如何在 Spark 中使用 Scala 进行某种条件加入。

df1

name   | col1 | col2 | col3
----------------------------
foo    | 0.1  | ...
bar    | null |
hello  | 0.6  |
foobar | null |


df2 

name   | col1 | col7
--------------------
lorem  | 0.1  |
bar    | 0.52 |
foobar | 0.47 |

编辑:

这是我目前的解决方案:

df1.select("name", "col2", "col3").join(df2, (df1("name") === df2("name")), "left").select(df1("name"), col("col1"))

EDIT2:

val df1 = Seq(
  ("foo", Seq(0.1), 10, "a"),
  ("bar", Seq(), 20, "b"),
  ("hello", Seq(0.1), 30, "c"),
  ("foobar", Seq(), 40, "d")
).toDF("name", "col1", "col2", "col3")

val df2 = Seq(
  ("lorem", Seq(0.1), "x"),
  ("bar", Seq(0.52), "y"),
  ("foobar", Seq(0.47), "z")
).toDF("name", "col1", "col7")

display(df1.
  join(df2, Seq("name"), "left_outer").
  select(df1("name"), coalesce(df1("col1"), df2("col1")).as("col1")))

返回:

name   | col1
bar    | []
foo    | [0.1]
foobar | []
hello  | [0.1]

【问题讨论】:

    标签: scala apache-spark join conditional-statements


    【解决方案1】:

    在执行left join 之后,考虑在col1 上使用coalesce。要按照 cmets 部分的修订要求同时处理 nulls 和空 arrays(在 ArrayType 的情况下),使用 when/otherwise 子句,如下所示:

    val df1 = Seq(
      ("foo",    Some(Seq(0.1)), 10, "a"),
      ("bar",    None,           20, "b"),
      ("hello",  Some(Seq(0.1)), 30, "c"),
      ("foobar", Some(Seq()),    40, "d")
    ).toDF("name", "col1", "col2", "col3")
    
    val df2 = Seq(
      ("lorem",  Seq(0.1),  "x"),
      ("bar",    Seq(0.52), "y"),
      ("foobar", Seq(0.47), "z")
    ).toDF("name", "col1", "col7")
    
    df1.
      join(df2, Seq("name"), "left_outer").
      select(
        df1("name"),
        coalesce(
          when(lit(df1.schema("col1").dataType.typeName) === "array" && size(df1("col1")) === 0, df2("col1")).otherwise(df1("col1")), 
          df2("col1")
        ).as("col1")
      ).
      show
    /*
    +------+------+
    |  name|  col1|
    +------+------+
    |   foo| [0.1]|
    |   bar|[0.52]|
    | hello| [0.1]|
    |foobar|[0.47]|
    +------+------+
    */
    

    更新:

    令人惊讶的是,Spark 似乎不像大多数其他语言那样处理conditionA && conditionB——即使conditionA 为假conditionB 仍将被评估,并且仍将&& 替换为嵌套的when/otherwise不会解决问题。这可能是由于内部翻译的case/when/else SQL 的执行方式受到限制。

    因此,当 col1 是非 ArrayType 时,通过特定于数组的函数 size() 进行的上述 when/otherwise 数据类型检查失败。鉴于此,我会放弃动态列类型检查并根据 col1 是否为 ArrayType 执行不同的查询,假设它是预先知道的:

    df1.
      join(df2, Seq("name"), "left_outer").
      select(
        df1("name"),
        coalesce(
          when(size(df1("col1")) === 0, df2("col1")).otherwise(df1("col1")),  // <-- if col1 is an array
          // df1("col1"),  // <-- if col1 is not an array
          df2("col1")
        ).as("col1")
      ).
      show
    

    【讨论】:

    • 当我将 col1 作为 ArrayType[String] 时它对我不起作用
    • @darkman,我无法重现上述问题——我刚刚在示例数据中将col1 修改为 ArrayType,完全相同的join/select sn-p 工作正常。跨度>
    • 这是一个不同于简单替换null 的要求,因为Seq() 是非空的。请查看我修改后的答案,其中包含一个稍微概括的样本数据集,该数据集同时处理 nulls 和空 arrays(在 ArrayType 的情况下)。
    猜你喜欢
    • 1970-01-01
    • 2023-03-26
    • 2017-04-10
    • 1970-01-01
    • 1970-01-01
    • 2023-03-16
    • 2021-11-16
    • 2017-10-21
    • 2016-01-27
    相关资源
    最近更新 更多