如果我有每分钟卷的RDD,例如
(("12:00" -> 124), ("12:01" -> 543), ("12:02" -> 102), ... )
我想将其映射到此分钟的音量数据集,前一分钟的音量,前5分钟的平均音量。 E.g。
(("12:00" -> (124, 300, 245.3)),
("12:01" -> (543, 124, 230.2)),
("12:02" -> (102, 543, 287.1)))
输入RDD可以是RDD[(DateTime, Int)]
,输出RDD[(DateTime, (Int, Int, Float))]
。
有什么好方法可以做到这一点?
答案 0 :(得分:4)
转换为数据框并使用窗口函数可以涵盖滞后,平均和可能的间隙:
import com.github.nscala_time.time.Imports._
import org.apache.spark.sql.Row
import org.apache.spark.sql.functions.{lag, avg, when}
import org.apache.spark.sql.expressions.Window
val fmt = DateTimeFormat.forPattern("HH:mm:ss")
val rdd = sc.parallelize(Seq(
("12:00:00" -> 124), ("12:01:00" -> 543), ("12:02:00" -> 102),
("12:30:00" -> 100), ("12:31:00" -> 101)
).map{case (ds, vol) => (fmt.parseDateTime(ds), vol)})
val df = rdd
// Convert to millis for window range
.map{case (dt, vol) => (dt.getMillis, vol)}
.toDF("ts", "volume")
val w = Window.orderBy($"ts")
val transformed = df.select(
$"ts", $"volume",
when(
// Check if we have data from the previous minute
(lag($"ts", 1).over(w) - $"ts").equalTo(-60000),
// If so get lag otherwise 0
lag($"volume", 1).over(w)).otherwise(0).alias("previous_volume"),
// Average over window
avg($"volume").over(w.rangeBetween(-300000, 0)).alias("average"))
// Optionally go to back to RDD
transformed.map{
case Row(ts: Long, volume: Int, previousVolume: Int, average: Double) =>
(new DateTime(ts) -> (volume, previousVolume, average))
}
请注意,没有窗口分区的窗口函数效率很低。