2012-05-09 4 views
1

Я хотел бы использовать закрытие Groovy для обработки данных, поступающих из таблицы SQL. Для каждой новой строки вычисление будет зависеть от того, что было вычислено ранее. Тем не менее, новые строки могут появиться на последующих запусках приложения, поэтому я хотел бы иметь возможность перезагрузить закрытие, инициализированное промежуточным состоянием, которое оно имело, когда последнее завершение было выполнено в предыдущем запуске приложения.Сохранение состояния закрытия в Groovy

Например, укупорочное намереваясь вычислить скользящее среднее за 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 имеет 3 колонки: id (автоинкрементным первичный ключ), value и processed. Скользящее среднее рассчитывается на основе двух предыдущих значений и вводится в таблицу 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] (к примеру), и где я мог бы использовать c.setState ([ prev2Val: 1, prevVal: 2, prevId: 6]) в следующий раз, когда приложение выполняется (если есть состояние сохраняется).

Я также должен исключить sql из списка. Кажется, это можно сделать, используя [email protected]=null.

Я понимаю, что это вряд ли будет работать в общем случае, но я ищу что-то достаточно общее для большинства случаев. Я пробовал dehydrate, сериализую и rehydrate закрытие, как описано в this Groovy issue, но я не уверен, как сохранить и сохранить все поля @ за одну операцию.

Возможно ли это? Есть ли лучший способ запомнить состояние между выполнением, если предположить, что список переменных, используемых закрытием, не обязательно известен заранее?

ответ

2

Не уверен, что это сработает в конечном итоге, и вам может быть лучше вернуть список, содержащий значения, которые нужно передать в закрытие, чтобы получить следующий набор данных, но вы можете допросить привязку закрытия.

Дано:

def closure = { row -> 
    a = 1 
    b = 2 
    c = 4 
} 

Если вы выполняете его:

closure(1) 

Вы можете составить такую ​​функцию:

def extractVarsFromClosure(Closure cl) { 
    cl.binding.variables.findAll { 
    !it.key.startsWith('_') && it.key != 'args' 
    } 
} 

которые при выполнении:

println extractVarsFromClosure(closure) 

печатает:

['a':1, 'b':2, 'c':4] 

Тем не менее, любой 'свободные' переменное, определенные в локальном связывании (без def) будет находиться в затворах связывание тоже, так что:

fish = 42 
println extractVarsFromClosure(closure) 

будет печатать:

['a':1, 'b':2, 'c':4, 'fish':42] 

Но

def fish = 42 
println extractVarsFromClosure(closure) 

не печатает значение fish

+0

Точно такие проблемы, которые я ожидал. Кроме того, закрытие не имеет привязки, если я явно не даю ему делегата заранее (следуя некоторым из [этих предложений] (http://stackoverflow.com/a/3237296/372643)). Во всяком случае, это работает для того, что я пытаюсь сделать. Приветствия. – Bruno

Смежные вопросы