我正在尝试通过获取数据帧中一组列的行值的总和来创建总和列。所以我按照以下方法去做。
val temp_data = spark.createDataFrame(Seq(
(1, 5),
(2, 4),
(3, 7),
(4, 6)
)).toDF("A", "B")
val cols = List(col("A"), col("B"))
temp_data.withColumn("sum", cols.reduce(_ + _)).show
+---+---+---+
| A| B|sum|
+---+---+---+
| 1| 5| 6|
| 2| 4| 6|
| 3| 7| 10|
| 4| 6| 10|
+---+---+---+
因此,此方法工作正常并产生预期的输出。但是,我想在不显式指定列名的情况下创建 cols 变量。因此,我按如下方式使用了typedLit。
val cols2 = temp_data.columns.map(x=>typedLit(x)).toList
当我看cols
和cols2
时,它们看起来一模一样。
cols: List[org.apache.spark.sql.Column] = List(A, B)
cols2: List[org.apache.spark.sql.Column] = List(A, B)
但是,当我使用 cols2
创建我的 sum 列时,它并没有按照我期望的方式工作。
temp_data.withColumn("sum", cols2.reduce(_ + _)).show
+---+---+----+
| A| B| sum|
+---+---+----+
| 1| 5|null|
| 2| 4|null|
| 3| 7|null|
| 4| 6|null|
+---+---+----+
有人知道我在这里做错了什么吗?为什么第二种方法不像第一种方法那样工作?
lit
或typedLit
不能替代Column
。您的代码执行的操作会创建一个字符串文本列表 - "A"
和"B"
temp_data.select(cols2: _*).show
+---+---+
| A| B|
+---+---+
| A| B|
| A| B|
| A| B|
| A| B|
+---+---+
并要求他们的总和 - 因此结果是不确定的。
您可以在此处使用TypedColumn
:
import org.apache.spark.sql.TypedColumn
val typedSum: TypedColumn[Any, Int] = cols.map(_.as[Int]).reduce{
(x, y) => (x + y).as[Int]
}
temp_data.withColumn("sum", typedSum).show
但与标准Column
相比,它并没有提供任何实际优势。
您正在尝试使用typedLit,这是不正确的,并且像提到的其他答案一样,您不必使用带有TypedColumn的函数。您可以简单地在数据帧的列上使用映射转换,将其转换为 List(Col)
将您的 cols2 语句更改为下面并尝试。
val cols = temp_data.columns.map(f=> col(f))
temp_data.withColumn("sum", cols.reduce(_ + _)).show
你会得到下面的输出。
+---+---+---+
| A| B|sum|
+---+---+---+
| 1| 5| 6|
| 2| 4| 6|
| 3| 7| 10|
| 4| 6| 10|
+---+---+---+
谢谢