Cache'は基本的にデータベースであるため、統計解析エンジンを持っていない。ここでは、Cache'と統計解析言語R(アール)を相互に利用する技術について解説する。
RからCache'を直接操作・利用する方法
RからCache'を直接操作するには、Cache' ActiveXバインディングとRのパッケージrcomを利用します。(WINのみ)
前提条件として、Rのインストール、rcomパッケージのインストール、Cache'評価版のインストールを事前におこなっておいてください。
(注)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)です)
RCacheDirect.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