Довольно новый для искры / скала. Мне интересно, есть ли простой способ агрегирования массива [Double] по столбцам. Вот пример:

c1   c2   c3
-------------------------
1     1   [1.0, 1.0, 3.4]
1     2   [1.0, 0,0, 4.3]
2     1   [0.0, 0.0, 0.0]
2     3   [1.2, 1.1, 1.1]

Затем при агрегировании я бы закончил с таблицей, которая выглядит следующим образом:

c1   c3prime
-------------
1     [2.0, 1.0, 7.7]
2     [1.2, 1.1, 1.1]

Глядя на UDAF сейчас, но мне было интересно, нужно ли мне вообще кодировать?

Спасибо за внимание.

3
Kirby 21 Окт 2017 в 00:15

3 ответа

Лучший ответ

Предполагая, что значения массива c3 имеют одинаковый размер, вы можете суммировать столбец поэлементно с помощью UDF, как показано ниже:

val df = Seq(
  (1, 1, Seq(1.0, 1.0, 3.4)),
  (1, 2, Seq(1.0, 0.0, 4.3)),
  (2, 1, Seq(0.0, 0.0, 0.0)),
  (2, 3, Seq(1.2, 1.1, 1.1))
).toDF("c1", "c2", "c3")

def elementSum = udf(
  (a: Seq[Seq[Double]]) => {
    val zeroSeq = Seq.fill[Double](a(0).size)(0.0)
    a.foldLeft(zeroSeq)(
      (a, x) => (a zip x).map{ case (u, v) => u + v }
    )
  }
)

val df2 = df.groupBy("c1").agg(
  elementSum(collect_list("c3")).as("c3prime")
)

df2.show(truncate=false)
// +---+-----------------------------+
// |c1 |c3prime                      |
// +---+-----------------------------+
// |1  |[2.0, 1.0, 7.699999999999999]|
// |2  |[1.2, 1.1, 1.1]              |
// +---+-----------------------------+
2
Leo C 21 Окт 2017 в 02:35

Вы можете объединить некоторые inbuilt functions, такие как groupBy, agg, sum, array, alias (as) и т. Д., Чтобы получить желаемый финал dataframe.

import org.apache.spark.sql.functions._
df.groupBy("c1")
  .agg(sum($"c3"(0)).as("c3_1"), sum($"c3"(1)).as("c3_2"), sum($"c3"(2)).as("c3_3"))
  .select($"c1", array("c3_1","c3_2","c3_3").as("c3prime"))

Я надеюсь, что ответ полезен.

1
Ramesh Maharjan 21 Окт 2017 в 13:04

Вот один без UDF. Он использует функции окна Spark. Не уверен, насколько это эффективно, так как в нем задействовано несколько groupBy

df.show

// +---+---+---------------+
// | c1| c2|             c3|
// +---+---+---------------+
// |  1|  1|[1.0, 1.0, 3.4]|
// |  1|  2|[1.0, 0.0, 4.3]|
// |  2|  1|[0.0, 0.0, 0.0]|
// |  2|  2|[1.2, 1.1, 1.1]|
// +---+---+---------------+

import org.apache.spark.sql.expressions.Window

val window = Window.partitionBy($"c1", $"c2").orderBy($"c1", $"c2")

df.withColumn("c3", explode($"c3") )
  .withColumn("rn", row_number() over window)
  .groupBy($"c1", $"rn").agg(sum($"c3").as("c3") )
  .orderBy($"c1", $"rn")
  .groupBy($"c1")
  .agg(collect_list($"c3").as("c3prime") ).show

// +---+--------------------+
// | c1|             c3prime|
// +---+--------------------+
// |  1|[2.0, 1.0, 7.6999...|
// |  2|     [1.2, 1.1, 1.1]|
// +---+--------------------+
1
philantrovert 21 Окт 2017 в 05:20