使用spark 1.6.0 说我有这样的课程
case class MyClass(date: java.util.Date, oid: org.bson.types.ObjectId)
如果我有
//rdd: RDD[MyClass]
rdd.toDF("date", "oid")
我得到java.lang.UnsupportedOperationException: Schema for type java.util.Date/org.bson.types.ObjectId is not supported
现在我知道我可以将其设为java.sql.Date
,但让我们说MyClass
在很多其他地方都依赖于在任何地方做出改变,仍然无法解决ObjectId
问题。
我也知道UserDefinedType
选项。但似乎只有在你创建一个新的类来使用它时才有效(同样,MyClass
的签名需要保持不变)
是不是只能为java.util.Date
和org.bson.types.ObjectId
注册一个序列化器/解串器,以便我可以在toDF
上调用RDD[MyClass]
,它会起作用吗?
UPDATE
所以这并没有完全回答我的问题,但它解锁了我们,所以将在这里分享,希望它对其他人有帮助。所以大多数json库都支持这个用例,spark-sql有一个内置的sqlContext.read.json(stringRdd).write.parquet("/path/to/output")
。所以你可以使用你选择的json lib定义类的(de)ser,序列化为string,然后spark-sql可以处理其余的
答案 0 :(得分:0)
这取决于工作的含义。要序列化/反序列化对象,只需要相应的UserDefinedType
和正确的注释即可。例如:
@SQLUserDefinedType(udt = classOf[MyClassUDT])
case class MyClass(date: java.util.Date, oid: ObjectId)
class MyClassUDT extends UserDefinedType[MyClass] {
override def sqlType: StructType = StructType(Seq(
StructField("date", DateType, nullable = false),
StructField("oid", StringType, nullable = false)
))
override def serialize(obj: Any): InternalRow = {
obj match {
case MyClass(date, oid) =>
val row = new GenericMutableRow(2)
row(0) = new java.sql.Date(date.getTime)
row(1) = UTF8String.fromString(oid.toString)
row
}
}
override def deserialize(datum: Any): MyClass = {
datum match {
case row: InternalRow =>
val date: java.util.Date = new java.util.Date(
row.get(0, DateType).asInstanceOf[java.sql.Date].getTime()
)
val oid = new ObjectId(row.getString(1))
MyClass(date, oid)
}
}
override def userClass: Class[MyClass] = classOf[MyClass]
}
这并不意味着您将能够访问在类或其任何字段上定义的任何方法。为此,你需要UDF。
更接近无缝集成的是Spark数据集,但是AFAIK还不能定义自定义编码器。