pyspark:从pyspark调用自定义java函数。我需要Java_Gateway吗?

时间:2016-02-28 19:58:11

标签: java python apache-spark pyspark py4j

我编写了以下MyPythonGateway.java,以便我可以从Python调用我的自定义java类:

public class MyPythonGateway {

    public String findMyNum(String input) {
        return MyUtiltity.parse(input).getMyNum(); 
    }

    public static void main(String[] args) {
        GatewayServer server = new GatewayServer(new MyPythonGateway());
        server.start();
    }
}

以下是我在Python代码中使用它的方法:

def main():

    gateway = JavaGateway()                   # connect to the JVM
    myObj = gateway.entry_point.findMyNum("1234 GOOD DAY")
    print(myObj)


if __name__ == '__main__':
    main()

现在我想使用PySpark中的MyPythonGateway.findMyNum()函数,而不仅仅是一个独立的python脚本。我做了以下事情:

myNum = sparkcontext._jvm.myPackage.MyPythonGateway.findMyNum("1234 GOOD DAY")
print(myNum)

但是,我收到以下错误:

... line 43, in main:
myNum = sparkcontext._jvm.myPackage.MyPythonGateway.findMyNum("1234 GOOD DAY")
  File "/home/edamameQ/spark-1.5.2/python/lib/py4j-0.8.2.1-src.zip/py4j/java_gateway.py", line 726, in __getattr__
py4j.protocol.Py4JError: Trying to call a package.

那我在这里想念的是什么?我不知道在使用pyspark时是否应该运行MyPythonGateway的单独JavaApplication来启动网关服务器。请指教。谢谢!

以下是我的需要:

input.map(f)

def f(row):
   // call MyUtility.java 
   // x = MyUtility.parse(row).getMyNum()
   // return x

最好的方法是什么?谢谢!

4 个答案:

答案 0 :(得分:3)

首先,您看到的错误通常意味着您尝试使用的课程无法访问。所以很可能是CLASSPATH问题。

关于一般概念,有两个重要问题:

  • 您无法在动作或转换中访问SparkContext,因此使用PySpark网关无法正常工作(有关详细信息,请参阅How to use Java/Scala function from an action or a transformation?))。如果你想使用工人的Py4J,你必须在每台工人机器上启动一个单独的网关。
  • 你真的不想以这种方式在Python和JVM之间传递数据。 Py4J不适用于数据密集型任务。

答案 1 :(得分:0)

在PySpark中开始调用方法之前-

myNum = sparkcontext._jvm.myPackage.MyPythonGateway.findMyNum("1234 GOOD DAY")

您必须按如下所示导入MyPythonGateway java类

java_import(sparkContext._jvm, "myPackage.MyPythonGateway")
myPythonGateway  = spark.sparkContext._jvm.MyPythonGateway()
myPythonGateway.findMyNum("1234 GOOD DAY")

使用 spark-submit

中的-jars 选项指定包含myPackage.MyPythonGateway的jar。

答案 2 :(得分:0)

例如,如果input.map(f)具有作为RDD的输入,则此方法可能会起作用,因为您无法为RDD的map函数(以及我的我)访问执行器中的JVM变量(附加到spark上下文)知识在pyspark中没有@transient lazy val的等效项。

def pythonGatewayIterator(iterator):
    results = []
    jvm = py4j.java_gateway.JavaGateway().jvm
    mygw = jvm.myPackage.MyPythonGateway()
    for value in iterator:
        results.append(mygw.findMyNum(value))
    return results


inputs.mapPartitions(pythonGatewayIterator)

答案 3 :(得分:0)

您需要做的就是编译jar并使用--jars或--driver-class-path spark提交选项将其添加到pyspark classpath中。然后使用以下代码访问类和方法-

sc._jvm.com.company.MyClass.func1()

其中sc-火花上下文

已通过Spark 2.3测试。请记住,您只能从驱动程序而不是执行程序调用JVM类方法。