簡體   English   中英

spark Aggregationbykey-同一通話中的總和和移動平均值

[英]spark aggregatebykey - sum and running average in the same call

我正在學習火花,並且沒有使用hadoop的經驗。

問題

我正在嘗試在對AggregateByKey的同一調用中計算總和和平均值。

讓我分享到目前為止我所做的嘗試。

設置數據

val categoryPrices = List((1, 20), (1, 25), (1, 10), (1, 45))
val categoryPricesRdd = sc.parallelize(categoryPrices)

嘗試在對AggregateByKey的同一調用中計算平均值。 這是行不通的。

val zeroValue1 = (0, 0, 0.0) // (count, sum, average)
categoryPricesRdd.
    aggregateByKey(zeroValue1)(
        (tuple, prevPrice) => {
            val newCount = tuple._1 + 1
            val newSum = tuple._2 + prevPrice
            val newAverage = newSum/newCount
            (newCount, newSum, newAverage)
    },
    (tuple1, tuple2) => {
        val newCount1 = tuple1._1 + tuple2._1
        val newSum1 = tuple1._2 + tuple2._2
        // TRYING TO CALCULATE THE RUNNING AVERAGE HERE
        val newAverage1 = ((tuple1._2 * tuple1._1) + (tuple2._2 * tuple2._1))/(tuple1._1 + tuple2._1)
       (newCount1, newSum1, newAverage1)
    }
).
collect.
foreach(println)

結果:每次打印不同的平均值

  • 第一次:(1,(4,100,70.0))
  • 第二次:(1,(4,100,52.0))

只需先求和,然后在單獨的操作中計算平均值。 這可行。

val zeroValue2 = (0, 0) // (count, sum, average)
categoryPricesRdd.
    aggregateByKey(zeroValue2)(
        (tuple, prevPrice) => {
            val newCount = tuple._1 + 1
            val newSum = tuple._2 + prevPrice
            (newCount, newSum)
        },
        (tuple1, tuple2) => {
            val newCount1 = tuple1._1 + tuple2._1
            val newSum1 = tuple1._2 + tuple2._2
            (newCount1, newSum1)
        }
    ).
    map(rec => {
        val category = rec._1
        val count = rec._2._1
        val sum = rec._2._2
        (category, count, sum, sum/count)
    }).
    collect.
    foreach(println)

每次都打印相同的結果:(1,4,100,25)

我想我了解seqOp和CombOp之間的區別。 鑒於操作可以在不同服務器上的多個分區之間拆分數據,我的理解是seqOp對單個分區中的數據進行操作,然后combOp合並從不同分區接收的數據。 如果這是錯誤的,請更正。

但是,有一些我不太了解的基本知識。 看起來我們無法在同一調用中同時計算總和和平均值。 如果是這樣,請幫助我理解原因。

seqOpaverage聚合有關的計算:

val newAverage = newSum/newCount

並在combOp

val newAverage1 = ((tuple1._2 * tuple1._1) + (tuple2._2 * tuple2._1)) / (tuple1._1 + tuple2._1)

是不正確的。

假設前三個元素在一個分區中,最后一個元素在另一個分區中。 您的seqOp將生成(計數,總和,平均值)元組,如下所示:

Partition #1: [20, 25, 10]
  --> (1, 20, 20/1)
  --> (2, 45, 45/2)
  --> (3, 55, 55/3)

Partition #2: [45]
  --> (1, 45, 45/1)

接下來,跨分區combOp將合並兩個分區中的2個元組,得到:

((55 * 3) + (45 * 1)) / 4
// Result: 52

從上述步驟可以看到,如果RDD元素的順序或分區不同,則average可能會不同。

您的第二種方法有效,因為按定義, average是總和超過總計數,因此在先計算總和和計數值之后可以更好地進行計算。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM