限制spark上下文中的记录数量

时间:2016-03-08 15:14:07

标签: python hadoop apache-spark pyspark rdd

我想减少每个reducer的记录数,并将结果变量保持为rdd

使用takeSample似乎是明显的选择,但它会返回collection而不是SparkContext对象。

我想出了这个方法:

rdd = rdd.zipWithIndex().filter(lambda x:x[1]<limit).map(lambda x:x[0])

然而,这种方法非常慢且效率不高。

是否有更智能的方法来获取小样本并使数据结构保持rdd

1 个答案:

答案 0 :(得分:3)

您需要一个示例子集,并且无法对数据做出任何其他假设,那么takeparallelize相结合可能是最佳解决方案:

sc.parallelize(rdd.take(n))

它将触及相对较少数量的分区(在最佳情况下只有一个),并且小 n 的网络流量成本应该可以忽略不计。

抽样(randomSplitsample)需要与zipWithIndex filter完全相同的完整数据扫描。

假设没有数据偏差,你可以尝试这样的方法来解决这个问题:

from __future__ import division  # Python 2 only

def limitApprox(rdd, n, timeout):
    count = rdd.countApprox(timeout)
    if count <= n:
        return rdd
    else:
        rec_per_part = count // rdd.getNumPartitions()
        required_parts = n / rec_per_part if rec_per_part else 1
        return rdd.mapPartitionsWithIndex(
            lambda i, iter: iter if i < required_parts else []
        )
  • 这仍将访问每个分区,但如果没有必要,将尝试避免计算内容
  • 如果存在大量数据偏差,
  • 无法工作
      如果分布均匀但是<&lt;&lt;&lt;&lt;而不是每个分区的平均记录数。 如果分布偏向高指数,
    • 可能会低估。

如果数据可以表示为Row,您可以尝试另一种技巧:

rdd.toDF().limit(n).rdd