是否可以在Python中扩展Spark的RDD以添加自定义运算符?如果不可能,那么如何为扩展RDD的类包装Scala代码,例如: http://blog.madhukaraphatak.com/extending-spark-api/
编辑:我正在尝试创建一个新的RDD,比如PersonRDD并在PersonRDD上添加一组新的运算符,例如。 PersonRDD.computeMedianIncome()。根据下面的链接,在Python中执行此操作并非易事。但是,由于它是一个旧线程,我想知道是否有任何新的更新。如果没有,我想用Scala来做,但我不知道如何使用Py4J从Python调用该类(mail-archives.us.apache.org/mod_mbox/spark-user/201308.mbox/...)
非常感谢任何建议或帮助。
曼迪
答案 0 :(得分:4)
在分布式环境中计算精确中位数需要花费一些精力,所以假设你想要像RDD中的所有值那样平方。让我们调用这个方法squares
并假设它应该如下工作:
assert rdd.squares().collect() == rdd.map(lambda x: x * x).collect()
pyspark.RDD
定义:from pyspark import RDD
def squares(self):
return self.map(lambda x: x * x)
RDD.squares = squares
rdd = sc.parallelize([1, 2, 3])
assert rdd.squares().collect() == [1, 4, 9]
注意:如果修改类定义,则每个实例都可以访问squares
。
class RDDWithSquares(RDD):
def squares(self):
return self.map(lambda x: x * x)
rdd = sc.parallelize([1, 2, 3])
rdd.__class__ = RDDWithSquares # WARNING: see a comment below
分配一个类是一个肮脏的黑客,所以在实践中你应该以适当的方式创建一个RDD(参见例如context.parallelize实现)。
import types
rdd = sc.parallelize([1, 2, 3])
# Reusing squares function defined above
rdd.squares = types.MethodType(squares, rdd)
首先,我没有对这些问题进行过长时间的测试,以确保没有任何隐藏的问题。
此外,我认为这不值得大惊小怪。如果没有静态类型检查,很难找到任何好处,您可以使用函数,currying和pipes
以更清晰的方式获得类似的结果。
from toolz import pipe
pipe(
sc.parallelize([1, 2, 3]),
squares,
lambda rdd: rdd.collect())
答案 1 :(得分:0)
我有一个类似的问题,虽然我还没有在我的扩展版本上测试普通RDD的全部功能,但它仍然按预期工作。它确实需要一些工作,我不确定这是否是最佳解决方案,但我正在做的只是扩展RDD类,重新实现返回新RDD的方法,方法是将它们传递给新类和类的添加方法。以下是代码的一小部分:
from pyspark.rdd import RDD, PipelinedRDD
class CustomRDD(RDD):
def __init__(self, rdd, first=True):
if first:
rdd = custom_parser(rdd)
self._jrdd = rdd._jrdd
self.is_cached = rdd.is_cached
self.is_checkpointed = rdd.is_checkpointed
self.ctx = rdd.ctx
self._jrdd_deserializer = rdd._jrdd_deserializer
self._id = rdd._id
self.partitioner = rdd.partitioner
def mapPartitionsWithIndex(self, f, preservesPartition=False):
return CustomRDD(PipelinedRDD(self, f, preservesPartition), False)
def union(self, other):
return WebtrendsRDD(super(WebtrendsRDD, self).union(other), False)
def custom_method(self):
return CustomRDD(self.filter(lambda x: x.has_property()), False)
mapPartitionsWithIndex方法被许多其他RDD功能调用,因此覆盖了很多,但是还有很多其他方法需要用你自己的构造函数来包装,以便像我使用union一样回到你自己的CustomRDD