digestとfilehashで適当に永続化

概要

d:id:hotoku:20120328 で、S4オブジェクトの中にキャッシュを持つ方法を考えたが、先のコードのままでは、オブジェクト自身以外の引数がある場合には上手くいかない。また、当たり前だけど、メモリにキャッシュがあるのでRを終了したらキャッシュも消える。だので、関数の引数を直列化してkey value storeでディスクに置く事を考えた。digestfilehashというライブラリを使った実装をメモ。

digestライブラリ

Rオブジェクトを直列化した後、色んな関数でハッシュ値を計算して文字列で返してくれるライブラリ。

> library(digest)
> digest(1:10)
[1] "c08951d2c283a799ab013bf845ed822e"

こんな感じ。

filehashライブラリ

お手軽key value storeライブラリ。

> library(filehash)
> db.file <- "filehash_test"
> dbCreate(db.file) # カレントディレクトリに"filehash_test"というファイルが出来る
[1] TRUE
> db <- dbInit(db.file)   # dbオブジェクト作成
> dbInsert(db, "a", 1:10) # 値の挿入
> dbFetch(db, "a")        # 値の取得
 [1]  1  2  3  4  5  6  7  8  9 10
> db$a #こういうアクセスも用意されている
 [1]  1  2  3  4  5  6  7  8  9 10
> db[["a"]] #こういうアクセスも用意されている その2
 [1]  1  2  3  4  5  6  7  8  9 10

コード例

library(filehash)
library(digest)




setClass("someClass", representation(db="filehash",
                                     pow="numeric"))
setMethod("initialize", "someClass",
          function(.Object, pow){
            .Object@db <- dbInit("filehash_test")
            .Object@pow <- pow
            .Object
          })

setGeneric("veryHeavyCalculation", function(obj, arg)standardGeneric("veryHeavyCalculation"))
setMethod("veryHeavyCalculation",
          signature(obj="someClass", arg="numeric"),
          function(obj, arg){
            key <- digest(list(pow=obj@pow, arg=arg))
            if(dbExists(obj@db, key)) return(dbFetch(obj@db, key))
            cat("executing very heavy calculation\n")
            val <- sum(arg^obj@pow)
            dbInsert(obj@db, key, val)
            val
          })


obj <- new("someClass", 3)
veryHeavyCalculation(obj, 1:10) # 真面目に計算
veryHeavyCalculation(obj, 1:10) # key value storeから取得