Pyspark 无法序列化调用外部web服务的Databricks UDF(PicklingError)

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时,

我使用的是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并模拟返回值时,它仍然有效

底部错误

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):#默认值1M
2465#广播的生命周期与创建的生命周期相同 蟒蛇

/转储中的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。