火花时间系列 - 定制组按10分钟间隔:提高性能

时间:2016-06-13 09:32:53

标签: time apache-spark pyspark series

我们有时间序列数据(自1970年以来我们的时间戳和整数数据值):

# load data and cache it
df_cache = readInData() # read data from several files (paritioned by hour)
df_cache.persist(pyspark.StorageLevel.MEMORY_AND_DISK)
df_cache.agg({"data": "max"}).collect()

# now data is cached
df_cache.show()
+--------------------+---------+
|                time|     data| 
+--------------------+---------+
|1.448409599861109E15|1551.7468|
|1.448409599871109E15|1551.7463|
|1.448409599881109E15|1551.7468|

现在我们想要使用外部python库在10分钟时间窗口之上计算一些非平凡的事情。为此,我们需要在内存中加载每个时间帧的数据,应用外部函数并存储结果。因此,无法使用用户定义的聚合函数(UDAF)。

现在的问题是,当我们将GroupBy应用于RDD时,它非常慢。

df_cache.rdd.groupBy(lambda x: int(x.time / 600e6) ). \ # create 10 minute groups
             map(lambda x: 1). \ # do some calculations, e.g. external library
             collect() # get results

此操作需要在两个节点上获得120Mio样本(100Hz数据),其中6GB Ram大约需要14分钟。 groupBy阶段的Spark详细信息:

Total Time Across All Tasks: 1.2 h
Locality Level Summary: Process local: 8
Input Size / Records: 1835.0 MB / 12097
Shuffle Write: 1677.6 MB / 379
Shuffle Spill (Memory): 79.4 GB
Shuffle Spill (Disk): 1930.6 MB

如果我使用一个简单的python脚本并让它迭代输入文件,那么完成的时间就会缩短。

如何在火花中优化这项工作?

1 个答案:

答案 0 :(得分:1)

groupBy是你的瓶颈:它需要在所有分区中对数据进行洗牌,这非常耗时并且在内存中占用了大量空间,正如您从指标中看到的那样。

这里的方法是使用reduceByKey操作并将其链接如下: df_cache.rdd.map(lambda x: (int(x.time/600e6), (x.time, x.data) ).reduceByKey(lambda x,y: 1).collect()

这里的关键点是groupBy需要在所有分区中混洗所有数据,而reduceByKey将首先在每个分区上减少,然后在所有分区上减少 - 大大减少了全球洗牌。请注意我是如何将输入组织到密钥中以利用reduceByKey操作的。

正如我在评论中提到的那样,您可能还希望通过使用Spark SQL的DataFrame抽象来尝试您的程序,这可以通过其优化器为您提供额外的提升。