Cache'とR

Last-modified: 2008-01-26 (土) 15:26:15

Cache'は基本的にデータベースであるため、統計解析エンジンを持っていない。ここでは、Cache'と統計解析言語R(アール)を相互に利用する技術について解説する。

RからCache'を直接操作・利用する方法

RからCache'を直接操作するには、Cache' ActiveXバインディングとRのパッケージrcomを利用します。(WINのみ)
前提条件として、Rのインストール、rcomパッケージのインストール、Cache'評価版のインストールを事前におこなっておいてください。
gbax_objsrvractivex3.PNG
(注)rcomの制限について
 現在rcomでマルチバイト文字を取得しようとすると、文字が切れる現象が起こります。これは、rcomがCOMObjectで値を受け取るときに、正常に文字のバイト数を計算できていないためと考えられます。ASCII文字では問題は発生しません。

Cache'への接続

 Rを起動しrcomライブラリを宣言。

library(rcom)

 CacheObject.Factoryを呼び出して、接続オブジェクトを作成。

ObjFactory<-comCreateObject("CacheObject.Factory")

 次に、接続チャンネルを開く。

 Cannel<-comInvoke(ObjFactory,"ConnectDlg")

 接続ダイアログが開くので、接続パラメータを入力する。

 次に接続を確立する。

x<-comInvoke(ObjFactory,"Connect",Channel)

 Cache'への接続が確立されました。
 正常に接続されていれば、TRUEが返されます。(エラーの場合はFALSEが返ります)

>x
[1]TRUE

