1. 程式人生 > >從Java裡呼叫R – 使用Rserve

從Java裡呼叫R – 使用Rserve

java中設定呼叫R語言-使用JRI方法,有一些弊端:

  • R需要與JVM執行在同一臺機器上,當R需要執行大型計算時,會耗用大量CPU與記憶體,因此會影響到JVM的效能
  • JRI的設定需要本地庫的支援,執行的時候還是有些麻煩的

Rserve可以解決這兩個問題,同時也有JRI一樣的易用性。它的原理是提供以HTTP方式連線的R語言介面, 因此可以讓專門一臺機器來執行RServe,然後讓Java或其它語言的客戶端來進行連線。額外的好處是,可以支援Java在內的多種客戶端。

Rserve推薦在Linux下使用,因為在Windows平臺上還很不完善(下面會介紹)。但由於多數程式設計師還是習慣於在Windows環境下進行開發,還是有必要找到在Windows上進行它的辦法。這篇文章主要介紹這個環境的話題。

安裝RServe

以下以Windows平臺為例介紹安裝的方法。Rserve可以從其網站下載單獨安裝,但更方便的方式是從R中直接進行安裝,只需執行

install.packages(‘Rserve’)

然後,需要手動複製$R_HOME/library/rserve/Rserve*.exe到bin/i386裡(視平臺而定)。

執行時,在命令列輸入:

R CMD Rserve

(說明:上述方法不可行時,使用如下方法開啟Rserve服務----在R控制檯下載入該包,然後輸入命令Rserve(),開啟伺服器,就可以供客戶端呼叫。

你會得到它成功執行的提示。

要想關閉服務,最好的方法是從工作管理員裡直接殺死rserve.exe程序。我發現在命令列視窗按Ctrl-C似乎有時並不能成功關閉服務, 這個很奇怪。

使用與侷限

Windows上執行Rserve還是有很大的侷限性的。

最大的問題是,所有的連線都會在一個工作空間內執行。所以當客戶端是多執行緒程式時,可能會造成執行緒間互相干擾。我們需要在客戶端做一些額外的工作,使它能夠以執行緒安全的方式執行。Java端可以通過使用synchronize使得同一時間只有一個執行緒使用R服務。

Rserve的另一個缺點是,它的錯誤處理過於簡單化,如果R端出現錯誤,它丟擲的異常對於找到問題的根源幾乎沒有任何用處。所以我建議R端的程式一定要多寫LOG,或以統一的方式處理異常。

其次,開發中需要注意的是,Rserve同時只允許一個客戶端連線。因此,如果第二個執行緒試圖連線時,它就會一直處在等待狀態。另外,如果要更新R包,也需要關閉並重新啟動Rserve。所以,如果發現客戶端連線時出現異常情況,檢視一下工作管理員,看是不是有多個Rserve的執行緒在執行,或者你的服務有沒有重啟,往往可以幫助解決問題。

以下原始碼是一個使用Rserve實現執行緒安全的R服務的Java客戶端。包含了用Spring配置的RService物件, 以及相關的TestNG的測試。下載後需要做一些配置和修改才能使用,不過東西比較簡單,主要是演示這個idea。

示例

以下Java程式碼演示了使用上面zip包中的R服務物件來呼叫R語言來生成圖形的方法。

RService rService = new RService();
RConnection re = rService.startTransaction(); //開始獨佔工作空間
 
double[][] xx = ...; //生成兩個二維陣列
double[][] yy = ...;
 
File tempFile = null;
try {
    re.assign("x", xx); //給R的變數賦值
    re.assign("y", yy);
    tempFile = File.createTempFile("test-", ".jpg"); //把影象生成到檔案
    String filePath = tempFile.getAbsolutePath();
    logger.info("Plot file to be produced:" + filePath);
    re.eval("jpeg('" + StringEscapeUtils.escapeJava(filePath) + "')");
    re.eval("qqplot(x,y)"); //繪圖
    re.eval("dev.off()");
} catch (IOException e) {
    logger.warn("Failed to create temp file", e);
} finally {
    this.rService.endTransaction(); //退出時一定要關閉此工作空間
}