将Scala类用作带有pyspark的UDF

时间:2018-04-03 14:04:13

标签: scala apache-spark pyspark apache-spark-sql user-defined-functions

我正在尝试使用Apache Spark将一些计算从Python卸载到Scala。我想使用Java中的类接口来使用持久变量,就像这样(这是一个基于我更复杂的用例的无意义的MWE):

import pyspark
from pyspark.sql import SQLContext
from pyspark import SparkContext

conf = pyspark.SparkConf()
conf.set("spark.jars", "mwe.jar")
sc = SparkContext.getOrCreate(conf)

sqlContext = SQLContext.getOrCreate(sc)
sqlContext.registerJavaFunction("fun", "mwe.SomeFun")

df0 = sc.parallelize((i,) for i in range(6)).toDF(["num"])
df1 = df0.selectExpr("fun(num) + 3 as new_num")
df1.show()

现在我正试图在pyspark中使用这个类:

pyspark.sql.utils.AnalysisException: u"cannot resolve '(UDF:fun(num) + 3)' due to data type mismatch: differing types in '(UDF:fun(num) + 3)' (struct<> and int).; line 1 pos 0;\n'Project [(UDF:fun(num#0L) + 3) AS new_num#2]\n+- AnalysisBarrier\n      +- LogicalRDD [num#0L], false\n"

并获得以下例外:

composer require magestore/storelocator-magento2

实现这个的正确方法是什么?我是否必须在课堂上使用Java本身?我非常感谢提示!

1 个答案:

答案 0 :(得分:3)

异常的来源是使用不兼容的类型:

  • 首先,o.a.s.sql.api.java.UDF*个对象需要外部Java(不是Scala类型),因此UDF期望整数应该装箱Integerjava.lang.Integer)而不是Int

    class SomeFun extends UDF1[Integer, Integer] {
      ...
      override def call(input: Integer): Integer = {
        ...
    
  • 除非您使用num而非LongType的旧版IntegerType列使用:

    df0.printSchema()
    root
     |-- num: long (nullable = true)
    

    所以实际的签名应该是

    class SomeFun extends UDF1[java.lang.Long, java.lang.Long] {
      ...
      override def call(input: java.lang.Long): java.lang.Long = {
        ...
    

    或应在应用UDF

    之前投放数据   
    df0.selectExpr("fun(cast(num as integer)) + 3 as new_num")
    

最后,UDF中不允许使用可变状态。它不会导致异常,但总体行为将是不确定的。