4.1 Rserve与Java的跨平台通信
问题
Java怎么调用R?
引言
当前主流的异构跨平台通信组件Apache Thrift已经火遍大江南北,支持15种编程语言,但是到目前为止还没有加入R语言。要让R实现跨平台的通信,就只能从R的社区(CRAN)中找方案,像rJava、RCpp、rpy都是2种语言结合的方案,这些方案类似地会把R引擎加载到其他语言内存环境。这类方案的优点是高效,缺点是紧耦合,扩展受限,接口程序无法重用。
Rserve给了我们一种新的选择,它是抽象R语言网络接口,基于TCP/IP协议实现与多语言之间的通信。Rserve支持R语言与其他语言通信,通过C/S结构的程序调用,支持C/C++、Java、PHP、Python、Ruby、Nodejs等。 Rserve支持远程连接、用户认证、文件传输等功能。我们可以设计R作为后台服务引擎,处理统计建模、数据分析、绘图等的任务。本节我们就来体验Rserve与Java的跨平台通信。
4.1.1 Rserve安装
本节使用的系统环境是:
- Linux Ubuntu 12.04.2 LTS 64bit server
- R: 3.0.1 x86_64-pc-linux-gnu
- IP 192.168.1.201
注:Rserve同时支持Win7环境和Linux环境,由于Rserve主要用来做通信服务器,建议使用Linux环境。
Rserve的安装过程如下:
~ R # 启动R程序
> install.packages("Rserve") # 安装Rserve
~ R CMD Rserve # 在命令行启动Rserve服务器
~ ps -aux|grep Rserve #查看进程
conan 7142 0.0 1.2 116296 25240 ? Ss 09:13 0:00 /usr/lib/R/bin/Rserve
~ netstat -nltp|grep Rserve #查看端口
tcp 0 0 127.0.0.1:6311 0.0.0.0:* LISTEN 7142/Rserve
这时Rserve服务器已经启动,端口是6311。127.0.0.1表示只接受来自IP为127.0.0.1的请求访问,即只允许本地应用访问。如果我们想远程访问 Rserve,就需要开启远程模式,这就需要在启动命令时增加参数 –RS-enable-remote:
~ kill -9 7142 #杀掉刚才的Rserve守护进程
~ R CMD Rserve --RS-enable-remote #以远程模式启动Rserve
~ netstat -nltp|grep Rserve #查看端口
tcp 0 0 0.0.0.0:6311 0.0.0.0:* LISTEN 7173/Rserve
0 0.0.0 说明不限IP访问了,我们接下来就可以从远程来访问Rserve了。
4.1.2 用Java远程连接Rserve
Java程序在Win7中通过EclipseIDE工具直接运行,让Java远程连接Linux系统上的Rserve服务器。Win7环境是:
- JAVA :Oracle SUN JDK 1.6.0_45 64bit
- Eclipse: Juno Service Release 2
- IP: 192.168.1.13
Rserve所在Linux服务器的IP为 192.168.1.201。
1. 下载Java客户端JAR包
通过链接( http://www.rforge.net/Rserve/files/),下载Java客户端JAR包REngine.jar 和 RserveEngine.jar。通过这两个Jar包,就可以实现Java和Rserve的通信了。
- REngine.jar : 用于R和Java数据类型的映射
- RserveEngine.jar : 用于Rserve的通信程序
这两个类库说明,可以查看官方的javadoc文件,网址是 http://rforge.net/org/doc/。这两个JAR包是Java编译后的二进制文件,没有提供源代码文件。
2. 在Eclipse中创建Java工程
在Eclipse中新建Java工程,并加载Jar包环境中,加载后如图4-1所示。
3. Java编程实现
下面我们来写一个Java的类Demo1.java,完成Java远程调用Rserve服务器的实现,Demo1.java中包括2个方法。
- main()方法:是Java程序启动的入口,实例化一个demo对象,然后调用callRserve()方法。
- callRserve()方法:创建远程访问Rserve的socket连接,以字符串的方式向Rserve服务器发送两条R的语句,在Rserve上计算并返回结果,最后在Java中输出结果。
Demo1.java代码如下。
package org.conan.r.rserve;
import org.rosuda.REngine.REXP;
import org.rosuda.REngine.REXPMismatchException;
import org.rosuda.REngine.Rserve.RConnection;
import org.rosuda.REngine.Rserve.RserveException;
public class Demo1 {
/**
* Main方法用于启动Java应用
*/
public static void main(String[] args) throws RserveException, REXPMismatchException {
Demo1 demo = new Demo1();
demo.callRserve();
}
/**
* 访问Rserve
*/
public void callRserve() throws RserveException, REXPMismatchException {
RConnection c = new RConnection("192.168.1.201"); //创建访问连接
REXP x = c.eval("R.version.string"); //执行一条R的语句
System.out.println(x.asString()); //在Java中打印返回结果
double[] arr = c.eval("rnorm(10)").asDoubles(); //执行rnorm(10)语句
for (double a : arr) { //在Java中循环打印返回结果
System.out.print(a + ",");
}
}
}
运行结果
R version 3.0.1 (2013-05-16)
1.7695224124757984,-0.29753038160770323,0.26596993631142246,1.4027325257239547,-0.30663565983302676,-0.17594309812158912,0.10071253841443684,0.9365455161259986,0.11272119436439701,0.5766373030674361,
通过Rserve我们就非常简单地实现了Java和R的通信,更准确地说,是Java访问Rserve服务器,实现了基于TCP/IP的通信。我们解决了通信的问题后,就可以发挥想象,把R更广泛地用起来了。本节只是简单地介绍了Rserve的安装和启动,关于Rserve服务器详细的使用和配置,请查看5.1节。