簡體   English   中英

編碼后無法對自定義類型進行操作? Spark 數據集

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM