1. 概述
R 语言是统计分析领域的主流工具,拥有海量的统计函数和扩展包。在实际开发中,我们经常需要在 Java 应用中调用 R 的计算能力,实现“Java 调 R”的混合编程。
本文将系统介绍几种主流的 Java 调用 R 的集成方案,帮助你在不同场景下做出合适的技术选型。
2. R 脚本准备
我们先准备一个简单的 R 脚本,实现向量求均值的功能。创建文件 script.R
:
customMean <- function(vector) {
mean(vector)
}
在 Java 中,我们通过一个工具方法读取该脚本内容:
String getMeanScriptContent() throws IOException, URISyntaxException {
URI rScriptUri = RUtils.class.getClassLoader().getResource("script.R").toURI();
Path inputScript = Paths.get(rScriptUri);
return Files.lines(inputScript).collect(Collectors.joining());
}
后续所有方案都将基于这个脚本进行调用演示。
3. RCaller:本地进程调用
RCaller 是一种简单直接的集成方式,其原理是 启动一个独立的 R 进程,通过标准输入输出与 Java 通信。
引入依赖
RCaller 已发布到 Maven Central,可直接引入:
<dependency>
<groupId>com.github.jbytecode</groupId>
<artifactId>RCaller</artifactId>
<version>3.0</version>
</dependency>
调用示例
public double mean(int[] values) throws IOException, URISyntaxException {
String fileContent = RUtils.getMeanScriptContent();
RCode code = RCode.create();
code.addRCode(fileContent);
code.addIntArray("input", values);
code.addRCode("result <- customMean(input)");
RCaller caller = RCaller.create(code, RCallerOptions.create());
caller.runAndReturnResult("result");
return caller.getParser().getAsDoubleArray("result")[0];
}
关键对象说明
- ✅
RCode
:封装 R 脚本、变量和执行语句 - ✅
RCaller
:执行脚本并获取结果
注意事项 ⚠️
- ❌ 不适合高频小计算:每次调用都要启动 R 进程,开销大
- ❌ 强依赖本地 R 环境:目标机器必须安装 R
- ✅ 适合离线批处理、计算密集型任务
4. Renjin:JVM 内嵌解释器
Renjin 是一个基于 JVM 的 R 语言解释器,无需外部 R 环境,运行在 JVM 内部。
配置仓库与依赖
Renjin 未发布到 Maven Central,需添加 Mulesoft 仓库:
<repositories>
<repository>
<id>mulesoft</id>
<name>Mulesoft Repository</name>
<url>https://repository.mulesoft.org/nexus/content/repositories/public/</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>org.renjin</groupId>
<artifactId>renjin-script-engine</artifactId>
<version>RELEASE</version>
</dependency>
</dependencies>
调用示例
public double mean(int[] values) throws IOException, URISyntaxException, ScriptException {
RenjinScriptEngine engine = new RenjinScriptEngine();
String meanScriptContent = RUtils.getMeanScriptContent();
engine.put("input", values);
engine.eval(meanScriptContent);
DoubleArrayVector result = (DoubleArrayVector) engine.eval("customMean(input)");
return result.asReal();
}
优势与限制
- ✅ 无需安装 R:纯 Java 依赖,部署简单
- ✅ 启动快:无进程开销,适合高频调用
- ⚠️ 兼容性问题:并非 100% 兼容 GNU R,部分包可能无法使用
- ✅ 提供企业支持,适合生产环境
5. Rserve:远程服务调用
当多个客户端需要共享 R 计算资源时,Rserve 是理想选择。它通过 TCP 提供 R 的远程调用能力,实现 R 服务化。
启动 Rserve 服务
在 R 环境中安装并启动服务:
> install.packages("Rserve")
> library("Rserve")
> Rserve(args = "--RS-source ~/script.R")
Starting Rserve...
默认监听 127.0.0.1:6311
。
引入客户端依赖
<dependency>
<groupId>org.rosuda.REngine</groupId>
<artifactId>Rserve</artifactId>
<version>1.8.1</version>
</dependency>
Java 调用代码
public double mean(int[] values) throws REngineException, REXPMismatchException {
RConnection c = new RConnection();
c.assign("input", values);
return c.eval("customMean(input)").asDouble();
}
适用场景
- ✅ 多 Java 应用共享 R 计算资源
- ✅ R 脚本需要长期驻留内存(避免重复加载)
- ✅ 集中管理 R 环境和依赖包
6. FastR:GraalVM 原生集成
FastR 是 Oracle 基于 GraalVM 实现的高性能 R 运行时,支持与 Java 深度互操作。
环境准备
- 安装 GraalVM
- 使用
gu
安装 FastR:
$ bin/gu install R
$ languages/R/bin/configure_fastr
⚠️ 当前仅支持 Linux 和 Darwin x64 系统。
Java 调用代码
public double mean(int[] values) {
Context polyglot = Context.newBuilder().allowAllAccess(true).build();
String meanScriptContent = RUtils.getMeanScriptContent();
polyglot.eval("R", meanScriptContent);
Value rBindings = polyglot.getBindings("R");
Value rInput = rBindings.getMember("c").execute(values);
return rBindings.getMember("customMean").execute(rInput).asDouble();
}
特点分析
- ✅ 性能极佳:GraalVM JIT 优化,接近原生速度
- ✅ 无缝互操作:Java 与 R 对象可直接传递
- ❌ 强绑定 GraalVM:无法在普通 JVM 上运行
- ❌ 平台限制:不支持 Windows 等系统
7. 总结与选型建议
方案 | 是否需 R 环境 | 部署复杂度 | 性能 | 适用场景 |
---|---|---|---|---|
RCaller | ✅ | 低 | 低(启动慢) | 离线批处理 |
Renjin | ❌ | 低 | 中 | 高频调用,轻量级计算 |
Rserve | ✅(服务端) | 中 | 中 | 多客户端共享,服务化部署 |
FastR | ❌(GraalVM) | 高 | 高 | 高性能要求,GraalVM 生态 |
✅ 简单粗暴的选型建议:
- 想快速验证?用 RCaller
- 想省运维?用 Renjin
- 想搞微服务?上 Rserve
- 不差钱且用 GraalVM?闭眼选 FastR
所有示例代码已托管至 GitHub:https://github.com/baeldung/tutorials/tree/master/libraries