spark kryo java,在Spark中自定义Kryo序列化输入输出API

虽然Kryo支持对RDD的cache和shuffle,但是在Spark中不是内置就显示提供使用Kryo将数据系列化到磁盘中的输入输出API,RDD中的saveAsObjectFile和SparkContext中的objectFile方法仅仅支持使用Java系列化。所以如果我们可以使用Kryo系列化将会变得很棒!

在这篇文章中,我将讨论如何自定义Kryo系列化输出输出相关API来将数据进行读写到磁盘中。

写数据

通常,我们使用rdd.saveAsObjectFile API将已经系列化的对象写入到磁盘中。下面的代码将展示如何使用我们自定义的saveAsObjectFile方法将已经使用kryo系列化的对象写入到磁盘中: def saveAsObjectFile[T: ClassTag](rdd: RDD[T], path: String)

这个函数中参数rdd就是我们需要写的数据;path是数据保存的路径。 val kryoSerializer = new KryoSerializer(rdd.context.getConf)

KryoSerializer是Spark内部提供的用于提供操作Kryo的类。在上述代码中,我们创建了KryoSerializer对象,并从rdd.context.getConf中获取传进来的缓存大小。 rdd.mapPartitions(iter => iter.grouped(10)

.map(_.toArray))

.map(splitArray => {}

所有的objectFile 将会在HDFS上保存,我们对RDD中的每个分片进行遍历,然后将他们转换成Byte数组。 val kryo = kryoSerializer.newKryo()

对每个splitArray,我们首先创建了kryo实例,kryo是线程不安全的,所以我们在每个map操作中单独创建。当我们调用kryoSerializer.newKryo()来创建新的kryo实例,他也会调用我们自定义的KryoRegistrator。 //create output stream and plug it to the kryo output

val bao = new ByteArrayOutputStream()

val output = kryoSerializer.newKryoOutput()

output.setOutputStream(bao)

kryo.writeClassAndObject(output, splitArray)

output.close()

一旦我们拥有kryo实例,我们就可以创建kryo输出对象,然后我们将类信息和对象写入到那个输出对象中。 val byteWritable = new BytesWritable(bao.toByteArray)

(NullWritable.get(), byteWritable)

}).saveAsSequenceFile(path)

我们在创建byteWritable的时候,包装了bytearray,然后保存成Sequence文件。使用那些代码我们就可以将Kryo对象写入到磁盘中。完整代码如下: /**

* User: 过往记忆

* Date: 15-04-24

* Time: 上午07:24

* bolg:

* 本文地址:/archives/1328

* 过往记忆博客,专注于hadoop、hive、spark、shark、flume的技术博客,大量的干货

* 过往记忆博客微信公共帐号:iteblog_hadoop

*/

def saveAsObjectFile[T: ClassTag](rdd: RDD[T], path: String) {

val kryoSerializer = new KryoSerializer(rdd.context.getConf)

rdd.mapPartitions(iter => iter.grouped(10)

.map(_.toArray))

.map(splitArray => {

//initializes kyro and calls your registrator class

val kryo = kryoSerializer.newKryo()

//convert data to bytes

val bao = new ByteArrayOutputStream()

val output = kryoSerializer.newKryoOutput()

output.setOutputStream(bao)

kryo.writeClassAndObject(output, splitArray)

output.close()

// We are ignoring key field of sequence file

val byteWritable = new BytesWritable(bao.toByteArray)

(NullWritable.get(), byteWritable)

}).saveAsSequenceFile(path)

}

光有写没有读对我们来说仍然不完美。通常我们使用sparkContext中的objectFile API从磁盘中读取数据,这里我们使用自定义的objectFile API来读取Kryo对象文件。 def objectFile[T](sc: SparkContext, path: String, minPartitions: Int = 1)

(implicit ct: ClassTag[T]) = {

val kryoSerializer = new KryoSerializer(sc.getConf)

sc.sequenceFile(path, classOf[NullWritable], classOf[BytesWritable],

minPartitions)

.flatMap(x => {

val kryo = kryoSerializer.newKryo()

val input = new Input()

input.setBuffer(x._2.getBytes)

val data = kryo.readClassAndObject(input)

val dataObject = data.asInstanceOf[Array[T]]

dataObject

})

}

上面的步骤和写的步骤很类似,只不过这里我们使用的是input,而不是output。我们从BytesWritable中读取bytes数据,然后使用readClassAndObject API反序列化数据。

如何使用

下面例子使用上面介绍的两个方法来系列化和反序列化Person对象: /**

* User: 过往记忆

* Date: 15-04-24

* Time: 上午07:24

* bolg:

* 本文地址:/archives/1328

* 过往记忆博客,专注于hadoop、hive、spark、shark、flume的技术博客,大量的干货

* 过往记忆博客微信公共帐号:iteblog_hadoop

*/

// user defined class that need to serialized

class Person(val name: String)

def main(args: Array[String]) {

if (args.length < 1) {

println("Please provide output path")

return

}

val outputPath = args(0)

val conf = new SparkConf().setMaster("local").setAppName("kryoexample")

conf.set("spark.serializer", "org.apache.spark.serializer.KryoSerializer")

val sc = new SparkContext(conf)

//create some dummy data

val personList = 1 to 10000 map (value => new Person(value + ""))

val personRDD = sc.makeRDD(personList)

saveAsObjectFile(personRDD, outputPath)

val rdd = objectFile[Person](sc, outputPath)

println(rdd.map(person => person.name).collect().toList)

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值