[英]Error: Unable to find encoder for type org.apache.spark.sql.Dataset[(String, Long)]
[英]How do I write a Dataset encoder to support mapping a function to a org.apache.spark.sql.Dataset[String] in Scala Spark
從 Spark 1.6 遷移到 Spark 2.2* 帶來了錯誤“錯誤:無法找到存儲在“數據集”中的類型的編碼器。 原始類型(Int、String 等)”,當嘗試將方法應用於查詢 Parquet 表返回的數據集時。 我已經過度簡化了我的代碼來演示相同的錯誤。 代碼查詢鑲木地板文件以返回以下數據類型: 'org.apache.spark.sql.Dataset[org.apache.spark.sql.Row]' 我應用一個函數來提取字符串和整數,返回一個字符串。 返回以下數據類型: Array[String] 接下來,我需要執行需要單獨函數的大量操作。 在這個測試函數中,我嘗試附加一個產生與我的詳細示例相同的錯誤的字符串。 我嘗試了一些編碼器示例並使用了“案例”,但還沒有提出可行的解決方案。 任何建議/示例將不勝感激
scala> var d1 = hive.executeQuery(st)
d1: org.apache.spark.sql.Dataset[org.apache.spark.sql.Row] = [cvdt35_message_id_d: string,
cvdt35_input_timestamp_s: decimal(16,5) ... 2 more fields]
val parseCVDP_parquet = (s:org.apache.spark.sql.Row) => s.getString(2).split("0x"
(1)+","+s.getDecimal(1);
scala> var d2 = d1.map(parseCVDP_parquet)
d2: org.apache.spark.sql.Dataset[String] = [value: string]
scala> d2.take(1)
20/03/25 19:01:08 WARN TaskSetManager: Stage 3 contains a task of very large size (131 KB). The
maximum recommended task size is 100 KB.
res10: Array[String] = Array(ab04006000504304,1522194407.95162)
scala> def dd(s:String){
| s + "some string"
| }
dd: (s: String)Unit
scala> var d3 = d2.map{s=> dd(s) }
<console>:47: error: Unable to find encoder for type stored in a Dataset. Primitive types (Int,
String, etc) and Product types (case classes) are supported by importing spark.implicits._ Support
for serializing other types will be added in future releases.
為了進一步提煉問題,我相信這種情況(盡管我還沒有嘗試過所有可能的解決方案)可以進一步簡化為以下代碼:
scala> var test = ( 1 to 3).map( _ => "just some words").toDS()
test: org.apache.spark.sql.Dataset[String] = [value: string]
scala> def f(s: String){
| s + "hi"
| }
f: (s: String)Unit
scala> var test2 = test.map{ s => f(s) }
<console>:42: error: Unable to find encoder for type stored in a Dataset.
Primitive types (Int, String, etc) and Product types (case classes) are
supported by importing spark.implicits._ Support for serializing other types
will be added in future releases.
var test2 = test.map{ s => f(s) }
我至少對我的簡化問題有一個解決方案(如下)。 我會測試更多......
scala> var test = ( 1 to 3).map( _ => "just some words").toDS()
test: org.apache.spark.sql.Dataset[String] = [value: string]
scala> def f(s: String): String = {
| val r = s + "hi"
| return r
| }
f: (s: String)String
scala> var test2 = test.rdd.map{ s => f(s) }
test2: org.apache.spark.rdd.RDD[String] = MapPartitionsRDD[17] at map at <console>:43
scala> test2.take(1)
res9: Array[String] = Array(just some wordshi)
第一個解決方案不適用於我的初始(生產)數據集,而是產生錯誤“org.apache.spark.SparkException:Task not serializable”(有趣的是,盡管兩者都存儲為相同的數據類型(org.apache.spark.sql) .Dataset[String] = [value: string]) 我認為是相關的。我在我的測試數據集中包含了另一個解決方案,該解決方案消除了初始編碼器錯誤,如圖所示實際上適用於我的玩具問題,不會上升到生產數據集。對於為什么我的應用程序在從 1.6 到 2.3 版本的移動中被擱置有點困惑,因為多年來我不必對我的應用程序進行任何特殊調整,並且已成功運行它以進行最有可能的計算數以萬億計。其他探索包括將我的方法包裝為 Serializable,探索 @transient 關鍵字,利用“org.apache.spark.serializer.KryoSerializer”,將我的方法編寫為函數並將所有變量更改為“vals”(以下重新 “堆棧”上的相關帖子)。
scala> import spark.implicits._
import spark.implicits._
scala> var test = ( 1 to 3).map( _ => "just some words").toDS()
test: org.apache.spark.sql.Dataset[String] = [value: string]
scala> def f(s: String): String = {
| val r = s + "hi"
| return r
| }
f: (s: String)String
scala> var d2 = test.map{s => f(s)}(Encoders.STRING)
d2: org.apache.spark.sql.Dataset[String] = [value: string]
scala> d2.take(1)
res0: Array[String] = Array(just some wordshi)
標度>
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.