Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/three.js/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Scala Spark:写入Avro文件_Scala_Serialization_Avro_Apache Spark - Fatal编程技术网

Scala Spark:写入Avro文件

Scala Spark:写入Avro文件,scala,serialization,avro,apache-spark,Scala,Serialization,Avro,Apache Spark,我在Spark,我有一个来自Avro文件的RDD。现在,我想对该RDD进行一些转换,并将其保存回Avro文件: val job = new Job(new Configuration()) AvroJob.setOutputKeySchema(job, getOutputSchema(inputSchema)) rdd.map(elem => (new SparkAvroKey(doTransformation(elem._1)), elem._2)) .saveAsNewAPIH

我在Spark,我有一个来自Avro文件的RDD。现在,我想对该RDD进行一些转换,并将其保存回Avro文件:

val job = new Job(new Configuration())
AvroJob.setOutputKeySchema(job, getOutputSchema(inputSchema))

rdd.map(elem => (new SparkAvroKey(doTransformation(elem._1)), elem._2))
   .saveAsNewAPIHadoopFile(outputPath, 
  classOf[AvroKey[GenericRecord]], 
  classOf[org.apache.hadoop.io.NullWritable], 
  classOf[AvroKeyOutputFormat[GenericRecord]], 
  job.getConfiguration)
运行此Spark时,会抱怨架构$recordSchema不可序列化

如果我取消对.map调用的注释(并且只使用rdd.saveAsNewAPIHadoopFile),调用将成功

我做错了什么


有什么想法吗?

Spark使用的默认序列化程序是Java序列化。因此,对于所有java类型,它将尝试使用java序列化进行序列化。AvroKey不可序列化,因此会出现错误

您可以在自定义序列化中使用KryoSerializer或插件(如Avro)。您可以在此处阅读有关序列化的更多信息


您还可以用可外化的东西包装对象。例如,在这里查看包装AvroFlumeEvent的SparkFlumeEvent:

这里的问题与作业中使用的avro.Schema类的不可序列化性有关。当您尝试从map函数内的代码引用schema对象时,会引发异常

例如,如果您尝试执行以下操作,则会出现“任务不可序列化”异常:

val schema = new Schema.Parser().parse(new File(jsonSchema))
...
rdd.map(t => {
  // reference to the schema object declared outside
  val record = new GenericData.Record(schema)
})
您只需在功能块内创建一个新的模式实例,即可使一切正常工作:

val schema = new Schema.Parser().parse(new File(jsonSchema))
// The schema above should not be used in closures, it's for other purposes
...
rdd.map(t => {
  // create a new Schema object
  val innserSchema = new Schema.Parser().parse(new File(jsonSchema))
  val record = new GenericData.Record(innserSchema)
  ...
})
由于您不希望为处理的每个记录解析avro模式,因此更好的解决方案是在分区级别解析模式。以下方法也有效:

val schema = new Schema.Parser().parse(new File(jsonSchema))
// The schema above should not be used in closures, it's for other purposes
...
rdd.mapPartitions(tuples => {
  // create a new Schema object
  val innserSchema = new Schema.Parser().parse(new File(jsonSchema))

  tuples.map(t => {
    val record = new GenericData.Record(innserSchema)
    ...
    // this closure will be bundled together with the outer one 
    // (no serialization issues)
  })
})
只要提供对jsonSchema文件的可移植引用,上述代码就可以工作,因为映射函数将由多个远程执行器执行。它可以是对HDFS中文件的引用,也可以与JAR中的应用程序一起打包(在后一种情况下,您将使用类装入器函数获取其内容)

对于那些试图将Avro与Spark一起使用的人,请注意,仍然存在一些未解决的编译问题,您必须在Maven POM上使用以下导入:

<dependency>
  <groupId>org.apache.avro</groupId>
  <artifactId>avro-mapred</artifactId>
  <version>1.7.7</version>
  <classifier>hadoop2</classifier>
<dependency>

org.apache.avro

.

使用dataframe,使用databrics库创建avro非常简单

dataframe.write.format(“com.databricks.spark.avro”).avro($hdfs\u路径)

在您的例子中,输入是avro,所以它将有与之关联的模式,这样您就可以直接将avro读入dataframe,在转换之后,您可以使用上述代码将其写入avro

要将avro读入数据帧:

火花1.6

val dataframe=sqlContext.read.avro($hdfs_path)或val dataframe= sqlContext.read.format(“com.databricks.spark.avro”).load($hdfs\u路径)

火花2.1

val dataframe=sparkSession.read.avro($hdfs_path)或val dataframe= sparkSession.read.format(“com.databricks.spark.avro”).load($hdfs\u路径)


您能提供异常堆栈跟踪吗?Spark、Hadoop和Avro版本号也可能有用。请原谅我的天真。请问这里的工作是什么?看起来像是地图缩小作业?如果我们使用spark来写,为什么我们需要一个map reduce作业?当map函数中没有外部依赖项时,这个方法可以很好地工作。有没有办法使模式可序列化?