【问题标题】:Spark conditional sum function returns null if column name is used如果使用列名,则 Spark 条件求和函数返回 null
【发布时间】:2021-03-24 22:32:01
【问题描述】:

我解释说spark sum function 可以使用字符串列名。但是,当使用 column namecolumn object 时,我会看到不同的结果。

schema = ["department", "employee", "knwos_ops", "developer"]
data = [("frontend", "john", 0, 1,), ("frontend", "jenny", 1, 1,), ("frontend", "michael", 0, 1,)]
input_df = spark.createDataFrame(data, schema=schema)
input_df.show(5, False)

+----------+--------+---------+---------+
|department|employee|knwos_ops|developer|
+----------+--------+---------+---------+
|frontend  |john    |0        |1        |
|frontend  |jenny   |1        |1        |
|frontend  |michael |0        |1        |
+----------+--------+---------+---------+

input_df \
    .groupBy(*["department"]) \
    .agg( \
            f.sum("developer").alias("dev"), \
            f.sum(f.when(f.col("knwos_ops") == 1, "developer")).alias("devops"), \
            f.sum("knwos_ops").alias("ops"),
    ).show(5, False)
    
+----------+---+------+---+
|department|dev|devops|ops|
+----------+---+------+---+
|frontend  |3  |null  |1  |
+----------+---+------+---+
    
input_df \
    .groupBy(*["department"]) \
    .agg( \
            f.sum("developer").alias("developer"), \
            f.sum(f.when(f.col("knwos_ops") == 1, f.col("developer"))).alias("devops"), \
            f.sum("knwos_ops").alias("ops"),
    ).show(5, False)

+----------+---+------+---+
|department|dev|devops|ops|
+----------+---+------+---+
|frontend  |3  |1     |1  |
+----------+---+------+---+

我对函数sumwhen的理解如下,

  • 函数when如果条件匹配则返回值,否则返回null。
  • 函数sum使用字符串类型的列名或Column类型的列名。

基于此,在第一个聚合示例中,when 函数内的条件应将列 developer 名称作为字符串返回,函数 sum 应使用该字符串进行聚合并返回 2。但是它返回 null。

为什么 spark 无法识别 developer 是数据框的一列。有人可以帮我理解这背后的文档吗?

更新 谢谢热心回复。正如我在第二次聚合中所做的那样,我有办法解决这个问题。我宁愿寻找这种行为背后的解释,并且有人指出我对功能sum的解释中的差距。

让我这样改写。如果函数 sum 获取字符串作为参数,它会尝试在数据框中找到同名的列

#### sum function receives string as argument, and finds the column and does the sum
input_df.agg(f.sum("developer")).show(5, False)
+--------------+
|sum(developer)|
+--------------+
|3             |
+--------------+

#### sum function receives string as argument, and finds the column and does the sum. Field type is string so it return null
input_df.agg(f.sum("employee")).show(5, False)
+--------------+
|sum(developer)|
+--------------+
|null          |
+--------------+

#### sum function receives string as argument, and does not find the column and throws error
input_df.agg(f.sum("manager")).show(5, False)
Py4JJavaError: An error occurred while calling o839.agg.
: org.apache.spark.sql.AnalysisException: cannot resolve '`manager`' given input columns: [department, employee, knwos_ops, developer];

基于上面的 sn-p,我希望函数 when 返回字符串 developer 和 我希望函数sum 将使用该字符串从该字符串中解析列并进行聚合。

【问题讨论】:

    标签: apache-spark pyspark apache-spark-sql


    【解决方案1】:

    when 与其他 Spark SQL 函数有点不同。如果您在then/otherwise 语句中指定一个字符串,它将被解释为字符串文字而不是列。

    例如,字符串文字的一个可能用例可能是

    F.when(F.col('size') > 10, 'large').otherwise('small')
    

    Spark 会将largesmall 解释为字符串文字而不是列。

    因此,在您的用例中,您对 'developer' 字符串求和,因为字符串无法求和,所以返回 null。

    由于这种歧义,有必要指定 F.col 以明确您想要一个列作为 then/otherwise 语句的结果。

    【讨论】:

    • 据我了解,函数sum 仅在参数中的列类型不是数字时才期望列名(类型字符串/列)返回 null。我在这里缺少什么?
    • when 返回一个带有文字 developer字符串列。它不返回字符串。
    【解决方案2】:

    您可能想要做的是以下操作:

    input_df \
        .groupBy(*["department"]) \
        .agg( \
                f.sum("developer").alias("developer"), \
                f.expr("SUM(CASE WHEN knwos_ops = 1 AND developer = 1 THEN 1 ELSE 0) AS devops"), \
                f.sum("knwos_ops").alias("ops"),
        ).show(5, False)
    

    【讨论】:

    • 谢谢。我更新了问题以明确我提出问题的意图。
    猜你喜欢
    • 2016-11-14
    • 1970-01-01
    • 1970-01-01
    • 2019-03-17
    • 2021-10-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多