解惑rJava R与Java的高速通道

R的极客理想系列文章,涵盖了R的思想,使用,工具,创新等的一系列要点,以我个人的学习和体验去诠释R的强大。

R语言作为统计学一门语言,一直在小众领域闪耀着光芒。直到大数据的爆发,R语言变成了一门炙手可热的数据分析的利器。随着越来越多的工程背景的人的加入,R语言的社区在迅速扩大成长。现在已不仅仅是统计领域,教育,银行,电商,互联网….都在使用R语言。

要成为有理想的极客,我们不能停留在语法上,要掌握牢固的数学,概率,统计知识,同时还要有创新精神,把R语言发挥到各个领域。让我们一起动起来吧,开始R的极客理想。

关于作者:

  • 张丹(Conan), 程序员Java,R,PHP,Javascript
  • weibo:@Conan_Z
  • blog: http://blog.fens.me
  • email: bsspirit@gmail.com

转载请注明出处:
http://blog.fens.me/r-rjava-java
rjava

前言
Java语言在工业界长期处于霸主地位,Java语法、JVM、JDK、Java开源库,在近10年得到了爆发式的发展,几乎覆盖了应用开发的所有领域。伴随着Java的全领域发展,问题也随之而来了。语法越来越复杂,近似的项目越来越多,学好Java变得很难。对于没有IT背景的统计人员,学用Java更是难于上青天。

R一直是统计圈内处于佼佼者的语言,语法简单,学习曲线不太长也不太陡。如果能结合Java的通用性和R的专业性,碰撞出的火花,将会缤纷绚烂。

本文将介绍R与Java连接的高速通道,rJava通信方案。另外一篇文章介绍的Rserve通信方案,请参考: Rserve与Java的跨平台通信

目录

  1. rJava介绍
  2. rJava安装
  3. rJava实现R调用Java
  4. rJava(JRI)实现Java调用R (win7)
  5. rJava(JRI)实现Java调用R (Ubuntu)

1. rJava介绍

rJava是一个R语言和Java语言的通信接口,通过底层JNI实现调用,允许在R中直接调用Java的对象和方法。

rJava还提供了Java调用R的功能,是通过JRI(Java/R Interface)实现的。JRI现在已经被嵌入到rJava的包中,我们也可以单独试用这个功能。现在rJava包,已经成为很多基于Java开发R包的基础功能组件。

正式由于rJava是底层接口,并使用JNI作为接口调用,所以效率非常高。在JRI的方案中,JVM直接通过内存直接加载RVM,调用过程性能几乎无损耗,因此是非常高效连接通道,是R和Java通信的首选开发包。

2. rJava安装

系统环境:

  • Linux Ubuntu 12.04.2 LTS 64bit server
  • R version 3.0.1 64bit
  • Java (Oracle SUN) 1.6.0_29 64bit Server VM

~ uname -a
Linux conan 3.5.0-23-generic #35~precise1-Ubuntu SMP Fri Jan 25 17:13:26 UTC 2013 x86_64 x86_64 x86_64 GNU/Linux

~ cat /etc/issue
Ubuntu 12.04.2 LTS \n \l

~ R --version
R version 3.0.1 (2013-05-16) -- "Good Sport"
Copyright (C) 2013 The R Foundation for Statistical Computing
Platform: x86_64-pc-linux-gnu (64-bit)

R is free software and comes with ABSOLUTELY NO WARRANTY.
You are welcome to redistribute it under the terms of the
GNU General Public License versions 2 or 3.
For more information about these matters see
http://www.gnu.org/licenses/.

~ java -version
java version "1.6.0_29"
Java(TM) SE Runtime Environment (build 1.6.0_29-b11)
Java HotSpot(TM) 64-Bit Server VM (build 20.4-b02, mixed mode)

rJava安装


#配置rJava环境
~ sudo R CMD javareconf

#启动R
~ sudo R
> install.packages("rJava")
installing via 'install.libs.R' to /usr/local/lib/R/site-library/rJava
** R
** inst
** preparing package for lazy loading
** help
*** installing help indices
** building package indices
** testing if installed package can be loaded
* DONE (rJava)

The downloaded source packages are in
        ‘/tmp/RtmpiZyCE7/downloaded_packages’

3. rJava实现R调用Java

在R环境中,使用rJava包编程


#加载rJava包
> library(rJava)
> search()
 [1] ".GlobalEnv"        "package:rJava"     "package:stats"
 [4] "package:graphics"  "package:grDevices" "package:utils"
 [7] "package:datasets"  "package:methods"   "Autoloads"
[10] "package:base"

