1

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_dataid(自動インクリメントされた主キー)、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 回の操作で保存および保存する方法がわかりません。@

これは可能ですか?クロージャーによって使用される変数のリストが必ずしも事前にわかっていないと仮定して、実行間の状態を記憶するより良い方法はありますか?

4

1 に答える 1