方式一:启动进程执行python脚本
// method1: launch local runtime process to exec python file
// just exec file
val proc1 = Runtime.getRuntime().exec("python src/test.py")
proc1.waitFor()
// exec with parameters
val proc2 = Runtime.getRuntime().exec("python src/test.py 8 9")
proc2.waitFor()
其中:
- 可以在命令行中带参数
- 本地python环境中的第三方扩展包可以正常使用
方法2:用Jpython来调用
Jpython(http://www.jython.org/)是一个java的扩展包,在scala里面可以直接调用。
首先将Jpyhon standaone的jar文件导入到scala工程并引用
import org.python.core.{PyFunction, PyInteger, PyObject}
import org.python.util.PythonInterpreter
// method2: use Jpython module
val interpreter = new PythonInterpreter()
// exec python code
interpreter.exec("print 'hello jpython'")
// exec python file in JVM
val py_file = new FileInputStream("src/test.py")
interpreter.execfile(py_file)
py_file.close()
// call python funtion and return result (oops: work in java but not in scala ~)
// val a = 15
// val b = 17
// val func = interpreter.get("addNum", PyFunction.class).asInstanceOf[PyFunction]
// val pyobj = func.__call__(new PyInteger(a), new PyInteger(b))
// println(pyobj.toString())
其中:
- 用Jpython理论上可以用三种方式调用python:执行语句,执行文件,调用函数,但是由于莫名其妙的原因,scala中call python的函数不能用
- 用Jpython的方式无法使用python本地安装的第三方扩展包,因为Jpython运行在JVM上
- 这种方式不建议使用
方式三:
通过查看 pySpark 的原理,可以通过 Socket 进行 Java/Scala 与 python 间的数据通信,实现耦合并且各自运行对应的代码;
其中 py4j 是比较好的实现方式:
Py4J enables Python programs running in a Python interpreter to dynamically access Java objects in a Java Virtual Machine. Methods are called as if the Java objects resided in the Python interpreter and Java collections can be accessed through standard Python collection methods. Py4J also enables Java programs to call back Python objects.
Py4J 是一个用 Python 和 Java 编写的库。
通过 Py4J,Python程序 能够动态访问 Java虚拟机 中的 Java对象,Java程序 也能够回调 Python对象
- Python 代码
>>> from py4j.java_gateway import JavaGateway
>>> gateway = JavaGateway() # connect to the JVM
>>> random = gateway.jvm.java.util.Random() # create a java.util.Random instance
>>> number1 = random.nextInt(10) # call the Random.nextInt method
>>> number2 = random.nextInt(10)
>>> print(number1, number2)
(2, 7)
>>> addition_app = gateway.entry_point # get the AdditionApplication instance
>>> value = addition_app.addition(number1, number2)) # call the addition method
>>> print(value)
9
- Java 代码
import py4j.GatewayServer;
public class AdditionApplication {
public int addition(int first, int second) {
return first + second;
}
public static void main(String[] args) {
AdditionApplication app = new AdditionApplication();
// app is now the gateway.entry_point
GatewayServer server = new GatewayServer(app);
server.start();
}
}
综上,采用方式一和方式三是比较可取的,其中方式三在 spark 所提供的 pySpark 有所应用,可借鉴。但方式三的相关可参考资料目前相对少,难度大。