#启动JVM
> .jinit()

#声明并赋值到字符串
> s <- .jnew("java/lang/String", "Hello World!")
> s
[1] "Java-Object{Hello World!}"

#查看字符串长度
> .jcall(s,"I","length")
[1] 12

#索引World的位置
> .jcall(s,"I","indexOf","World")
[1] 6

#查看concat的方法声明
> .jmethods(s,"concat")
[1] "public java.lang.String java.lang.String.concat(java.lang.String)"

#使用concat方法连接字符串
> .jcall(s,"Ljava/lang/String;","concat",s)
[1] "Hello World!Hello World!"

#打印字符串对象
> print(s)
[1] "Java-Object{Hello World!}"

#打印字符串值
> .jstrVal(s)
[1] "Hello World!"

rJava优化过的方法调用,用$来调用方法


#同.jcall(s,"I","length")
> s$length()
[1] 12

#同.jcall(s,"I","indexOf","World")
> s$indexOf("World")
[1] 6

4. rJava(JRI)实现Java调用R (win7)

在win7中安装rJava

系统环境:

  • win7 64bit 旗舰版
  • R 3.0.1
  • Java 1.6.0_45

设置环境变量


PATH: C:\Program Files\R\R-3.0.1\bin\x64;D:\toolkit\java\jdk6\bin;;D:\toolkit\java\jdk6\jre\bin\server
JAVA_HOME: D:\toolkit\java\jdk6
CLASSPATH: C:\Program Files\R\R-3.0.1\library\rJava\jri

在R中安装rJava


> install.packages("rJava")

#加载rJava
> library(rJava)
> .jinit()

#R调用Java变量测试
> s <- .jnew("java/lang/String", "Hello World!")
> s
[1] "Java-Object{Hello World!}"

启动Eclipse编写程序
rjava2


package org.conan.r.rjava;

import org.rosuda.JRI.Rengine;

public class DemoRJava {

    public static void main(String[] args) {
        DemoRJava demo = new DemoRJava();
        demo.callRJava();
    }

    public void callRJava() {
        Rengine re = new Rengine(new String[] { "--vanilla" }, false, null);
        if (!re.waitForR()) {
            System.out.println("Cannot load R");
            return;
        }
        
        //打印变量
        String version = re.eval("R.version.string").asString();
        System.out.println(version);

        //循环打印数组
        double[] arr = re.eval("rnorm(10)").asDoubleArray();
        for (double a : arr) {
            System.out.print(a + ",");
        }
        re.end();
    }
}

在Eclipse启动设置VM参数:

-Djava.library.path="C:\Program Files\R\R-3.0.1\library\rJava\jri\x64"

rjava

运行结果:


R version 3.0.1 (2013-05-16)
0.04051018703700011,-0.3321596519938258,0.45642459001166913,-1.1907153494936031,1.5872266854172385,1.3639721994863943,-0.6309712627586983,-1.5226698569087498,-1.0416402147174952,0.4864034017637044,

打包DemoRJava.jar
在Eclipse中完成打包,上传到linux环境,继续测试。

5. rJava(JRI)实现Java调用R (Ubuntu)

新建目录DemoRJava,上传DemoRJava.jar到DemoRJava


~ mkdir /home/conan/R/DemoRJava
~ cd /home/conan/R/DemoRJava
~ ls -l
-rw-r--r-- 1 conan conan 1328 Aug  8  2013 DemoRJava.jar

运行Jar包


~ export R_HOME=/usr/lib/R
~ java -Djava.library.path=/usr/local/lib/R/site-library/rJava/jri -cp /usr/local/lib/R/site-library/rJava/jri/JRI.jar:/home/conan/R/DemoRJava/DemoRJava.jar org.conan.r.rjava.DemoRJava

运行结果


R version 3.0.1 (2013-05-16)
0.6374494596732511,1.3413824702002808,0.04573045670001342,-0.6885617932810327,0.14970067632722675,-0.3989493870007832,-0.6148250252955993,0.40132038323714453,-0.5385260423222166,0.3459850956295771,

我们完成了,R和Java的互调。包括了R通过rJava调用Java,Java通过JRI调用R。并演示了win和linux中的使用方法。

转载请注明出处:
http://blog.fens.me/r-rjava-java

打赏作者

This entry was posted in JAVA语言实践, R语言实践

0 0 votes
Article Rating
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

62 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Yihui Xie

