在返回RDD的函数上执行flatmap

时间:2015-11-02 15:48:07

标签: apache-spark

我正在尝试在下面的代码中处理多个avro文件。我们的想法是先在列表中获取一系列avro文件。然后打开每个avro文件并生成元组的循环(string,int)。然后最后用密钥对元组流进行分组并对整数求和。

object AvroCopyUtil {
  def main(args: Array[String]) : Unit = {

    val conf = new SparkConf().setAppName("Leads Data Analysis").setMaster("local[*]")
    val sc = new SparkContext(conf)

    val fs = FileSystem.get(new Configuration())
    val avroList = GetAvroList(fs, args(0))
    avroList.flatMap(av =>
      sc.newAPIHadoopFile[AvroKey[GenericRecord], NullWritable, AvroKeyInputFormat[GenericRecord]](av)
        .map(r => (r._1.datum.get("field").toString, 1)))
      .reduceByKey(_ + _)
      .foreach(println)
  }


  def GetAvroList(fs: FileSystem, input: String) : List[String] = {
    // get all children
    val masterList : List[FileStatus] = fs.listStatus(new Path(input)).toList
    val (allFiles, allDirs) = masterList.partition(x => x.isDirectory == false)
    allFiles.map(_.getPath.toString) ::: allDirs.map(_.getPath.toString).flatMap(x => GetAvroList(fs, x))
  }
}

我得到的编译错误是

[error]  found   : org.apache.spark.rdd.RDD[(org.apache.avro.mapred.AvroKey[org.apache.avro.generic.GenericRecord], org.apache.hadoop.io.NullWritable)]
[error]  required: TraversableOnce[?]
[error]     avroRdd.flatMap(av => sc.newAPIHadoopFile[AvroKey[GenericRecord], NullWritable, AvroKeyInputFormat[GenericRecord]](av))
[error]                                                                                                                       ^
[error] one error found

编辑:根据下面的建议,我试过

val rdd = sc.newAPIHadoopFile[AvroKey[GenericRecord], NullWritable, 
AvroKeyInputFormat[GenericRecord]](avroList.mkString(","))

但是我收到了错误

Exception in thread "main" java.lang.IllegalArgumentException: java.net.URISyntaxException: Illegal character in scheme name at index 0: 2015-10-
15-00-1576041136-flumetracker.foo.com-FooAvroEvent.1444867200044.avro,hdfs:

1 个答案:

答案 0 :(得分:1)

您的功能是不必要的。您还试图在转换中创建一个RDD,这个转换并不真正有意义。转换(在这种情况下,flatMap)在RDD之上运行,RDD中的记录将是转换的内容。在flatMap的情况下,匿名函数的预期输出是TraversableOnce对象,然后通过转换将其展平为多个记录。看看你的代码,你真的不需要做flatMap因为简单map就足够了。请记住,由于RDD的不变性,您必须始终将转换重新分配给新值。

尝试类似:

val avroRDD = sc.newAPIHadoopFile[AvroKey[GenericRecord], NullWritable, AvroKeyInputFormat[GenericRecord]](filePath)
val countsRDD = avroRDD.map(av => (av._1.datum.get("field1").toString, 1)).reduceByKey(_ + _)

似乎您可能需要花一些时间来掌握Spark的一些基本框架细微差别。我建议您完全阅读Spark Programming Guide。最后,如果您想使用Avro,请查看spark-avro尽可能多地使用Avro处理锅炉板(并且DataFrames可能更直观,更易于用于您的用例)

(编辑:)

您似乎可能误解了如何加载要在Spark中处理的数据。 parallelize()方法用于跨RDD分发集合,而不是文件中的数据。要执行后者,您实际上只需要为newAPIHadoopFile()加载器提供以逗号分隔的输入文件列表。因此,假设您的GetAvroList()函数有效,您可以执行以下操作:

val avroList = GetAvroList(fs, args(0))
val avroRDD = sc.newAPIHadoopFile[AvroKey[GenericRecord], NullWritable, AvroKeyInputFormat[GenericRecord]](avroList.mkString(","))
val countsRDD = avroRDD.map(av => (av._1.datum.get("field1").toString, 1)).reduceByKey(_ + _)
flatMappedRDD.foreach(println)