我试图弄清楚我是否可以与Kotlin和Spark合作, 并使用前者的数据类代替Scala的案例类。
我具有以下数据类:
data class Transaction(var context: String = "", var epoch: Long = -1L, var items: HashSet<String> = HashSet()) :
Serializable {
companion object {
@JvmStatic
private val serialVersionUID = 1L
}
}
主例程的相关部分如下所示:
val transactionEncoder = Encoders.bean(Transaction::class.java)
val transactions = inputDataset
.groupByKey(KeyExtractor(), KeyExtractor.getKeyEncoder())
.mapGroups(TransactionCreator(), transactionEncoder)
.collectAsList()
transactions.forEach { println("collected Transaction=$it") }
TransactionCreator
定义为:
class TransactionCreator : MapGroupsFunction<Tuple2<String, Timestamp>, Row, Transaction> {
companion object {
@JvmStatic
private val serialVersionUID = 1L
}
override fun call(key: Tuple2<String, Timestamp>, values: MutableIterator<Row>): Transaction {
val seq = generateSequence { if (values.hasNext()) values.next().getString(2) else null }
val items = seq.toCollection(HashSet())
return Transaction(key._1, key._2.time, items).also { println("inside call Transaction=$it") }
}
}
但是,我认为我遇到了某种序列化问题, 因为集合在收集后最终为空。 我看到以下输出:
inside call Transaction=Transaction(context=context1, epoch=1000, items=[c])
inside call Transaction=Transaction(context=context1, epoch=0, items=[a, b])
collected Transaction=Transaction(context=context1, epoch=0, items=[])
collected Transaction=Transaction(context=context1, epoch=1000, items=[])
我尝试了一个自定义KryoRegistrator
,以查看Kotlin的HashSet
是否有问题:
class MyRegistrator : KryoRegistrator {
override fun registerClasses(kryo: Kryo) {
kryo.register(HashSet::class.java, JavaSerializer()) // kotlin's HashSet
}
}
但这似乎无济于事。 还有其他想法吗?
完整代码here。
答案 0 :(得分:0)
这似乎是一个序列化问题。
Encoders.bean
状态的文档(Spark v2.4.0):
集合类型:当前仅数组和java.util.List,正在进行地图支持
将Transaction
数据类移植到Java并将items
更改为java.util.List
似乎很有帮助。