需求
软工三大作业中需要实现的一个功能是:对一篇新闻进行实体分析和关系分析
后端项目是通过JAVA+SpringBoot实现的,而可以进行的实体分析和关系识别模型都是python项目
故需要在后端项目中调用python项目
实现阶段
几种调用方式
参考:【Java】使用Java调用Python的四种方法_java调用python方法-CSDN博客
由于我需要调用的python项目比较大,还需要虚拟环境等等,所以我选在了ProcessBuilder实现
代码如下:windows实现
// 创建 ProcessBuilder 对象,设置工作目录为虚拟环境路径
ProcessBuilder builder = new ProcessBuilder("cmd.exe", "/c", "cd " + Constant.EntProjectPath + " && .\\venv\\Scripts\\activate && python " + Constant.EntPredictPath + " " + s);
builder.directory(new File(Constant.EntProjectPath));
// builder.redirectErrorStream(true); // 将标准输出和标准错误合并到同一个流中
// 启动进程
Process process = null;
try {
process = builder.start();
} catch (IOException e) {
throw new RuntimeException(e);
}
BufferedReader in = null;
try {
in = new BufferedReader(new InputStreamReader(process.getInputStream(), "UTF-8"));
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
String line = null;
while (true) {
try {
if ((line = in.readLine()) == null) break;
} catch (IOException e) {
throw new RuntimeException(e);
}
System.out.println(line);
}
至此就可以把python项目中的输出打印出来(当然,最终项目可不能仅仅打印,需要把识别出来的实体转为Entity类,再进行关系分析)。
ProcessBuilder builder = new ProcessBuilder("cmd.exe", "/c", "cd " + Constant.EntProjectPath + " && .\\venv\\Scripts\\activate && python " + Constant.EntPredictPath + " " + s);
解释一下这一行:创建一个进程,打开恶一个一个终端,进入到我需要调用的python项目文件夹,“&&”表示执行多个命令,“.\\venv\\Scripts\\activate”表示激活该项目中的虚拟环境(python项目中需要的包都在此文件夹下了,执行完该命令才会有对应版本python等),“python ........”表示运行python文件,“python predict.py 这是一个待识别实体的句子”这句命令给python文件传入了一个字符串参数。
python环境
看了好多网上java运行python文件的教程,几乎都是运行单个文件的,不太需要配置相应的软件包以及需求的python版本。
Bug_1
问题:pycharm能正常运行项目,但是java运行“python xx文件”就会报错python版本问题或者软件包缺失问题
原因:因为pycharm里可以手动配置python解释器且运行时就在这个虚拟环境里,如我通过Anaconda配置了该项目需要的python3.6和tensorflow1.12
而在Java中执行python命令时 用到的python环境是本地配置的python环境,所以python版本不匹配,同时也没有tensorflow等软件包。
解决:我在本地下载了python3.6,通过python3.6为这个项目创建了虚拟环境(因为python3.6才和tensorflow1.12匹配),如图可以发现python解释器的路径已经变为项目文件/venv中了
知道原因后,就很好解决啦,还有一种方法是在java里执行python命令时不要直接用python,而是指明解释器的位置。我已经配置好了Anaconda的 虚拟环境,所以也可以直接通过以下命令来运行该python项目
D:\Anaconda\envs\bertNER\python python文件
我之所以创建了项目里的虚拟环境是因为后续我想把软件包和环境迁移到Linux!!!于是我又埋藏了新bug,很明显更换解释器位置更简洁有效而不是前者
至此,在Windows中,Java调用python项目没有问题了,能够得到python项目中的输出
Bug_2
问题:将整个python项目打包到服务器上,部署完Java项目以后,调用实体关系分析接口以后,报错。在服务器中根本无法调用python模型
原因:(应该是因为Windows和Linux创建的python虚拟环境根本不互通?)Windows和Linux中创建的虚拟环境结构如下:
Windows:
venv
|--Lib
|--Scripts
Linux:
venv
|--lib
|--bin
其他文件
显然,在Java中的命令“\\venv\\Scripts\\activate”这种方式无法激活虚拟环境
忙活忙活白忙活,最终还是从头做起:在服务器上安装了miniconda,创建了各项目需要的虚拟环境,于是Java中的调用命令改为:进入项目路径,激活虚拟环境,调用python文件(不进入该项目的话,python文件中需要用到的一些辅助文件会找不到)
ProcessBuilder builder = new ProcessBuilder("/bin/bash", "-c", "cd "+Constant.EntProjectPath+" && conda activate bertNER && python "+Constant.EntPredictPath + " " + s);
这一串命令在Linux服务器上跑没有任何问题,但是Java调用会报错:
CommandNotFoundError: Your shell has not been properly configured to use 'conda activate'. To initialize your shell, run $ conda init <SHELL_NAME> Currently supported shells are: - bash - fish - tcsh - xonsh - zsh - powershell See 'conda init --help' for more information and options. IMPORTANT: You may need to close and restart your shell after running 'conda init'.
按照提示在命令中添加conda init也无用......
解决:最终只能以另一种方式设置python解释器了
ProcessBuilder builder = new ProcessBuilder("/bin/bash", "-c", "cd "+Constant.EntProjectPath+" && /root/miniconda3/envs/bertNER/bin/python3.6 "+Constant.EntPredictPath + " " + s);
成功调用!
其他相关命令
迁移python项目到服务器:
当然,下面是一步步的操作命令,假设您的项目名为 `my_python_project`,服务器上的用户名为 `username`,服务器IP地址为 `server_ip`,并且您已经登录到服务器上:
1. 创建打包文件:
cd /path/to/your/project
zip -r my_python_project.zip .2. 上传到服务器:
scp /path/to/your/project/my_python_project.zip username@server_ip:/path/to/destination3. 解压打包文件:
ssh username@server_ip
cd /path/to/destination
unzip my_python_project.zip
在Linux中安装需要的环境
迁移 Windows 上的 Python 虚拟环境到 Linux 并不需要直接使用 Miniconda,而是可以通过导出虚拟环境的依赖项列表并在 Linux 上重新安装这些依赖项来完成。以下是具体的步骤:
1. 在 Windows 上导出虚拟环境:
在 Windows 上使用以下命令导出虚拟环境的依赖项列表到一个文本文件中:
pip freeze > requirements.txt2. 将导出的依赖项文件传输到 Linux 系统:
将在 Windows 上生成的 `requirements.txt` 文件传输到 Linux 系统,你可以使用 `scp` 命令或者其他文件传输工具进行传输。
3. 在 Linux 上创建新的虚拟环境:
在 Linux 系统上创建一个新的虚拟环境,并激活该环境:
conda create -n myenv python=版本号conda activate myenv
4. 安装依赖项:
在新的虚拟环境中安装从 Windows 导出的依赖项:
pip install -r requirements.txt5. 验证迁移是否成功:
在新的虚拟环境中执行一些命令来验证依赖项是否成功安装,并确保项目能够正常工作。
通过这些步骤,你应该能够将 Windows 上的 Python 虚拟环境迁移到 Linux,并在 Linux 上继续使用你的项目。