Pyspark 无法序列化调用外部web服务的Databricks UDF(PicklingError)
我使用的是DataRicks,数据框中有一列,我需要通过外部web服务调用为每个记录更新该列。在本例中,它使用Azure机器学习服务SDK并执行服务调用。这段代码在spark中不作为UDF运行(即python)时运行良好,但是当我尝试将其作为UDF调用时,它会抛出一个序列化错误。如果使用lambda和带有rdd的映射,也会发生同样的情况 该模型使用fastText,可以通过普通http调用或使用AMLS的WebService SDK从Postman或python中很好地调用-只有当它是UDF时,它才会失败,并显示以下消息: TypeError:无法pickle\u线程。\u本地对象 我能想到的唯一解决方法是按顺序遍历数据帧中的每条记录,并用调用更新记录,但是这不是很有效。我不知道这是spark错误还是因为服务正在加载fasttext模型。当我使用UDF并模拟返回值时,它仍然有效 底部错误Pyspark 无法序列化调用外部web服务的Databricks UDF(PicklingError),pyspark,user-defined-functions,pickle,azure-databricks,azure-machine-learning-service,Pyspark,User Defined Functions,Pickle,Azure Databricks,Azure Machine Learning Service,我使用的是DataRicks,数据框中有一列,我需要通过外部web服务调用为每个记录更新该列。在本例中,它使用Azure机器学习服务SDK并执行服务调用。这段代码在spark中不作为UDF运行(即python)时运行良好,但是当我尝试将其作为UDF调用时,它会抛出一个序列化错误。如果使用lambda和带有rdd的映射,也会发生同样的情况 该模型使用fastText,可以通过普通http调用或使用AMLS的WebService SDK从Postman或python中很好地调用-只有当它是UDF时,
from azureml.core.webservice import Webservice, AciWebservice
from azureml.core import Workspace
def predictModelValue2(summary, modelName, modelLabel):
raw_data = '[{"label": "' + modelLabel + '", "model": "' + modelName + '", "as_full_account": "' + summary + '"}]'
prediction = service.run(raw_data)
return prediction
from pyspark.sql.types import FloatType
from pyspark.sql.functions import udf
predictModelValueUDF = udf(predictModelValue2)
DVIRCRAMFItemsDFScored1 = DVIRCRAMFItemsDF.withColumn("Result", predictModelValueUDF("Summary", "ModelName", "ModelLabel"))
TypeError:无法pickle\u线程。\u本地对象
在处理上述异常期间,发生了另一个异常:
PicklingError回溯(最近的调用
最后)在
---->2 x=df.withColumn(“结果”),predictModelValueUDF(“摘要”,
“模型名称”、“模型标签”))
/包装器中的databricks/spark/python/pyspark/sql/udf.py(*args)
194@functools.wrapps(self.func,assigned=assignments)
195 def包装(*参数):
-->196返回自(*args)
197
198包装器。名称=self.\u名称
/调用中的databricks/spark/python/pyspark/sql/udf.py(self,*cols)
172
173 def呼叫(self,*cols):
-->174 judf=自我
175 sc=SparkContext.\u活动\u spark\u上下文
176返回列(judf.apply(_to_seq(sc,cols,_to_java_列)))
/databricks/spark/python/pyspark/sql/udf.py in_judf(self)
156#并且应该对性能影响最小。
157如果self.\u judf\u占位符为无:
-->158 self.\u judf\u占位符=self.\u create\u judf()
159返回自我。\u judf\u占位符
一百六十
/创建judf(self)中的databricks/spark/python/pyspark/sql/udf.py
165 sc=spark.sparkContext
166
-->167 wrapped_func=_wrapp_函数(sc,self.func,self.returnType)
168 jdt=spark.\u jsparkSession.parseDataType(self.returnType.json())
169 judf=sc.\u jvm.org.apache.spark.sql.execution.python.UserDefinedPythonFunction(
/函数中的databricks/spark/python/pyspark/sql/udf.py(sc,
func,returnType)
33定义包装函数(sc、func、returnType):
34命令=(func,returnType)
--->35 pickled_命令,broadcast_vars,env,includes=_prepare_for_python_RDD(sc,command)
36返回sc._jvm.python函数(bytearray(pickled_命令),env,includes,sc.pythonExec,
37 sc.pythonVer,广播公司,sc.(蓄能器公司)
/databricks/spark/python/pyspark/rdd.py在为python的rdd(sc,
命令)2461#序列化命令将由
广播2462 ser=CloudPickerSerializer()
->2463 pickled_command=如果len(pickled_command)>
sc.#ujvm.PythonUtils.getBroadcastThreshold(sc.#uJSC):#默认值1M2465#广播的生命周期与创建的生命周期相同 蟒蛇 /转储中的databricks/spark/python/pyspark/serializers.py(self,obj) 709 msg=“无法序列化对象:%s:%s”%(例如类名称,emsg) 710 cloudpickle.print_exec(sys.stderr) -->711升高腌菜。腌菜错误(味精) 712 713 PicklingError:无法序列化对象:TypeError:无法pickle _线程。\u本地对象
我不擅长DataBricks或Spark,但是当您接触复杂对象(如
服务
对象)时,从本地笔记本上下文中清除函数总是有问题的。在这种特殊情况下,我建议删除对azureML服务
对象的依赖,只需使用请求
调用服务
从维修中拔出钥匙:
# retrieve the API keys. two keys were generated.
key1, key2 = service.get_keys()
scoring_uri = service.scoring_uri
您应该能够在UDF中直接使用这些字符串,而不存在酸洗问题——即如何仅通过请求调用服务。下面应用于您的UDF:
import requests, json
def predictModelValue2(summary, modelName, modelLabel):
input_data = json.dumps({"summary": summary, "modelName":, ....})
headers = {'Content-Type':'application/json', 'Authorization': 'Bearer ' + key1}
# call the service for scoring
resp = requests.post(scoring_uri, input_data, headers=headers)
return resp.text[1]
不过,在一个侧节点上:您的UDF将针对数据帧中的每一行被调用,并且每次它都会进行网络调用——这将非常缓慢。我建议您寻找批处理执行的方法。正如您从构建的json
服务中所看到的那样。run
将接受一个项目数组,因此您应该以100秒的时间批处理它或者是这样。如果直接调用predictModelValue2函数(不带spark),那么从该函数返回的变量预测的类型是什么?如果它不是字符串,那么您可能需要在udf声明中相应地提供它。预测是一个浮点值-我将明确地尝试它,谢谢,这是我一直在考虑的事情-切换到请求库而不是使用SDK…但是我没有想到使用SDK来获取密钥和URL-这是正确的好主意。是的,我同意,这并不理想!我想我可能需要改变我的方法,切换到azure函数或异步运行它们。啊,我也不知道我可以将它们作为批传递-这是另一个好主意,ta。