這次不扯蛋,直接開講。
該問題的本質是序列化問題!!!序列化問題!!!序列化問題!!!
重要問題說三遍。
把對象轉換爲字節序列的過程稱爲對象的序列化。
把字節序列恢復爲對象的過程稱爲對象的反序列化。
序列化和反序列化爲的是對象經過傳輸(也可能是通過文件方式)後,程序還能對他進行還原成對應object。
序列化 詳解 左拐 https://www.cnblogs.com/xdp-gacl/p/3777987.html
那麼爲什麼會報上面那個問題呢?
因爲你傳輸的對象沒有序列化,或者序列化錯誤。java中序列化 是 java.io.Serializable;
但是 該序列化方式開銷比較大,如果使用網絡傳輸大量對象,那麼可能造成帶寬的大量浪費。所以spark自己搞了個序列化方式。org.apache.spark.serializer.KryoSerializer。該序列化方式好處是開銷小。
spark 2.0以上版本 默認org.apache.spark.serializer.KryoSerializer序列化方式。如果你使用java 序列化那麼鐵定跪了。所以統一spark序列化方式 要不是這 spark成java序列化方式
conf.set("spark.serializer", "org.apache.spark.serializer.JavaSerializer")
要不對象註冊成 KryoSerializer序列化方式。
conf.set("spark.serializer", "org.apache.spark.serializer.KryoSerializer")
conf.set("spark.kryo.registrationRequired", "true")
var arrclasses: Array[Class[_]] =Array(classOf[Sub], classOf[DMPUser],
classOf[SubType], classOf[org.apache.avro.generic.GenericData.Array[_]], classOf[BasicTag]
, classOf[ExtendTag], classOf[org.apache.avro.util.Utf8], classOf[java.util.HashMap[_, _]], classOf[java.util.Map[_, _]]
, classOf[java.util.ArrayList[_]], classOf[java.util.List[_]], classOf[java.lang.CharSequence])
conf.registerKryoClasses(arrclasses)
但是有時 使用KryoSerializer註冊也不是很方便。比如你用avro格式定義的嵌套格式。完了和我上面的例子一樣 需要註冊一大堆類。還不一定註冊全。那麼怎麼辦呢。
通用解決方式:
寫代碼 實現 objectToByte 和 byteToObject 方法。在有傳輸操作地方 將object轉換成byte數組,在接收操作地方再轉回來。
對於初學各種大數據格式的小朋友會遇到問題。比如 avro自動生成的類報上面錯,無從下手。主要是 對avro理解錯誤。avro提供序列化方式,但是使用avro工具生成的類本身沒有序列化!!!但是使用avro工具生成的類本身沒有序列化!!!但是使用avro工具生成的類本身沒有序列化!!!。avro提供了序列化類,例如DatumReader。
如果使用scala編程,可以使用case class來定義類。case class 默認實現了java 序列化方式。