Sample.Personクラスへの接続

 例として、Sample.Personクラスへ接続し、データを取得してみます。(Sample.Personクラスの構造を見る場合は、スタジオからネームスペース[Samples]を選んだ後、ワークスペースの[+クラス]の中に入っています。またデータを見る場合は、システム管理ポータルの[データ管理][SQL]から入って探してください。Cache'では、Sample.PersonクラスはSQLのテーブルの構造を持っています。)

library(rcom)
ObjFactory<-comCreateObject("CacheObject.Factory")
Cannel<-comInvoke(ObjFactory,"ConnectDlg")

 ここで、ネームスペースに[SAMPLES]を選択する。

x<-comInvoke(ObjFactory,"Connect",Channel)

 これで、Cache'に接続できました。
 次にSample.Personクラスを呼び出してByNameクエリを実行させ、結果をResultSetオブジェクトに渡します。

> rs <- comInvoke(ObjFactory,"ResultSet","Sample.Person","ByName")

 実行。TRUEなら成功。

> comInvoke(rs,"Execute") #クエリ:名前の並び替えA~Z
[1] TRUE

 rsに結果がセットされたので、取り出します。(名前が昇順に並んで取り出されます)

> comInvoke(rs,"Get","Name");comInvoke(rs,"Next")
[1] NA
[1] TRUE
> comInvoke(rs,"Get","Name");comInvoke(rs,"Next")
[1] "Alton,Edgar I."
[1] TRUE
> comInvoke(rs,"Get","Name");comInvoke(rs,"Next")
[1] "Avery,Umberto K."
[1] TRUE

 "Next"はポインタをインクリメントさせています。

RCacheDirectクラスを利用したダイレクト接続

 Cache'側にダイレクト接続用の専用のクラス(RCacheDirect.cls)を作成し、R側にもrcomラッパー関数(RCacheDirect.R)を作成することで、rcomの制限を回避して正常なマルチバイト文字データを取り出すことが可能になります。
 下記のファイルをダウンロード後解凍し、C:直下に保存します。(RCacheDirectはGPL(>=2)です)
fileRCacheDirect.zip
 RCacheDirectフォルダ内のRCacheDirect.xmlをCache'スタジオをネームスペースUserで開き、[ツール][ローカルからのインポート]でCache'にインポートします。(自動的にコンパイルされRCacheDirect.clsが作成される)
 Rでの実行は、

> #RCacheDirect組み込み関数(rcomラッパー関数)
> source("C:/RCacheDirect/RCacheDirect.R")
> #初期化
> mInitialize()
[1] "初期化しました"
> #接続処理
> factory<-mCreateObject()
> channel<-mConnectDlg(factory) #Userを選択してください
> mConnect(factory,channel)
[1] TRUE

 Cache'に接続されました。次にRCacheDirect.clsへのインスタンスを作成します。

> #CacheObjectクラス(RCacheDirect.Class)へのインスタンス生成
> Obj<-mNew(factory)

 これで、RCacheDirect.clsに接続できました。
 (m*****()関数は、すべてrcomラッパー関数です)
 次にRからCache'にデータを書き込んでみます。(110Byte(デリミタ含)*10000レコード)

> dat50<-paste("1234567890","abcdefghij","まみむめも","abcdefghij","1234567890","まみむめも",sep=",")
> dat100<-paste(dat50,dat50,sep=",")
> i<-1:10000
> Command<-paste('^x(',i,') = "',dat100,'"',sep='')
> Command2<-paste("mSet(Obj,'",Command,"')",sep="")
> text2<-parse(text=Command2)
> eval(text2)
[1] 0

 書き込みが終了しました。(書き込み時間は2.5秒)
 [システム管理ポータル]で見ると、グローバル変数^x(*)にデータが入っていることが確認できます。
 次にグローバル変数^xからデータを取り出してみます。

>X<-NULL
>Command<-NULL;Command2<-NULL
> ValueName<-"x"
> MaxLine<-as.integer(mGetValue(Obj,paste('$O(^',ValueName,'(""),-1)',sep='')))
> Command<-paste("^",ValueName,"(1)",sep="")
> Command2<-paste("X[1] <-mGetValue(Obj,'",Command,"')",sep="")
> eval(parse(text=Command2))
> X
[1] "1234567890,abcdefghij,まみむめも,abcdefghij,1234567890,1234567890,abcdefghij,まみむめも,abcdefghij,1234567890"

 ^xの一行目のデータ^x(1)を取得しました。(マルチバイト文字も正常に取得できています)
 カラムに分解し、カラム数を計算します。

> X2<-unlist(strsplit(X,split=","))
> X2
 [1] "1234567890" "abcdefghij" "まみむめも" "abcdefghij" "1234567890" "1234567890" "abcdefghij" "まみむめも" "abcdefghij" "1234567890"
> FieldLen<-length(X2)
> FieldLen
[1] 10

 さて、実際に10000レコードを取り出してみます。

> i<-1:MaxLine
> X[i]<-""
> Command[i]<-"" ;Command2[i]<-""
> Command<-paste("^",ValueName,"(",i,")",sep="")
> Command2<-paste("X[",i,"] <-mGetValue(Obj,'",Command,"')",sep="")
> eval(parse(text=Command2))
> X3<-unlist(strsplit(X,split=","))
> X4<-matrix(X3,ncol=FieldLen,byrow=TRUE)
> X5<-as.data.frame(X4)

 これでデータフレームX5に^xのデータがすべて入りました。

> summary(X5)
         V1                 V2                 V3                 V4                 V5                 V6                 V7                 V8
1234567890:10000   abcdefghij:10000   まみむめも:10000   abcdefghij:10000   1234567890:10000   1234567890:10000   abcdefghij:10000   まみむめも:10000
         V9                V10
abcdefghij:10000   1234567890:10000

 このように、RからCache'へダイレクト接続してCache'を直に操作することができます。
 すなわち、Rのプログラム中の変数(データ)を直接データベースに永続保管することが可能となります。
更に、B-TREE構造での保管となるため、工夫をすればRのクラス構造(オブジェクト構造)をそのまま利用してデータベースにすることも可能でしょう。(これは非常に大きな意味を持ちます。何しろSQLデータベースにRのオブジェクトをそのまま保存できませんから。)

ブロック転送

 上記の実験では、1レコードのバイト数はデリミタを入れて110バイトでした。しかし、Cache'では1レコードのバイト数を32Kまで持つことができます。(Rでeval(parse())を使った場合書き込みに関して8Kの制限があります)
 要するに、1レコードづつ送るのではなく、1行を複数レコードにして一括で送ることができれば、IO処理が少ない分高速にデータを転送できるようになります。
 実際に1行に50レコードを持たせたブロック転送の実験(私のスタンドアロンの環境)では、10万レコードを約5秒でRに転送することができました。(Cache'への書き込みは10万レコードで約2秒でした)

Cache'からRを直接操作・利用する方法

Cache'からRを直接操作・利用するには、R(D)COMServerのタイプライブラリをActivateウイザードを用いて、Cache'にバインドします。(Winのみ)

RからODBC経由でCache'に接続する

http://www.okada.jp.org/RWiki/?%A5%C7%A1%BC%A5%BF%A5%D9%A1%BC%A5%B9%A4%C8R

Rユーザー会2007発表スライド