Pyspark collectAsMap()UDAF替代方案-无法序列化对象:Py4JError:调用o62 .__ getstate __

时间:2019-04-02 16:59:19

标签: scala apache-spark pyspark mapreduce rdd

我正在尝试将聚合函数应用于pyspark中的列。上下文是我手头只有Spark 2.2,没有使用向量化pandas_udf

的选择
sdt = spark.createDataFrame(zip([random.randint(1,100) for x in range(20)], [random.randint(1,100) for x in range(20)]), schema=['col1', 'col2'])
+----+----+
|col1|col2|
+----+----+
|  19|  51|
|  95|  56|
|  11|  94|
|  80|  99|
|  20|  80|
|  38|  91|
|  18|  88|
|   4|  33|
+----+----+

为了并行化列,我将其转换为rdd

sdt_col_rdd = sc.parallelize(sdt.columns)

使用普通的python函数进行测试可以正常工作,并返回熊猫的数据帧

x = sdt_col_rdd.map(lambda col : (col, pd.DataFrame(np.random.randint(0,100,size=(2, 4)), columns=list('ABCD'))))
y = x.collectAsMap() #collect into dictionary with column names as key
print(y['col1']; print(y['col2']);
    A   B   C   D
0  14  55   4  57
1  36  84  53  51
    A   B   C   D
0  14  55   4  57
1  36  84  53  51

切换到spark数据框,这也是返回熊猫的df的示例函数,但是处理Spark的df并使用其本机聚合,转换,操作等:

def myFunc(df, c):
    #other more processing, aggregation, transformation may be performed here
    res = df.agg((F.min(c)-1).alias("min_"+c), (F.max(c)+1).alias("max_"+c)).toPandas()
    res["col_name"] = c
    return res

函数可以正常运行

myFunc(sdt.select('col1'), 'col1')
    min_col1    max_col1    col_name
0   4   100 col1

当我将其放入rdd地图时,就会出现问题,类似于上面所做的

x= sdt_col_rdd.map(lambda col: (col,myFunc(sdt.select(col), col)))
y = x.collectAsMap()

有没有想法如何在Spark中针对并行列而无需 udaf 来实现这种转换/动作?由于庞大的数据集,而且没有利用Spark的功能,Collect_list效率不高。

  

在处理上述异常期间,发生了另一个异常:

     

PicklingError Traceback(最近的通话)   最后)在()         1 col_map = sdt_col_rdd.map(lambda col:(col,myFunc(sdt.select(col),col)))   ----> 2 y = col_map.collectAsMap()

     collectpMap(self)中的

/data/2/parcels/SPARK2-2.2.0.cloudera4-1.cdh5.13.3.p0.603055/lib/spark2/python/pyspark/rdd.py 1555 4 1556“”“   -> 1557 return dict(self.collect())1558 1559 def keys(self):

     

/data/2/parcels/SPARK2-2.2.0.cloudera4-1.cdh5.13.3.p0.603055/lib/spark2/python/pyspark/rdd.py在collect(self)中       794“”“       795以SCCallSiteSync(self.context)作为CSS:   -> 796 sock_info = self.ctx._jvm.PythonRDD.collectAndServe(self._jrdd.rdd())       797返回列表(_load_from_socket(sock_info,self._jrdd_deserializer))       798

     

/data/2/parcels/SPARK2-2.2.0.cloudera4-1.cdh5.13.3.p0.603055/lib/spark2/python/pyspark/rdd.py in _jrdd(self)2440 2441 wrapd_func =   _wrap_function(self.ctx,self.func,self._prev_jrdd_deserializer,   -> 2442 self._jrdd_deserializer,profiler)2443 python_rdd =   self.ctx._jvm.PythonRDD(self._prev_jrdd.rdd(),包装的功能,2444
  self.preservesPartitioning)

     _wrap_function中的

/data/2/parcels/SPARK2-2.2.0.cloudera4-1.cdh5.13.3.p0.603055/lib/spark2/python/pyspark/rdd.py(sc,func,反序列化器,序列化器,分析器)
  2373断言序列化器,“序列化器不应为空” 2374
  命令=(func,探查器,解串器,序列化器)   -> 2375 pickled_command,broadcast_vars,env,include = _prepare_for_python_RDD(sc,command)2376 return sc._jvm.PythonFunction(bytearray(pickled_command),env,includes,   sc.pythonExec,2377 sc.pythonVer,   broadcast_vars,sc._javaAccumulator)

     _prepare_for_python_RDD(sc,command)中的

/data/2/parcels/SPARK2-2.2.0.cloudera4-1.cdh5.13.3.p0.603055/lib/spark2/python/pyspark/rdd.py 2359#序列化   命令将被广播2360压缩=   CloudPickleSerializer()   -> 2361 pickled_command = ser.dumps(命令)2362,如果len(pickled_command)>(1 << 20):#1M 2363#   广播将具有与创建的PythonRDD相同的生命周期

     

/data/2/parcels/SPARK2-2.2.0.cloudera4-1.cdh5.13.3.p0.603055/lib/spark2/python/pyspark/serializers.py   在转储中(self,obj)       462       463 def dumps(自己,obj):   -> 464返回cloudpickle.dumps(obj,2)       465       466

     

/data/2/parcels/SPARK2-2.2.0.cloudera4-1.cdh5.13.3.p0.603055/lib/spark2/python/pyspark/cloudpickle.py   在转储中(obj,protocol)       702       703 cp = CloudPickler(文件,协议)   -> 704 cp.dump(obj)       705       706返回file.getvalue()

     

/data/2/parcels/SPARK2-2.2.0.cloudera4-1.cdh5.13.3.p0.603055/lib/spark2/python/pyspark/cloudpickle.py   在转储中(self,obj)       160 msg =“无法序列化对象:%s:%s”%(例如,名称,emsg)       161 print_exec(sys.stderr)   -> 162提高pickle.PicklingError(msg)       163       164 def save_memoryview(self,obj):

     

PicklingError:无法序列化对象:Py4JError:错误   发生在调用o62。 getstate 时。跟踪:py4j.Py4JException:   方法 getstate ([])在以下位置不存在   py4j.reflection.ReflectionEngine.getMethod(ReflectionEngine.java:318)     在   py4j.reflection.ReflectionEngine.getMethod(ReflectionEngine.java:326)     在py4j.Gateway.invoke(Gateway.java:274)处   py4j.commands.AbstractCommand.invokeMethod(AbstractCommand.java:132)     在py4j.commands.CallCommand.execute(CallCommand.java:79)处   py4j.GatewayConnection.run(GatewayConnection.java:238)在   java.lang.Thread.run(Thread.java:748)

1 个答案:

答案 0 :(得分:-1)

似乎您没有注册udf,导入udf函数并按如下所示注册udf,这应该可以。

从pyspark.sql.functions导入*

myFunc = udf(myFunc,StringType())