Spark Avro按键将RDD写入多个目录

时间:2016-05-20 23:18:34

标签: apache-spark

我需要先用字母(A-Z)分割RDD,然后将文件分别写入目录。 简单的解决方案是为每个字母过滤RDD,但这需要26次通过。 对于写入文本文件here的类似问题有回应,但我无法弄清楚如何为Avro文件执行此操作。

有没有人能够做到这一点?

2 个答案:

答案 0 :(得分:1)

您可以使用multipleoutputformat来执行此操作

这是一项两步任务: -

  1. 首先,您需要avro的多输出格式。以下是代码:

    package avro
    
    import org.apache.hadoop.mapred.lib.MultipleOutputFormat
    import org.apache.hadoop.fs.FileSystem
    import org.apache.hadoop.mapred.JobConf
    import org.apache.hadoop.util.Progressable
    import org.apache.avro.mapred.AvroOutputFormat
    import org.apache.avro.mapred.AvroWrapper
    import org.apache.hadoop.io.NullWritable
    import org.apache.spark.rdd.RDD
    import org.apache.hadoop.mapred.RecordWriter
    
    class MultipleAvroFileOutputFormat[K] extends MultipleOutputFormat[AvroWrapper[K], NullWritable] {
    val outputFormat = new AvroOutputFormat[K]
    
    override def generateFileNameForKeyValue(key: AvroWrapper[K], value: NullWritable, name: String) = {
    val name = key.datum().asInstanceOf[String].substring(0, 1)
    name + "/" + name
    }
    
    override def getBaseRecordWriter(fs: FileSystem,
    job: JobConf,
    name: String,
    arg3: Progressable) = {
    outputFormat.getRecordWriter(fs, job, name, arg3).asInstanceOf[RecordWriter[AvroWrapper[K], NullWritable]]
    }
    
    }
    
  2. 在您的驱动程序代码中,您必须提到您要使用Above given输出格式。您还需要提及avro数据的输出模式。下面是示例驱动程序代码,它以avro格式存储字符串的RDD,模式为 {" type":" string"}

    package avro
    
    import org.apache.spark.SparkConf
    import org.apache.spark.SparkContext
    import org.apache.hadoop.io.NullWritable
    import org.apache.spark._
    import org.apache.spark.SparkContext._
    import org.apache.hadoop.mapred.JobConf
    import org.apache.avro.mapred.AvroJob
    import org.apache.avro.mapred.AvroWrapper
    object AvroDemo {
    def main(args: Array[String]): Unit = {
    val conf = new SparkConf
    conf.setAppName(args(0));
    conf.setMaster("local[2]");
    conf.set("spark.serializer",   "org.apache.spark.serializer.KryoSerializer")
    conf.registerKryoClasses(Array(classOf[AvroWrapper[String]]))
    val sc = new SparkContext(conf);    
    val input = sc.parallelize(Seq("one", "two", "three", "four"), 1);
    val pairRDD = input.map(x => (new AvroWrapper(x), null));
    val job = new JobConf(sc.hadoopConfiguration)
    val schema = "{\"type\":\"string\"}"
    job.set(AvroJob.OUTPUT_SCHEMA, schema)  //set schema for avro output
    pairRDD.partitionBy(new HashPartitioner(26)).saveAsHadoopFile(args(1),  classOf[AvroWrapper[String]], classOf[NullWritable], classOf[MultipleAvroFileOutputFormat[String]], job, None);
    sc.stop()
    }  
    }
    

答案 1 :(得分:0)

我希望你能得到比我更好的答案......

我自己也处于类似情况,除了" ORC"而不是Avro。我基本上把手拉起来,最后直接调用ORC文件类来自己编写文件。

在您的情况下,我的方法需要通过" partitionBy"来分割数据。进入26个分区,每个首字母A-Z一个。然后调用" mapPartitionsWithIndex",将一个输出第i个分区的函数传递给适当路径的Avro文件。最后,为了说服Spark实际做某事,请让mapPartitionsWithIndex返回一个包含单个布尔值的List" true&#34 ;;然后拨打" count"在mapPartitionsWithIndex返回的RDD上,让Spark开始播放。

我在这里找到了编写Avro文件的示例:http://www.myhadoopexamples.com/2015/06/19/merging-small-files-into-avro-file-2/