在Spark Scala/Java应用中调用Python脚本,会么?
摘要:本文将介绍如何在 Spark scala 程序中调用 Python 脚本,Spark java程序调用的过程也大体相同。
本文分享自华为云社区《【Spark】如何在Spark Scala/Java应用中调用Python脚本》,作者: 小兔子615 。
1.PythonRunner
对于运行与 JVM 上的程序(即Scala、Java程序),Spark 提供了 PythonRunner 类。只需要调用PythonRunner 的main方法,就可以在Scala或Java程序中调用Python脚本。在实现上,PythonRunner 基于py4j ,通过构造GatewayServer实例让python程序通过本地网络socket来与JVM通信。
// Launch a Py4J gateway server for the process to connect to; this will let it see our
// Java system properties and such
val localhost = InetAddress.getLoopbackAddress()
val gatewayServer = new py4j.GatewayServer.GatewayServerBuilder()
.authToken(secret)
.javaPort(0)
.javaAddress(localhost)
.callbackClient(py4j.GatewayServer.DEFAULT_PYTHON_PORT, localhost, secret)
.build()
val thread = new Thread(new Runnable() {
override def run(): Unit = Utils.logUncaughtExceptions {
gatewayServer.start()
}
})
thread.setName("py4j-gateway-init")
thread.setDaemon(true)
thread.start() // Wait until the gateway server has started, so that we know which port is it bound to.
// `gatewayServer.start()` will start a new thread and run the server code there, after
// initializing the socket, so the thread started above will end as soon as the server is
// ready to serve connections.
thread.join()
在启动GatewayServer后,再通过ProcessBuilder构造子进程执行Python脚本,等待Python脚本执行完成后,根据exitCode判断是否执行成功,若执行失败则抛出异常,最后关闭gatewayServer。
// Launch Python process
val builder = new ProcessBuilder((Seq(pythonExec, formattedPythonFile) ++ otherArgs).asJava)
try {
val process = builder.start() new RedirectThread(process.getInputStream, System.out, "redirect output").start() val exitCode = process.waitFor()
if (exitCode != 0) {
throw new SparkUserAppException(exitCode)
}
} finally {
gatewayServer.shutdown()
}
2.调用方法
2.1 调用代码
PythonRunner的main方法中需要传入三个参数:
- pythonFile:执行的python脚本
- pyFiles:需要添加到PYTHONPATH的其他python脚本
- otherArgs:传入python脚本的参数数组
val pythonFile = args(0)
val pyFiles = args(1)
val otherArgs = args.slice(2, args.length)
具体样例代码如下,scala样例代码:
package com.huawei.bigdata.spark.examples import org.apache.spark.deploy.PythonRunner
import org.apache.spark.sql.SparkSession object RunPythonExample {
def main(args: Array[String]) {
val pyFilePath = args(0)
val pyFiles = args(1)
val spark = SparkSession
.builder()
.appName("RunPythonExample")
.getOrCreate() runPython(pyFilePath, pyFiles) spark.stop()
} def runPython(pyFilePath: String, pyFiles :String) : Unit = {
val inputPath = "-i /input"
val outputPath = "-o /output"
PythonRunner.main(Array(pyFilePath, pyFiles, inputPath, outputPath))
}
}
python样例代码:
#!/usr/bin/env python
# coding: utf-8
import sys
import argparse argparser = argparse.ArgumentParser(description="ParserMainEntrance")
argparser.add_argument('--input', '-i', help="input path", default=list(), required=True)
argparser.add_argument('--output', '-o', help="output path", default=list(), required=True)
arglist = argparser.parse_args() def getTargetPath(input_path, output_path):
try:
print("input path: {}".format(input_path))
print("output path: {}".format(output_path))
return True
except Exception as ex:
print("error with: {}".format(ex))
return False if __name__ == "__main__":
ret = getTargetPath(arglist.input, arglist.output)
if ret:
sys.exit(0)
else:
sys.exit(1)
2.2 运行命令
执行python脚本需要设置pythonExec,即执行python脚本所使用的执行环境。默认情况下,使用的执行器为python(Spark 2.4 及以下)或 python3 (Spark 3.0 及以上)。
//Spark 2.4.5
val sparkConf = new SparkConf()
val secret = Utils.createSecret(sparkConf)
val pythonExec = sparkConf.get(PYSPARK_DRIVER_PYTHON)
.orElse(sparkConf.get(PYSPARK_PYTHON))
.orElse(sys.env.get("PYSPARK_DRIVER_PYTHON"))
.orElse(sys.env.get("PYSPARK_PYTHON"))
.getOrElse("python") //Spark 3.1.1
val sparkConf = new SparkConf()
val secret = Utils.createSecret(sparkConf)
val pythonExec = sparkConf.get(PYSPARK_DRIVER_PYTHON)
.orElse(sparkConf.get(PYSPARK_PYTHON))
.orElse(sys.env.get("PYSPARK_DRIVER_PYTHON"))
.orElse(sys.env.get("PYSPARK_PYTHON"))
.getOrElse("python3")
如果要手动指定pythonExec,需要在执行前设置环境变量(无法通过spark-defaults传入)。在cluster模式下,可以通过 --conf “spark.executorEnv.PYSPARK_PYTHON=python3” --conf “spark.yarn.appMasterEnv.PYSPARK_PYTHON=python3” 设置。driver端还可以通过export PYSPARK_PYTHON=python3 设置环境变量。
若需要上传pyhton包,可以通过 --archive python.tar.gz 的方式上传。
为了使应用能够获取到py脚本文件,还需要在启动命令中添加 --file pythonFile.py 将python脚本上传到 yarn 上。
运行命令参考如下:
spark-submit --master yarn --deploy-mode cluster --class com.huawei.bigdata.spark.examples.RunPythonExample --files /usr/local/test.py --conf "spark.executorEnv.PYSPARK_PYTHON=python3" --conf "spark.yarn.appMasterEnv.PYSPARK_PYTHON=python3" /usr/local/test.jar test.py test.py
如果需要使用其他python环境,而非节点上已安装的,可以通过 --archives 上传python压缩包,再通过环境变量指定pythonExec,例如:
spark-submit --master yarn --deploy-mode cluster --class com.huawei.bigdata.spark.examples.RunPythonExample --files /usr/local/test.py --archives /usr/local/python.tar.gz#myPython --conf "spark.executorEnv.PYSPARK_PYTHON=myPython/bin/python3" --conf "spark.yarn.appMasterEnv.PYSPARK_PYTHON=myPython/bin/python3" /usr/local/test.jar test.py test.py
在Spark Scala/Java应用中调用Python脚本,会么?的更多相关文章
- Mac笔记本中是用Idea开发工具在Java项目中调用python脚本遇到的环境变量问题解决
问题描述: mac笔记本本身会自带几个python版本,比如python2.7版本,我没有改动mac默认的python版本,只是安装了python3.7版本. 使用Pycharm开发Python项目没 ...
- Java程序中调用Python脚本的方法
在程序开发中,有时候需要Java程序中调用相关Python脚本,以下内容记录了先关步骤和可能出现问题的解决办法. 1.在Eclipse中新建Maven工程: 2.pom.xml文件中添加如下依赖包之后 ...
- C++中调用Python脚本
C++中调用Python脚本的意义就不讲了,至少你可以把它当成文本形式的动态链接库, 需要的时候还可以改一改,只要不改变接口, C++的程序一旦编译好了,再改就没那么方便了 先看Python的代码 代 ...
- C++中调用Python脚本(转载)
转载▼ 标签: 杂谈 C++中调用Python脚本的意义就不讲了,至少你可以把它当成文本形式的动态链接库,需要的时候还可以改一改,只要不改变接口, C++的程序一旦编译好了,再改就没那么方便了先看Py ...
- c++中调用python脚本提示 error LNK2001: 无法解析的外部符号 __imp_Py_Initialize等错误的解决方法
最近项目中需要实现一个服务器宕机后短信提醒的功能,个人觉得在使用Python 写http请求这块很方便,发短信这块就使用了python,但是c++程序中调用这个脚本时,编译不通过,提示如下错误: er ...
- 使用Runtime.getRuntime().exec()在java中调用python脚本
举例有一个Python脚本叫test.py,现在想要在Java里调用这个脚本.假定这个test.py里面使用了拓展的包,使得pythoninterpreter之类内嵌的编译器无法使用,那么只能采用ja ...
- python爬虫简单实现,并在java中调用python脚本,将数据保存在json文件中
# coding:utf-8 import urllib2 from bs4 import BeautifulSoup import json import sys reload(sys) sys.s ...
- 通过Java调用Python脚本
在进行开发的过程中,偶尔会遇到需要使用Java调用Python脚本的时候,毕竟Python在诸如爬虫,以及科学计算等方面具有天然的优势.最近在工作中遇到需要在Java程序中调用已经写好的Python程 ...
- 如何在Java中调用Python代码
有时候,我们会碰到这样的问题:与A同学合作写代码,A同学只会写Python,而不会Java, 而你只会写Java并不擅长Python,并且发现难以用Java来重写对方的代码,这时,就不得不想方设法“调 ...
- 在Java中调用Python
写在前面 在微服务架构大行其道的今天,对于将程序进行嵌套调用的做法其实并不可取,甚至显得有些愚蠢.当然,之所以要面对这个问题,或许是因为一些历史原因,或者仅仅是为了简单.恰好我在项目中就遇到了这个问题 ...
随机推荐
- 【matplotlib 实战】--雷达图
雷达图(Radar Chart),也被称为蛛网图或星型图,是一种用于可视化多个变量之间关系的图表形式.雷达图是一种显示多变量数据的图形方法.通常从同一中心点开始等角度间隔地射出三个以上的轴,每个轴代表 ...
- JVM SandBox 的技术原理与应用分析
https://www.infoq.cn/article/tsy4lgjvsfweuxebw*gp https://blog.csdn.net/qq_40378034/article/details/ ...
- 神经网络入门篇:详解多样本向量化(Vectorizing across multiple examples)
多样本向量化 与上篇博客相联系的来理解 逻辑回归是将各个训练样本组合成矩阵,对矩阵的各列进行计算.神经网络是通过对逻辑回归中的等式简单的变形,让神经网络计算出输出值.这种计算是所有的训练样本同时进行的 ...
- 栈与队列应用:逆波兰计算器(逆波兰表达式;后缀表达式)把运算符放到运算量后边 && 中缀表达式转化为后缀表达式
1 //1.实现对逆波兰输入的表达式进行计算如(2-1)*(2+3)= 5 就输入2 1 - 2 3 + * //先把2 1 压栈 遇到-弹栈 再把2 3压进去 遇到+弹栈 最后遇到*弹栈 2 //2 ...
- go并发 - goroutine
概述 Go并发模型独树一帜,简洁.高效.Go语言最小执行单位称为协程(goroutine),运行时可以创建成千万上个协程,这在Java.C等线程模型中是不可想象的,并发模型是Go的招牌能力之一.很多文 ...
- 后台获取的map集合封装json
let list = [] let arr = {'a':'1','b':'2','c':'3','d':'4'} for(var key in arr){ console.log("key ...
- AutoCAD ObjectARX 二次开发(2020版)--4,使用ARX向导创建CAD二次开发项目(编程框架)--
手动创建ObjectARX应用程序非常麻烦,在此步骤中,将介绍ObjectARX向导. 在这里,我们将使用ObjectARX向导创建我们的ObjectARX应用程序. 本节的程序的需求是,接收CAD用 ...
- 介绍一个我开源的项目:一键部署 VictoriaMetrics 群集
作者:张富春(ahfuzhang),转载时请注明作者和引用链接,谢谢! cnblogs博客 zhihu Github 公众号:一本正经的瞎扯 我实在是非常喜欢这个强大的 metrics 监控组件 Vi ...
- 在自动化测试时,Python常用的几个加密算法,你有用到吗
本文分享自华为云社区<『加密算法』| 自动化测试时基于Python常用的几个加密算法实现,你有用到吗?>,作者:虫无涯 . 写在前边 这几天做自动化测试,遇到一个问题,那就是接口的请求的密 ...
- LIS和LCS算法分析
LIS(最长上升子序列) 常规的解法就是动态规划. mx[ j ]表示长度为j的上升子序列最小的值a[i]; dp[ i ]表示前i个数的最长上升子序列长度多少. 1 for(int i=1;i< ...