我有一个主要基于Python的笔记本,现在我想集成一些Scala UDF功能(出于性能原因实际上是从Python移植的)
这些UDF大量使用Python映射,因此我需要一种将这些映射从Python导入JVM的方法。我不是天生的Scala专家,我天真的认为我可以在程序包中编写一个Scala类,然后从Python使用它:
%scala
package com.scalatest
import org.apache.spark.sql.expressions.UserDefinedFunction
import org.apache.spark.sql.functions._
import org.apache.spark.sql.DataFrame
import collection.mutable.HashMap
import org.apache.spark.api.java.JavaSparkContext
import org.apache.spark.sql.functions._
class ScalaSparkTest(jsc: JavaSparkContext, lookups:
java.util.HashMap[String,String]) extends Serializable
{
val lookup = lookups
// val lookup_bc = JavaSparkContext.toSparkContext(jsc).broadcast(lookups)
def lookupUdf = udf((c: String) => lookup(c))
def lookupTest(df: DataFrame, input_col: String, output_col: String):
DataFrame = {
return df.withColumn(output_col, lookupUdf(col(input_col)))
}
}
还有Python:
from pyspark.sql import Row, Column, DataFrame
rows = []
lookups = {}
for i in range(10):
c = str(i)
lookups[c] = str(i*2)
rows.append( (c,c) )
df = spark.createDataFrame(rows,['A','B'])
scalaTest = sc._jvm.com.scalatest.ScalaSparkTest(sc._jsc, lookups)
scalaTest.printType()
results = DataFrame(scalaTest.lookupTest(df._jdf,'A','C'),sqlContext)
results.show()
# ==> This is how i do it in Python
lookups_bc = sc.broadcast(lookups)
@pandas_udf(LongType())
def udf_pandas(c):
return c.map(lookups_bc.value)
result = df.select("C", udf_pandas("A"))
现在,这一切都可以按预期工作,但是可以序列化整个类。我不想这样做,我只想传递我的查询并广播它们,而不必每次都向整个班级发送。
鉴于我拥有的代码,我该如何更改它,以便我只能广播查找内容,然后可以在UDF中使用它?在Python中,通过使用全局变量保存广播并让闭包对其进行排序,可以轻松实现这一点。使用Scala,包和类,我不知道如何获得所需的行为,因此欢迎任何示例。
注意::我知道查找可以作为内置函数使用,但用例比示例代码复杂。
更新:响应重复标记。我没有从PySpark调用Scala的问题,我不知道该怎么做是从PySpark在Scala中创建一个广播变量,然后可将其提供给软件包中的UDF。我有一个地图的Python列表,我希望这些地图在Scala中广播,然后可以通过我的UDF访问广播变量。我不知道如何构造我的Scala和/或与Python的交互