I have implemented reading serialized object with plain JDBC, and now want to use Anorm 2.3.8.
Plain JDBC Scala code is as bellow:
def loadModel(rName: String, rPdbCode: String) = {
//Connection Initialization
Class.forName("org.mariadb.jdbc.Driver")
val jdbcUrl = s"jdbc:mysql://172.17.0.2:3306/db_profile?user=root&password=root"
val connection = DriverManager.getConnection(jdbcUrl)
//Reading Pre-trained model from Database
var model: InductiveClassifier[MLlibSVM, LabeledPoint] = null
if (!(connection.isClosed())) {
val sqlRead = connection.prepareStatement("SELECT r_model FROM MODELS WHERE r_name = ? and r_pdbCode = ?")
sqlRead.setString(1, rName)
sqlRead.setString(2, rPdbCode)
val rs = sqlRead.executeQuery()
rs.next()
val modelStream = rs.getObject("r_model").asInstanceOf[Array[Byte]]
val modelBaip = new ByteArrayInputStream(modelStream)
val modelOis = new ObjectInputStream(modelBaip)
model = modelOis.readObject().asInstanceOf[InductiveClassifier[MLlibSVM, LabeledPoint]]
rs.close
sqlRead.close
connection.close()
} else {
println("MariaDb Connection is Close")
System.exit(1)
}
model
}
Now I want to load my serialized model with amAnorm so everything is consistent with rest of my application and I only use the default connection.
Following is my effort but I can't convert Stream[Row]
to Array[Byte]
as it raises an exception:
ClassCastException: scala.collection.immutable.Stream$Cons cannot be cast to [B]
The Anorm 2.3.8 code is as bellow.
def loadModel(rName: String, rPdbCode: String) = {
//Connection Initialization
var model: InductiveClassifier[MLlibSVM, LabeledPoint] = null
DB.withConnection { implicit c =>
val results = SQL(
"""
| SELECT r_model
| FROM MODELS
| WHERE r_name={r_name}
| AND r_pdbCode={r_pdbCode};
""".stripMargin).on(
"r_name" -> rName,
"r_pdbCode" -> rPdbCode).apply()
val byteArray = results.asInstanceOf[Array[Byte]]
val modelBaip = new ByteArrayInputStream(byteArray)
val modelOis = new ObjectInputStream(modelBaip)
model = modelOis.readObject().asInstanceOf[InductiveClassifier[MLlibSVM, LabeledPoint]]
}
model
}
答案 0 :(得分:0)
此代码来自Anorm 2.5,但希望它与之前的版本没有什么不同。假设我们将Model
定义为
case class Model(i: Int, s: String) extends Serializable
这里是loadModel
和test-wrapper testLoadModel
使用简化表调用它
import anorm._
import java.io._
def loadModel(rName: String): Model = {
db.withConnection { implicit c =>
val result = SQL"""
SELECT r_model
FROM MODELS
WHERE r_name=${rName}
""".as(SqlParser.byteArray("r_model").single)
Logger.info(s"result ${result.getClass} => $result")
deserialize[Model](result)
}
}
def serialize(obj: Serializable): Array[Byte] = {
val outBuf = new ByteArrayOutputStream()
val out = new ObjectOutputStream(outBuf)
out.writeObject(obj)
out.flush()
outBuf.toByteArray
}
def deserialize[T](byteArray: Array[Byte]): T = {
val ois = new ObjectInputStream(new ByteArrayInputStream(byteArray))
ois.readObject().asInstanceOf[T]
}
def testLoadModel(): Unit = {
db.withConnection { implicit c =>
val createRes = SQL(
"""
|DROP TABLE IF EXISTS MODELS;
|
|CREATE TABLE MODELS(
| r_name VARCHAR(50) PRIMARY KEY NOT NULL,
| r_model VARBINARY NOT NULL
| );
""".
stripMargin).execute()
Logger.info(s"Create result = $createRes")
val rName = "rName"
val m0 = Model(42, "Abc")
val ser0 = serialize(m0)
val insertRes = SQL(
"""
| insert into MODELS values ({r_name},{r_model})
"""
.stripMargin).on("r_name" -> rName, "r_model" -> ser0).executeInsert()
Logger.info(s"Insert result = $insertRes")
val m1 = loadModel(rName)
Logger.info(s"m0 = $m0")
Logger.info(s"m1 = $m1")
}
}
主要技巧似乎是使用.as(SqlParser.byteArray("r_model").single)
。
请注意,如果无法保证记录的存在,您可能希望使用.singleOpt
。
此外,在查询中使用LIMIT 1
SQL clause以获得更好的性能也是有意义的。