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