Groovy クロージャーを使用して、SQL テーブルからのデータを処理したいと考えています。新しい行ごとに、計算は以前に計算されたものに依存します。ただし、アプリケーションをさらに実行すると新しい行が使用可能になる可能性があるため、アプリケーションの前回の実行でクロージャが最後に実行されたときの中間状態で初期化されたクロージャをリロードできるようにしたいと考えています。
たとえば、3 行の移動平均を計算するクロージャは、次のように実装されます。
def prev2Val = null
def prevVal = null
def prevId = null
Closure c = { row ->
println([ prev2Val, prevVal, prevId])
def latestVal = row['val']
if (prev2Val != null) {
def movMean = (prev2Val + prevVal + latestVal) / 3
sql.execute("INSERT INTO output(id, val) VALUES (?, ?)", [prevId, movMean])
}
sql.execute("UPDATE test_data SET processed=TRUE WHERE id=?", [row['id']])
prev2Val = prevVal
prevVal = latestVal
prevId = row['id']
}
test_data
id
(自動インクリメントされた主キー)、value
およびの3 つの列がありprocessed
ます。前の 2 つの値に基づいて移動平均が計算され、前の行のoutput
に対してテーブルに挿入されます。id
処理された行には のフラグが付けられprocessed=TRUE
ます。
すべてのデータが最初から利用可能であった場合、これは次のように呼び出すことができます。
sql.eachRow("SELECT id, val FROM test_data WHERE processed=FALSE ORDER BY id", c)
問題は、アプリケーションが既に実行された後に新しい行が使用可能になったときに発生します。これは、毎回小さなバッチを処理することでシミュレートできます (たとえばLIMIT 5
、前のステートメントで使用)。
実行の最後にクロージャーの完全な状態をダンプしeachRow
(たとえば、中間データをデータベースのどこかに保存する)、アプリケーション全体を再実行するときに再度初期化できるようにしたいと思います(ロードすることにより)データベースからのそれらの中間変数)。
この特定の例ではprev2Val
、 、prevVal
、の値を格納することで手動でこれを行うことができますが、prevId
どの変数が使用されているかを正確に知る必要がない一般的なソリューションを探しています。
おそらく、c.getState()
どちらが返されるか[ prev2Val: 1, prevVal: 2, prevId: 6]
(たとえば)、[ prev2Val: 1, prevVal: 2, prevId: 6]
次にアプリケーションが実行されるときに c.setState( ) を使用できる場所 (状態が格納されている場合) のようなものです。
また、リストから除外する必要がありsql
ます。を使えばできるようc.@sql=null
です。
これが一般的なケースではうまくいかないことはわかっていますが、ほとんどのケースで十分に一般的なものを探しています。この Groovy issuedehydrate
で説明されているように、シリアライズとrehydrate
クロージャーを試みましたが、すべてのフィールドを 1 回の操作で保存および保存する方法がわかりません。@
これは可能ですか?クロージャーによって使用される変数のリストが必ずしも事前にわかっていないと仮定して、実行間の状態を記憶するより良い方法はありますか?