我需要先用字母(A-Z)分割RDD,然后将文件分别写入目录。 简单的解决方案是为每个字母过滤RDD,但这需要26次通过。 对于写入文本文件here的类似问题有回应,但我无法弄清楚如何为Avro文件执行此操作。
有没有人能够做到这一点?
答案 0 :(得分:1)
您可以使用multipleoutputformat来执行此操作
这是一项两步任务: -
首先,您需要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]]
}
}
在您的驱动程序代码中,您必须提到您要使用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/