我想减少每个reducer的记录数,并将结果变量保持为rdd
使用takeSample
似乎是明显的选择,但它会返回collection
而不是SparkContext
对象。
我想出了这个方法:
rdd = rdd.zipWithIndex().filter(lambda x:x[1]<limit).map(lambda x:x[0])
然而,这种方法非常慢且效率不高。
是否有更智能的方法来获取小样本并使数据结构保持rdd
?
答案 0 :(得分:3)
您需要一个小示例子集,并且无法对数据做出任何其他假设,那么take
与parallelize
相结合可能是最佳解决方案:
sc.parallelize(rdd.take(n))
它将触及相对较少数量的分区(在最佳情况下只有一个),并且小 n 的网络流量成本应该可以忽略不计。
抽样(randomSplit
或sample
)需要与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 []
)
如果数据可以表示为Row
,您可以尝试另一种技巧:
rdd.toDF().limit(n).rdd