使用Avro和Spark重复,重复记录?

时间:2016-03-11 23:16:52

标签: scala apache-spark avro

我发生了一件奇怪的事:

import org.apache.avro.generic.{GenericData, GenericRecord}
import org.apache.avro.mapred.{AvroInputFormat, AvroWrapper, AvroKey}
import org.apache.avro.mapreduce.AvroKeyInputFormat
import org.apache.hadoop.io.{NullWritable, WritableUtils}

val path = "/path/to/data.avro"

val rdd = sc.newAPIHadoopFile(path, classOf[AvroKeyInputFormat[GenericRecord]], classOf[AvroKey[GenericRecord]], classOf[NullWritable])
rdd.take(10).foreach( x => println( x._1.datum() ))

在这种情况下,我得到了正确数量的记录返回,如果我查看rdd的内容,我会将各个记录视为tuple2的...但是,如果我在每个记录上打印如上所示,我得到了每次都有相同的结果。

显然这与Spark保持对其迭代的项目的引用有关,所以我需要在使用它之前克隆该对象。但是,如果我尝试克隆它,我会得到:

rdd.take(10).foreach( x => {
  val clonedDatum = x._1.datum().clone()
  println(clonedDatum.datum())
})

<console>:37: error: method clone in class Object cannot be accessed in org.apache.avro.generic.GenericRecord
 Access to protected method clone not permitted because
 prefix type org.apache.avro.generic.GenericRecord does not conform to
 class $iwC where the access take place
                val clonedDatum = x._1.datum().clone()

那么,我该如何克隆基准?

看起来我不是唯一遇到此问题的人:https://github.com/GoogleCloudPlatform/DataflowJavaSDK/issues/102。我无法弄清楚如何在我的情况下修复它,而不像链接公关中的那个人那样被黑客攻击。

建议?

1 个答案:

答案 0 :(得分:2)

在邮件列表的帮助下,我想我有点想通了。来自SparkContext API docs

  

&#39;&#39;&#39;注意:&#39;&#39;&#39;因为Hadoop的RecordReader类为每条记录重复使用相同的Writable对象,所以直接缓存返回的RDD或直接将其传递给聚合或shuffle操作将创建对同一对象的许多引用。如果您计划直接缓存,排序或聚合Hadoop可写对象,则应首先使用map函数复制它们。

所以,这就是我解决问题的方法:

val rdd = sc.newAPIHadoopFile(path, 
    classOf[AvroKeyInputFormat[GenericRecord]],
    classOf[AvroKey[GenericRecord]],
    classOf[NullWritable])
  .map(_._1.datum) // <-- added this

rdd.take(10).foreach(println)