Scala Spark reduce和聚合在同一数据集上
我有一个文本文件,我读取它,然后使用Scala Spark reduce和聚合在同一数据集上,scala,apache-spark,aggregate-functions,Scala,Apache Spark,Aggregate Functions,我有一个文本文件,我读取它,然后使用split操作进行拆分。这将产生一个带有数组(A、B、C、D、E、F、G、H、I)的RDD 我想为每个键E(按键E减少)查找max(F)-min(G)。然后我想按键C组合结果值,并用相同的键连接每一行的这个求和结果 例如: +--+--+--+--+ | C| E| F| G| +--+--+--+--+ |en| 1| 3| 1| |en| 1| 4| 0| |nl| 2| 1| 1| |nl| 2| 5| 2| |nl| 3| 9| 3| |nl| 3|
split
操作进行拆分。这将产生一个带有数组(A、B、C、D、E、F、G、H、I)的RDD
我想为每个键E
(按键E
减少)查找max(F)-min(G)
。然后我想按键C
组合结果值,并用相同的键连接每一行的这个求和结果
例如:
+--+--+--+--+
| C| E| F| G|
+--+--+--+--+
|en| 1| 3| 1|
|en| 1| 4| 0|
|nl| 2| 1| 1|
|nl| 2| 5| 2|
|nl| 3| 9| 3|
|nl| 3| 6| 4|
|en| 4| 9| 1|
|en| 4| 2| 1|
+-----------+
应该导致
+--+--+-------------+---+
| C| E|max(F)-min(G)|sum|
+--+--+-------------+---+
|en| 1| 4 |12 |
|nl| 2| 4 |10 |
|nl| 3| 6 |10 |
|en| 4| 8 |12 |
+--+--+-------------+---+
解决这个问题的最好办法是什么?目前,我正试图通过运行来执行max(F)-min(G)
val maxCounts = logEntries.map(line => (line(4), line(5).toLong)).reduceByKey((x, y) => math.max(x, y))
val minCounts = logEntries.map(line => (line(4), line(6).toLong)).reduceByKey((x, y) => math.min(x, y))
val maxMinCounts = maxCounts.join(minCounts).map{ case(id, maxmin) => (id, (maxmin._1 - maxmin._2)) }
然后join
生成的RDD。然而,当我还想对这些值求和并将它们附加到现有数据集中时,这就变得很棘手了
我很想听到任何建议 假设,像您的示例数据一样,唯一的E永远不会跨越多个C。。。你可以这样做
import math.{max,min}
case class FG(f: Int, g: Int) {
def combine(that: FG) =
FG(max(f, that.f), min(g, that.g))
def result = f - g
}
val result = {
rdd
.map{ case Array(_, _, c, _, e, f, g, _, _) =>
((c, e), FG(f, g)) }
.reduceByKey(_ combine _)
.map{ case ((c, _), fg) =>
(c, fg.result) }
.reduceByKey(_+_)
}
这种逻辑很容易在DataFrameAPI中实现。但您需要从数组中显式形成列:
val window = Window.partitionBy('C)
val df = rdd
.map { case Array(_, _, c, _, e, f, g, _, _) => (c,e,f,g) }
.toDF("C","E","F","G")
.groupBy('C,'E)
.agg((max('F) - min('G)).as("diff"))
.withColumn("sum",sum('diff).over(window))
使用Spark SQL DataFrame很容易,您可以将RDD转换为DataFrame并执行所有聚合操作。。尝试此链接为什么不将
math.max
和math.min
合并到同一RDD中?谢谢您的建议。我将sum(diff)
更改为sum('diff)
和Window.partitionBy('v)
更改为Window.partitionBy('C)
,因为否则会导致错误。但是,当我尝试运行此代码时,我得到了以下错误:scala.MatchError:[Ljava.lang.String;@f908897(属于[Ljava.lang.String;)
。使用Window.partitionBy('v)
导致org.apache.spark.sql.AnalysisException:无法解析给定输入列[C,E,diff];
。我使用Spark CSV阅读器解决了这个问题,而不是直接读取输入文件。这个问题可能与输入中的特殊字符有关。