[英]How to set default value to 'null' in Dataset parsed from RDD[String] applying Case Class as schema
[英]How to return successfully parsed rows that converted into my case class
我有一個文件,每一行都是一個 json 數組。 我讀取文件的每一行,並嘗試將行轉換為 json 數組,然后對於每個元素,我使用 json Spray 轉換為 case 類。
到目前為止我有這個:
for (line <- source.getLines().take(10)) {
val jsonArr = line.parseJson.convertTo[JsArray]
for (ele <- jsonArr.elements) {
val tryUser = Try(ele.convertTo[User])
}
}
如何將整個過程轉換為單行語句?
val users: Seq[User] = source.getLines.take(10).map(line => line.parseJson.convertTo[JsonArray].elements.map(ele => Try(ele.convertTo[User])
錯誤是:
發現:迭代器[無]
注意:我在所有示例中都使用了 Scala 2.13.6。
在這幾行代碼中有很多東西需要解壓。 首先,我將分享一些我們可以用來生成一些有意義的輸入的代碼。
object User {
import scala.util.Random
private def randomId: Int = Random.nextInt(900000) + 100000
private def randomName: String = Iterator
.continually(Random.nextInt(26) + 'a')
.map(_.toChar)
.take(6)
.mkString
def randomJson(): String = s"""{"id":$randomId,"name":"$randomName"}"""
def randomJsonArray(size: Int): String =
Iterator.continually(randomJson()).take(size).mkString("[", ",", "]")
}
final case class User(id: Int, name: String)
import scala.util.{Try, Success, Failure}
import spray.json._
import DefaultJsonProtocol._
implicit val UserFormat = jsonFormat2(User.apply)
這只是一些腳手架來定義一些User
域對象,並提出一種方法來生成此類對象數組的 JSON 表示,以便我們可以使用 JSON 庫(在本例中為spray-json
)將其解析回我們想要什么。
現在,回到你的問題。 這是一種將您的數據轉換成其解析表示的可能方法。 它可能無法 100% 適合您想要做的事情,但是所涉及的數據類型及其工作方式存在一些細微差別:
val parsedUsers: Iterator[Try[User]] =
for {
line <- Iterator.continually(User.randomJsonArray(4)).take(10)
element <- line.parseJson.convertTo[JsArray].elements
} yield Try(element.convertTo[User])
第一個區別:請注意,我以一種形式使用for
理解,其中迭代的“結果”不是副作用( for (something) { do something }
),而是for (something) yield { return a value }
的實際值for (something) yield { return a value }
)。
第二個區別:我明確要求使用Iterator[Try[User]]
而不是Seq[User]
。 我們可以深入探討為什么類型是它們在這里的主題,但簡單的解釋是for ... yield
表達式:
val ns: Iterator[Int]; for (n<- ns) ...
開頭val ns: Iterator[Int]; for (n<- ns) ...
val ns: Iterator[Int]; for (n<- ns) ...
你會得到一個迭代器一種可能的消費方式如下:
for (user <- parsedUsers) {
user match {
case Success(user) => println(s"parsed object $user")
case Failure(error) => println(s"ERROR: '${error.getMessage}'")
}
至於如何將其轉換為“單行”, for
推導式是編譯器應用的語法糖,它將每個嵌套調用轉換為flatMap
並將最后一個轉換為map
,如下例所示(產生等效的結果作為for
上面for
理解並且非常接近編譯器自動執行的操作):
val parsedUsers: Iterator[Try[User]] = Iterator
.continually(User.randomJsonArray(4))
.take(10)
.flatMap(line =>
line.parseJson
.convertTo[JsArray]
.elements
.map(element => Try(element.convertTo[User]))
)
我想補充的一點是,您應該注意可讀性。 有些球隊喜歡for
內涵,別人手動推出自己flatMap
/ map
鏈。 建議編碼人員酌情決定。
您可以在 Scastie 上使用此代碼( 這里是帶有flatMap
/ map
調用的版本)。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.