如何添加具有最大值的新列?

时间:2018-05-31 14:03:26

标签: scala apache-spark apache-spark-sql

我有一个包含2列tagvalue的数据框。

我想添加一个包含max valueval df2 = df.withColumn("max",max($"value")) 的新列。 (每行的值相同。)

我尝试按照以下方式执行操作,但它无法正常工作。

max

如何将<td > <button id="cat" type="button" name="button[]" class="w3-btn w3-dark-grey w3-hover-light-grey" onclick="openCateg(<?php echo $row["idEmpresa"]?>);">Categorias</button> </td> 列添加到数据集?

2 个答案:

答案 0 :(得分:4)

有三种方法可以做到(一个你已经从另一个答案中得知)。我避免使用collect,因为它并不是真的需要。

这是最大值为3的数据集出现两次。

val tags = Seq(
  ("tg1", 1), ("tg2", 2), ("tg1", 3), ("tg4", 4), ("tg3", 3)
).toDF("tag", "value")
scala> tags.show
+---+-----+
|tag|value|
+---+-----+
|tg1|    1|
|tg2|    2|
|tg1|    3| <-- maximum value
|tg4|    4|
|tg3|    3| <-- another maximum value
+---+-----+

笛卡尔加入&#34; Max&#34;数据集

我将使用tags的笛卡尔联接和具有最大值的单行数据集。

val maxDF = tags.select(max("value") as "max")
scala> maxDF.show
+---+
|max|
+---+
|  4|
+---+
val solution = tags.crossJoin(maxDF)
scala> solution.show
+---+-----+---+
|tag|value|max|
+---+-----+---+
|tg1|    1|  4|
|tg2|    2|  4|
|tg1|    3|  4|
|tg4|    4|  4|
|tg3|    3|  4|
+---+-----+---+

我并不担心这里的笛卡尔联盟,因为它只是一个单行数据集。

窗口聚合

我最喜欢的窗口聚合非常适合这个问题。另一方面,由于使用的分区数量很少,我并不认为这是最有效的方法,即只有1,这给出了最差的并行性。

诀窍是在空窗口规范上使用聚合函数max,该规范通知Spark SQL以任何顺序使用所有行。

val solution = tags.withColumn("max", max("value") over ())
scala> solution.show
18/05/31 21:59:40 WARN WindowExec: No Partition Defined for Window operation! Moving all data to a single partition, this can cause serious performance degradation.
+---+-----+---+
|tag|value|max|
+---+-----+---+
|tg1|    1|  4|
|tg2|    2|  4|
|tg1|    3|  4|
|tg4|    4|  4|
|tg3|    3|  4|
+---+-----+---+

请注意这一切的警告。

  

WindowExec:没有为Window操作定义分区!将所有数据移动到单个分区,这可能会导致严重的性能下降。

我不会在给出其他解决方案的情况下使用这种方法,并将其留在这里用于教育目的。

答案 1 :(得分:3)

如果您想要所有行的列的最大值,您将需要比较某种形式的所有行。这意味着要进行聚合。 withColumn仅在单行上运行,因此您无法获取DataFrame最大值。

最简单的方法如下:

val data = Seq(("a", 1), ("b", 2), ("c", 3), ("d", 4))
val df = sc.parallelize(data).toDF("name", "value")

// first is an action, so this will execute spark stages to compute the value
val maxValue = df.groupBy().agg(max($"value")).first.getInt(0)

// Now you can add it to your original DF
val updatedDF = df.withColumn("max", lit(maxValue))

updatedDF.show

还有一种替代方案可能会快一点。如果你不需要最大值直到你的处理结束(在你已经运行了一个spark动作之后),你可以通过编写自己的Spark Acccumulator来计算它,而不是在做任何其他Spark Action工作的时候收集值请求。