实际问题
如何将对象序列化为 ASCII 并再次从 ASCII 反序列化without必须对文件连接进行写入和读取(即从内存中的 ASCII)?
背景
在无状态的客户端-服务器框架中,我想使某些信息在调用中持久化(序列化 >> 发送到客户端 >> 从客户端返回序列化信息 >> 反序列化)而不将其缓存在服务器端。
请注意,我的 JSON 对象/strong 还包含其他未序列化的信息,因此与序列化信息混合,这就是为什么该方法在这个帖子 https://stackoverflow.com/questions/2258511/r-serialize-objects-to-text-file-and-back-again并不能完全解决问题。
现在,问题是我想反序列化仅基于已读取的 JSON 字符串的对象。可以这么说:来自“内存中 ASCII”而不是来自文件连接。我该怎么做呢?
这是我尝试过的:
require(forecast)
方法一
## SERVER: estimates initial model and writes JSON to socket
model <- auto.arima(AirPassengers, trace = TRUE)
## Model trace:
# ARIMA(2,1,2)(1,1,1)[12] : Inf
# ARIMA(0,1,0)(0,1,0)[12] : 967.6773
# ARIMA(1,1,0)(1,1,0)[12] : 965.4487
# ARIMA(0,1,1)(0,1,1)[12] : 957.1797
# ARIMA(0,1,1)(1,1,1)[12] : 963.5291
# ARIMA(0,1,1)(0,1,0)[12] : 956.7848
# ARIMA(1,1,1)(0,1,0)[12] : 959.4575
# ARIMA(0,1,2)(0,1,0)[12] : 958.8701
# ARIMA(1,1,2)(0,1,0)[12] : 961.3943
# ARIMA(0,1,1)(0,1,0)[12] : 956.7848
# ARIMA(0,1,1)(1,1,0)[12] : 964.7139
#
# Best model: ARIMA(0,1,1)(0,1,0)[12]
fc <- as.data.frame(forecast(model))
deparsed <- deparse(model)
json_out <- list(data = AirPassengers, model = deparsed, fc = fc)
json_out <- jsonlite::toJSON(json_out)
## CLIENT: keeps estimated model, updates data, writes to socket
json_in <- jsonlite::fromJSON(json_out)
json_in$data <- window(AirPassengers, end = 1949 + (1/12 * 14))
## SERVER: reads new JSON and applies model to new data
data <- json_in$data
model_0 <- json_in$model
model_1 <- eval(parse(text = model_0))
## Model trace:
# ARIMA(2,1,2)(1,1,1)[12] : Inf
# ARIMA(0,1,0)(0,1,0)[12] : 967.6773
# ARIMA(1,1,0)(1,1,0)[12] : 965.4487
# ARIMA(0,1,1)(0,1,1)[12] : 957.1797
# ARIMA(0,1,1)(1,1,1)[12] : 963.5291
# ARIMA(0,1,1)(0,1,0)[12] : 956.7848
# ARIMA(1,1,1)(0,1,0)[12] : 959.4575
# ARIMA(0,1,2)(0,1,0)[12] : 958.8701
# ARIMA(1,1,2)(0,1,0)[12] : 961.3943
# ARIMA(0,1,1)(0,1,0)[12] : 956.7848
# ARIMA(0,1,1)(1,1,0)[12] : 964.7139
#
# Best model: ARIMA(0,1,1)(0,1,0)[12]
# Warning message:
# In auto.arima(x = structure(list(x = structure(c(112, 118, 132, :
# Unable to fit final model using maximum likelihood. AIC value approximated
fc <- as.data.frame(forecast(Arima(data, model = model_1)))
## And so on ...
这可行,但请注意eval(parse(text = json_in$model))
实际上re-runs打电话给auto.arima()
而不是仅仅重新建立/反序列化对象(请注意打印到控制台的跟踪信息,我将其作为注释包含在内)。
这并不完全是我想要的,因为只是想以最快的方式重新建立最终的模型对象。
这就是为什么我转向serialize()
next.
方法2
## SERVER: estimates initial model and writes JSON to socket
model <- auto.arima(AirPassengers, trace = TRUE)
fc <- as.data.frame(forecast(model))
serialized <- serialize(model, NULL)
class(serialized)
json_out <- list(data = AirPassengers, model = serialized, fc = fc)
json_out <- jsonlite::toJSON(json_out)
## CLIENT: keeps estimated model, updates data, writes to socket
json_in <- jsonlite::fromJSON(json_out)
json_in$data <- window(AirPassengers, end = 1949 + (1/12 * 14))
## SERVER: reads new JSON and applies model to new data
data <- json_in$data
model_0 <- json_in$model
try(model_1 <- unserialize(model_0))
## --> error:
# Error in unserialize(model_0) :
# character vectors are no longer accepted by unserialize()
不幸的是,功能unserialize()
需要文件连接而不是“纯 ASCII”。
这就是为什么我需要执行以下解决方法。
方法3
## SERVER: estimates initial model and writes JSON to socket
model <- auto.arima(AirPassengers, trace = TRUE)
fc <- as.data.frame(forecast(model))
con <- file("serialized", "w+")
serialize(model, con)
close(con)
json_out <- list(data = AirPassengers, model = "serialized", fc = fc)
json_out <- jsonlite::toJSON(json_out)
## CLIENT: keeps estimated model, updates data, writes to socket
json_in <- jsonlite::fromJSON(json_out)
json_in$data <- window(AirPassengers, end = 1949 + (1/12 * 14))
## SERVER: reads new JSON and applies model to new data
data <- json_in$data
model_0 <- json_in$model
con <- file(model_0, "r+")
model_1 <- unserialize(con)
close(con)
fc <- as.data.frame(forecast(Arima(data, model = model_1)))
## And so on ...
现在反序列化工作无需实际auto.arima()
正在重新评估呼叫。但这违背了我的无状态范例,因为现在实际信息缓存在服务器端,而不是通过 JSON 对象/字符串实际发送。