我有一个困扰我很久的问题,正好你写了这篇文章,于是向你请教一下:在knitr里面我有一些调用外部语言的方式( http://yihui.name/knitr/demo/engines/ ),对于Java,我想实现类似的功能,就是以字符串的形式给你一段Java代码,在R里面调用Java运行它,然后返回stdout中的输出。这个rJava可以实现吗?

Conan Zhang

可以实现!参考“3. rJava实现R调用Java”,只要装好JAVA,配好环境变量就行了。不过这种语法,并不是标准的JAVA语法。写JAVA的人,会很不习惯。

我在开发过程中,一般习惯使用JAVA调用R。JVM会加载RVM的虚拟机,在一个进程中完成。

你的Language engines的想法非常好!如果不用R做中间转换层,而是用JAVA或者C在中间转换,前景应该会更大。

Yihui Xie

我不熟悉Java,所以也许问不好问题:我的猜想是Java里面应该也有eval()之类的函数可以运行一段代码,然后我在R里面创建一个Java运行器,然后不断j$eval(‘code code code’)。这个具体怎么弄我不清楚,不知是否能给个例子?谢谢。

Conan Zhang

1. JAVA里没有eval()函数。你希望eval()执行的代码,是Linux命令?还是其他语言的代码?

如果是linux命令,可以用下面的代码
Runtime.getRuntime().exec(“dir”)

如果是其他语言的代码,会比较麻烦,需要安装对应语言的环境。

2. R里面创建一个Java运行器,rJava就是做的这件事。通过JNI来完成,R对Java的调用。依赖于rJava的函数可以实现,你要的j$eval(‘code code code’)功能。

3. JAVA是编译运行的语言,与R,Python, Ruby是完全不一样的语言结构。所有都是JAVA代码,都编译后才能运行,我不知道是不是这个原因,所以咱们对问题的理解是不一样的?!

Yihui Xie

我希望eval()执行的就是Java代码,因为Java是编译型语言,所以eval()可以先编译它再运行。我之前做的大多都是解释型语言(除了C和C++之外),所以简单一些,我现在又想了想,可能没太大必要做Java,等用户真有需求了再说吧。

Conan Zhang

要用eval()执行Java代码,虽然有解决方案,但是复杂度是很高的。如果没有一个很懂JAVA的帮你,这个事难啊。还是先往后放放吧,等有需求再做吧。

outqin

最近发现有一个叫jvmr的包,可以有类似的功能。在我的电脑上,示例代码里scala比java的代码快一些,http://t.cn/RhukXtW。

Yihui Xie

谢谢,这个看起来不错,我有空仔细研究一下。

Conan Zhang

jvmr似乎还是依赖于rJava的,这样其实并不能解决R本身的瓶境。

gaotao

丹,如果用java写好了算法, 然后用rJava来调用就可以了咯?那么说r与mahaout的链接可以通过rJava来实现,再加上rhadoop的转化?

Conan Zhang

1. Java写算法,R调用Java,这是一种标准的用法。像RJDBC这样的包,都是通过这种方案实现的。

2. r与mahout,确实可以通过rjava来实现,但这样做的意义不是太大,除非你准备开发一个Rmahout的包。

Mahout是一套完整的机器学习算法框架,天生已接入hadoop,能够把Mahout使用好的人,在算法上面不用依赖R,完全有能力JAVA实现。

3. rhadoop,是一条打能R与Hadoop的通道,让R语言处理大数据成为可能。不过,rmr2的开发,依然是一件很难的事情。

[…] 参考文章: Rserve与Java的跨平台通信 解惑rJava R与Java的高速通道 […]

[…] 另一个R和Java通信的库JRI,并不支持多会话机制。关于R和Java通信的其他文章,请参考:解惑rJava R与Java的高速通道, Rserve与Java的跨平台通信 […]

wangzhen

刚接触rjava,配置很长时间没成功。返回这个错误:Warning in install.packages :
installation of package ‘rJava’ had non-zero exit status
进行sudo R CMD javareconf这步时,
conftest.c:1:17: 致命错误: jni.h:没有那个文件或目录
编译中断。
make: *** [conftest.o] 错误 1
Unable to compile a JNI program

网上搜了很长时间,没配置成功,请问该怎么解决?

Conan Zhang

似乎没装JDK吧?

wangzhen

ubuntu下装eclipse着,可以使用,查询有下面结果:
:~$ echo $JAVA_HOME

/usr/lib/jvm/java-7-sun

:~$ java -version

java version “1.6.0_27”

OpenJDK Runtime Environment (IcedTea6 1.12.6) (6b27-1.12.6-1ubuntu0.12.04.4)

OpenJDK 64-Bit Server VM (build 20.0-b12, mixed mode)

Conan Zhang

改成:SUN JDK

zhuqing

错误于.jcall(“RJavaTools”, “Ljava/lang/Object;”, “invokeMethod”, cl, :
java.lang.NoClassDefFoundError: Could not initialize class org.apache.log4j.LogManager
这是怎么回事呢?找不到类吗?

Conan Zhang

我不知道你的程序是什么样子的,从错误来看,是没有找到这个类。org.apache.log4j.LogManager

zhuqing

我用的是R3.0.3版本,hadoop是2.2版本,安装完成后,进入R命令行,library(rhdfs),然后hdfs.init(),就出现了以上错误。如果没有找到这个类,我怎么加载上呢?

Conan Zhang

R2.15.3 + Hadoop 1.0.x

wangyanjia

linux下运行Java时,会报这个错误
Cannot find JRI native library!
Please make sure that the JRI native library is in a directory listed in java.library.path.

java.lang.UnsatisfiedLinkError: no jri in java.library.path

Conan Zhang

这个包也可以单独下载,然后加载到运行时环境。

wangyanjia

linux安装完rJava后,有jri.so吗? LD_LIBRARY_PATH应该配置到哪个目录?jri的几个jar包都有了,但是报这个错误,是不是环境变量配置不对?能把你配置的环境变量给我看一下吗,尤其是 java.library.path,谢谢了

Conan Zhang

文章里不是有java.library.path和运行环境。
~ java -Djava.library.path=/usr/local/lib/R/site-library/rJava/jri -cp /usr/local/lib/R/site-library/rJava/jri/JRI.jar:/home/conan/R/DemoRJava/DemoRJava.jar org.conan.r.rjava.DemoRJava

fengshi

您好,我和你遇到了同样的问题,请问下你是怎么解决的。linux下运行Java时,会报这个错误
Cannot find JRI native library!
Please make sure that the JRI native library is in a directory listed in java.library.path.
java.lang.UnsatisfiedLinkError: no jri in java.library.path

Kongnuan Zhao

我64位的R,64位的eclipse,64位的JDK 不行啊,R里面报错说LoadLibrary failure: %1 不是有效的 Win32 应用程序。 全部换成32位的没有问题,但是那样做的别的工作都要换,很麻烦,楼主有办法解决在64位上面按rjava吗

Conan Zhang

在Linux环境中,一般不会出现这个问题。如果必须用Window,那只能在麻烦中操作了。

Zijia

樓主你好,
請問R語言的底層運作架構是RVM嘛?
RVM是如何運作的?

Conan Zhang

RVM,R Virtual Machine运行时环境,如何动作要查官方文档了。

Michael

/usr/R-3.1.2/lib64/R/library/rJava/jri/libjri.so: libR.so: 无法打开共享对象文件,没有那个文件或目录

fengshi

/usr/R-3.1.2/lib64/R/library/rJava/jri/libjri.so: libR.so: 无法打开共享对象文件,没有那个文件或目录 我也遇到了同样的问题,请问您是怎么解决的

Michael

在eclipse中设置了: -Djava.library.path=:/usr/R-3.1.2/lib64/R/library/rJava/jri
运行DemoRJava, 显示/usr/R-3.1.2/lib64/R/library/rJava/jri/libjri.so: libR.so: 无法打开共享对象文件,没有那个文件或目录
不知道该如何处理

Conan Zhang

版本不同,可能R的安装目录是不一样的。用linux find函数找一下。

fengshi

遇到同样的问题,请问你是怎么解决的呢?

Conan Zhang

win系统的目录下面
D:toolR-3.2.3libraryrJavajrix64jri.dll

linux是 .so的

fengshi

我在Linux系统的Eclipse中,VM配置为:-Djava.library.path=”/opt/R-3.2.3/library/rJava/jri/libjri.so” ,然后出现报错:Cannot find JRI native library!
Please make sure that the JRI native library is in a directory listed in java.library.path.
java.lang.UnsatisfiedLinkError: no jri in java.library.path

Conan Zhang

-Djava.library.path=”/opt/R-3.2.3/library/rJava/jri/
指定目录而不是文件,是不是这个问题?

fengshi

-Djava.library.path=”/opt/R-3.2.3/library/rJava/jri/ 或者 -Djava.library.path=”/opt/R-3.2.3/library/rJava/jri 都会报以下的错误:
Cannot find JRI native library!
Please make sure that the JRI native library is in a directory listed in java.library.path.
java.lang.UnsatisfiedLinkError: /opt/R-3.2.3/library/rJava/jri/libjri.so: libR.so: 无法打开共享对象文件: 没有那个文件或目录

Conan Zhang

确定一下,你的目录里有这个文件吗?

fengshi

目录里有这个文件,jdk装的事sun的,不是openjdk。
把编译后的类文件拷出来放到/opt/R-3.2.3/library/rJava/jri/examples目录下,然后通过运行/opt/R-3.2.3/library/rJava/jri/run 执行文件可以正常运行

Conan Zhang

这样吧,你直接把rJava下面的*.jar都复制你的项目类库里面吧,不要用这种-D的方式加载了。应该就行了。

Michael

/usr/R-3.1.2/lib64/R/library/rJava/jri/ 下面存在JRI.jar, JRIEngine.jar及REngine.jar,以及libjri.so等文件

Jackie Lee

我的rJava没有libjri.so文件,你的rJava是如何安装的?能不能告诉我下你是使用install.packages还是自己下载的,如果是install.packages,你选的那个源,如果是自己下载是在哪下载的?谢谢

郭郭

楼主,我的错误是这样的,麻烦问一下应该如何解决呀
Cannot find JRI native library!

Please make sure that the JRI native library is in a directory listed in java.library.path.

java.lang.UnsatisfiedLinkError: D:TDDownloadR_softwareinstallR-3.2.2libraryrJavajrix64jri.dll: %1 不是有效的 Win32 应用程序。

Conan Zhang

不好意思,回复晚了。
UnsatisfiedLinkError这个错误,应该是版本的问题。你的JAVA和jri.dll不兼容。

Michael

rJava在tomcat里运行,new REngine()第二次会导致tomcat崩溃。

Conan Zhang

要看你是怎么加载的。 一个DDL,只能被JVM加载一次。

fengshi

rJava下的3个jar包:JRI.jar JRIEngine.jar REngine.jar 本就在项目底下,还是照样问题

Conan Zhang

我也不知道,你哪里出了问题,环境要调啊。

licy

版主你好,我想问下安装rjava时报如下错,怎么解决,系统为centos6.2,jdk版本1.7
rjava.c:52: warning: ignoring return value of ‘read’, declared with attribute warn_unused_result

gcc -m64 -std=gnu99 -o libjri.so Rengine.o jri.o Rcallbacks.o Rinit.o globals.o rjava.o -shared -L/usr/java/jdk1.7.0_79/jre/lib/amd64/server -ljvm -Wl,–export-dynamic -fopenmp -L/usr/lib64/R/lib -lR -lrt -ldl -lm -licuuc -licui18n

/usr/bin/ld: cannot find -licuuc

collect2: ld returned 1 exit status

make[2]: *** [libjri.so] Error 1

make[2]: Leaving directory `/tmp/RtmpTiqE2j/R.INSTALL36592d83da75/rJava/jri/src’

make[1]: *** [src/JRI.jar] Error 2

make[1]: Leaving directory `/tmp/RtmpTiqE2j/R.INSTALL36592d83da75/rJava/jri’

make: *** [jri] Error 2

ERROR: compilation failed for package ‘rJava’

* removing ‘/usr/lib64/R/library/rJava’

Conan Zhang

看起来是环境的问题,换个Java或换个R再试试。

licy

是的,我换了java版本就OK了,谢谢

Conan Zhang

编译错误,看上去是JAVA和R的版本不匹配。

郭郭

楼主,我的错误是这样的,麻烦请教一下应该如何解决呀
Cannot find JRI native library!

Please make sure that the JRI native library is in a directory listed in java.library.path.

java.lang.UnsatisfiedLinkError: D:TDDownloadR_softwareinstallR-3.2.2libraryrJavajrix64jri.dll: %1 不是有效的 Win32 应用程序。

maozhenyu

请问,我如果用java语言调用R语言卡方分析,怎么在java中输出多个分析结果

maozhenyu

用eval()执行完,卡方分析的结果在java里面怎么显示

Conan Zhang

你可以查看一下R语言代码里怎么实现的,如果是用cat, print输出的,就不能返回到java里;如果是return的,就可以返回来。

Conan Zhang

> chisq.test,

structure(list(statistic = STATISTIC, parameter = PARAMETER,

p.value = PVAL, method = METHOD, data.name = DNAME, observed = x,

expected = E, residuals = (x – E)/sqrt(E), stdres = (x –

E)/sqrt(V)), class = “htest”)

返回的是对象,这个会对应java的数据结构。

maozhenyu

返回的structure是这个数据结构吗

Conan Zhang

是的,会映射成JAVA的一个结构。

maozhenyu

谢谢

62
0
Would love your thoughts, please comment.x
()
x