Spark Scala UDAF可在n天内滚动计数

时间:2020-10-14 08:42:40

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

我正在尝试计算最近30天内相对于当前交易时间戳记的密钥出现次数。我知道我可以直接使用窗口来计算,但是对于窗口中的单个键(分区)来说,我有大量的数据,因此作业无法在我的硬件上完成。

我看到一些博客谈论UDAF。有人可以建议我怎么做,为我指出好的文章(找不到适合我所用用例的东西。比如window + UDAF

下面是我的窗口 valrollingWindow =窗口 .partitionBy(keyColumn) .orderBy(unix_timestamp) .rangeBetween(-30 24 3600,currentRow)

我无法通过其他任何键对数据进行分区,因为那时计数会出错。 任何建议将不胜感激

1 个答案:

答案 0 :(得分:0)

用UDAF实现切片窗口可能有些棘手。如果问题是分区很大,则UDAF可能存在相同的问题,因为您也需要为密钥进行汇总。

我将首先检查幻灯片窗口的问题,为什么要花这么长时间才能完成(完成?),然后再转到其他选项。您必须考虑到Spark SQL优化可提高内存/ CPU /存储效率,因此,先验地使用UDAF使用JVM类型处理数据不会提高性能。

如果分区太大,则可以尝试在RDD和mapPartitions中进行迭代器转换。迭代器是一种访问元素集合的方法。迭代器不会将整个元素集合全部加载到内存中。相反,迭代器一个接一个地加载元素。”

您可以对mapPartitions使用迭代器到迭代器的转换。这里的要点是,您应该首先从这些分区构建一个RDD并应用功能mapPartition:

// AN example of pair RDD
val rdd : RDD[(Int, Array[Double])] = ???

rdd.mapPartitions { iterator : Iterator[(Int, Array[Double])] =>
  // Read the elements one by one with the next method
  // 
  iterator.map(el => (el, windowFunction(buffer))
}

请注意,如果将迭代器加载到类似List的集合中,则会遇到相同的内存问题。因此,您需要使用迭代器的map函数执行聚合函数,并在另一个迭代器中转换此迭代器。另一个问题是,按日期范围执行函数可能会更加困难,因为您只能读取一次迭代器,因此您需要进行处理。