[英]Spark 2.0.0: How to aggregate DataSet with custom encoded types?
[英]Impossible to operate on custom type after it is encoded? Spark Dataset
假設你有這個(編碼自定義類型的解決方案是從這個線程帶來的):
// assume we handle custom type
class MyObj(val i: Int, val j: String)
implicit val myObjEncoder = org.apache.spark.sql.Encoders.kryo[MyObj]
val ds = spark.createDataset(Seq(new MyObj(1, "a"),new MyObj(2, "b"),new MyObj(3, "c")))
什么時候做ds.show
,我得到:
+--------------------+
| value|
+--------------------+
|[01 00 24 6C 69 6...|
|[01 00 24 6C 69 6...|
|[01 00 24 6C 69 6...|
+--------------------+
我知道這是因為內容被編碼為內部 Spark SQL 二進制表示。 但是我怎樣才能像這樣顯示解碼的內容呢?
+---+---+
| _1| _2|
+---+---+
| 1| a|
| 2| b|
| 3| c|
+---+---+
更新1
顯示內容不是最大的問題,更重要的是在處理數據集時可能會導致問題,請考慮以下示例:
// continue with the above code
val ds2 = spark.createDataset(Seq(new MyObj(2, "a"),new MyObj(6, "b"),new MyObj(5, "c")))
ds.joinWith(ds2, ds("i") === ds2("i"), "inner")
// this gives a Runtime error: org.apache.spark.sql.AnalysisException: Cannot resolve column name "i" among (value);
這是否意味着kryo
編碼類型不能方便地進行像joinWith
這樣的操作?
那么我們如何處理
Dataset
上的自定義類型呢?
如果我們在編碼后無法處理它,那么自定義類型的kryo
編碼解決方案有什么意義?!
(下面@jacek 提供的解決方案對於case class
類型很好,但它仍然無法解碼自定義類型)
以下對我有用,但似乎使用高級 API 來執行低級(反序列化)工作。
這並不是說應該這樣做,而是表明這是可能的。
我不知道為什么 KryoDeserializer 不會將字節反序列化為字節來自的對象。 就是這樣。
你的類定義和我的類定義之間的一個主要區別是這種case
讓我使用以下技巧。 同樣,不知道為什么它使它成為可能。
scala> println(spark.version)
3.0.1
// Note that case keyword
case class MyObj(val i: Int, val j: String)
import org.apache.spark.sql.Encoders
implicit val myObjEncoder = Encoders.kryo[MyObj]
// myObjEncoder: org.apache.spark.sql.Encoder[MyObj] = class[value[0]: binary]
val ds = (Seq(new MyObj(1, "a"),new MyObj(2, "b"),new MyObj(3, "c"))).toDS
// the Kryo deserializer gives bytes
scala> ds.printSchema
root
|-- value: binary (nullable = true)
scala> :type sc
org.apache.spark.SparkContext
// Let's deserialize the bytes into an object
import org.apache.spark.serializer.KryoSerializer
val ks = new KryoSerializer(sc.getConf)
// that begs for a generic UDF
val deserMyObj = udf { value: Array[Byte] =>
import java.nio.ByteBuffer
ks.newInstance.deserialize(ByteBuffer.wrap(value)).asInstanceOf[MyObj] }
val solution = ds.select(deserMyObj('value) as "result").select($"result.*")
scala> solution.show
+---+---+
| i| j|
+---+---+
| 1| a|
| 2| b|
| 3| c|
+---+---+
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.