NotSerializableException:org.apache.hadoop.io.LongWritable

时间:2015-10-05 07:29:18

标签: apache-spark

我知道这个问题已被多次回答,但我尝试了一切,但我没有找到解决方案。我有以下代码引发NotSerializableException

val ids : Seq[Long] = ...
ids.foreach{ id =>
 sc.sequenceFile("file", classOf[LongWritable], classOf[MyWritable]).lookup(new LongWritable(id))
}

出现以下异常

Caused by: java.io.NotSerializableException: org.apache.hadoop.io.LongWritable
Serialization stack:
...
org.apache.spark.serializer.JavaSerializationStream.writeObject(JavaSerializer.scala:47)
at org.apache.spark.serializer.JavaSerializerInstance.serialize(JavaSerializer.scala:84)
at org.apache.spark.util.ClosureCleaner$.ensureSerializable(ClosureCleaner.scala:301)

创建SparkContext时,我做

val sparkConfig = new SparkConf().setAppName("...").setMaster("...")
sparkConfig.set("spark.serializer", "org.apache.spark.serializer.KryoSerializer")
sparkConfig.registerKryoClasses(Array(classOf[BitString[_]], classOf[MinimalBitString], classOf[org.apache.hadoop.io.LongWritable]))
sparkConfig.set("spark.kryoserializer.classesToRegister", "org.apache.hadoop.io.LongWritable,org.apache.hadoop.io.Text,org.apache.hadoop.io.LongWritable")

并查看环境选项卡,我可以看到这些条目。但是,我不明白为什么

  1. 似乎没有使用Kryo序列化程序(堆栈没有提到Kryo)
  2. LongWritable未序列化。
  3. 我正在使用Apache Spark v.1.5.1

2 个答案:

答案 0 :(得分:4)

  1. 在循环内重复加载相同的数据是非常低效的。如果针对相同的数据执行操作,请加载一次并缓存:

    val rdd = sc
      .sequenceFile("file", classOf[LongWritable], classOf[MyWritable])
    
    rdd.cache()
    
  2. Spark并不认为Hadoop Writable可序列化。这是一个开放的JIRA(SPARK-2421)。要处理LongWritables简单get应该足够

    rdd.map{case (k, v) => k.get()}
    

    关于您的自定义类,您有责任解决此​​问题。

  3. 有效查找需要分区RDD。否则,它必须搜索RDD中的每个分区。

    import org.apache.spark.HashPartitioner
    
    val numPartitions: Int = ???
    val partitioned = rdd.partitionBy(new HashPartitioner(numPartitions))
    
  4. 一般来说,RDD不是为随机访问而设计的。即使定义了分区器lookup也必须线性搜索候选分区。在RDD中使用5000个均匀分布的密钥和10M对象,这很可能意味着在整个RDD上重复搜索。您可以选择避免这种情况:

    • 过滤器

      val idsSet = sc.broadcast(ids.toSet)
      rdd.filter{case (k, v) => idsSet.value.contains(k)}
      
    • 加入

      val idsRdd = sc.parallelize(ids).map((_, null)) 
      idsRdd.join(rdd).map{case (k, (_, v)) => (k, v)}
      
    • IndexedRDD - 它并不像一个特别活跃的项目

  5. 使用10M条目,您在本地搜索内存可能比使用Spark更好。对于较大的数据,您应该考虑使用正确的键值存储。

答案 1 :(得分:0)

我是apache spark的新手,但是试图解决你的问题,请评估它,如果它可以帮助你解决序列化的问题,它会发生因为spark-hadoop LongWritable和其他可写的问题没有序列化。

val temp_rdd = sc.parallelize(ids.map(id =>
sc.sequenceFile("file", classOf[LongWritable], classOf[LongWritable]).toArray.toSeq
)).flatMap(identity)

ids.foreach(id =>temp_rdd.lookup(new LongWritable(id)))