在collectAsList之后设置为空,即使在转换运算符中不为空

时间:2019-02-23 16:41:56

标签: apache-spark kotlin

我试图弄清楚我是否可以与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

1 个答案:

答案 0 :(得分:0)

这似乎是一个序列化问题。 Encoders.bean状态的文档(Spark v2.4.0):

  

集合类型:当前仅数组和java.util.List,正在进行地图支持

Transaction数据类移植到Java并将items更改为java.util.List似乎很有帮助。