![](/img/trans.png)
[英]How to read optional json values in case class using scala combinators
[英]Using Spark converting nested json with optional fields to Scala case class not working
我有一個用例,我需要在 scala 中使用 spark 作為 Dataset[T] 讀取 json 文件或 json 字符串。 json 文件有嵌套元素,json 中的一些元素是可選的。 如果我忽略 json 中的可選字段,因為架構與案例類匹配,我可以讀取 json 文件並將它們映射到案例類。
根據此鏈接和答案,當案例類具有選項字段時,它適用於第一級 json,但如果存在嵌套元素,則它不起作用。
我正在使用的 Json 字符串如下:
val jsonString = """{
"Input" :
{
"field1" : "Test1",
"field2" : "Test2",
"field3Array" : [
{
"key1" : "Key123",
"key2" : ["keyxyz","keyAbc"]
}
]
},
"Output":
{
"field1" : "Test2",
"field2" : "Test3",
"requiredKey" : "RequiredKeyValue",
"field3Array" : [
{
"key1" : "Key123",
"key2" : ["keyxyz","keyAbc"]
}
]
}
}"""
我創建的案例類如下:
case class InternalFields (key1: String, key2 : Array[String])
case class Input(field1:String, field2: String,field3Array : Array[InternalFields])
case class Output(field1:String, field2: String,requiredKey : String,field3Array : Array[InternalFields])
case class ExternalObject(input : Input, output : Output)
我正在閱讀 jsonString 的代碼如下:
val df = spark.read.option("multiline","true").json(Seq(jsonString).toDS).as[ExternalObject]
上面的代碼工作得很好。 現在,當我在輸出案例類中添加一個可選字段作為 json 字符串可以讓它支持某些用例時,它會拋出一個錯誤,指出我在案例類中指定的可選字段丟失。
因此,為了解決這個問題,我繼續嘗試使用編碼器提供模式,看看是否可行。
添加可選字段后,我的案例類更改為如下:
case class InternalFields (key1: String, key2 : Array[String])
case class Input(field1:String, field2: String,field3Array : Array[InternalFields])
case class Output(field1:String, field2: String,requiredKey : String, optionalKey : Option[String],field3Array : Array[InternalFields]) //changed
case class ExternalObject(input : Input, output : Output)
在輸出案例類中添加了一個額外的可選字段。
現在我正在嘗試讀取 jsonString 如下:
import org.apache.spark.sql.Encoders
val schema = Encoders.product[ExternalObject].schema
val df = spark.read
.schema(schema)
.json(Seq(jsonString).toDS)
.as[ExternalObject]
當我執行 df.show 或 display(df) 時,它會為我提供如下輸出表,輸入列和輸出列都為空。
如果我從案例類中刪除該可選字段,則此代碼也可以正常工作並向我顯示預期的輸出。
有什么方法可以使內部 json 或內部案例類中的這個可選字段工作並將其直接轉換為數據集 [T] 中的相應案例類。
任何可以使其發揮作用的想法、指導和建議都會有很大幫助。
問題是 spark 使用 struct 類型將類映射到Row
,以此為例:
case class MyRow(a: String, b: String, c: Option[String])
spark可以創建一個數據框,有時有c
列,有時沒有? 喜歡:
+-----+-----+-----+
| a | b | c |
+-----+-----+-----+
| a1 | b1 | c1 |
+-----+-----+-----+
| a2 | b2 | <-- note the non-existence here :)
+-----+-----+-----+
| a3 | b3 | c3 |
+-----+-----+-----+
那么它不能,並且可以為空,意味着鍵必須存在,但值可以為空:
... other key values
"optionalKey": null,
...
這被認為是有效的,並且可以轉換為您的結構。 我建議你使用一個專用的 JSON 庫(你知道那里有很多),並使用 udf 或其他東西從 json 中提取你需要的東西。
我用以下案例類結構測試了上面的代碼庫
case class Field3Array(
key1: String,
key2: List[String]
)
case class Input(
field1: String,
field2: String,
field3Array: List[Field3Array]
)
case class Output(
field1: String,
field2: String,
requiredKey: String,
field3Array: List[Field3Array]
)
case class Root(
Input: Input,
Output: Output
)
Json 字符串不能像您嘗試過的那樣直接傳遞給 DataFrameReader,因為json
方法需要一個路徑。 我將JSON字符串放在一個文件中,並將文件路徑傳遞給DataFrameReader,結果如下
import org.apache.spark.sql.{Encoder,Encoders}
import org.apache.spark.sql.Dataset
case class Field3Array(
key1: String,
key2: List[String]
)
case class Input(
field1: String,
field2: String,
field3Array: List[Field3Array]
)
case class Output(
field1: String,
field2: String,
requiredKey: String,
field3Array: List[Field3Array]
)
case class Root(
Input: Input,
Output: Output
)
val pathToJson: String = "file:////path/to/json/file/on/local/filesystem"
val jsEncoder: Encoder[Root] = Encoders.product[Root]
val df: Dataset[Root] = spark.read.option("multiline","true").json(pathToJson).as[Root]
顯示結果如下:
df.show(false)
+--------------------------------------------+--------------------------------------------------------------+
|Input |Output |
+--------------------------------------------+--------------------------------------------------------------+
|[Test1, Test2, [[Key123, [keyxyz, keyAbc]]]]|[Test2, Test3, [[Key123, [keyxyz, keyAbc]]], RequiredKeyValue]|
+--------------------------------------------+--------------------------------------------------------------+
df.select("Input.field1").show()
+------+
|field1|
+------+
| Test1|
+------+
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.