对于选项(null)的getOrElse,在Scala {null}中为空时不返回None类型或默认值

时间:2018-04-30 16:57:00

标签: scala apache-spark spark-dataframe optional-parameters

我正在尝试使用scala从一列数据初始化Spark中的列表。某些行中的值可以为空,并且在某些行中它的值已填充。所以我正在制作Option[String]类型的列表。但是,当我访问其中的元素时,scala会为每个元素返回Some,包括空值,即使它们已使用Option(null)初始化。这意味着当我尝试将值设为getOrElse("0")时,如果值应为" 0"则会打印Some()。在代码中,这就是我正在做的事情:

val columnsToRead: List[String] = List("__id", "device");

val selectedColumnsDataset: Array[List[(String, Option[String])]] =
    dataset.map(s => {columnsToUseForCorrelation
    .map(t => (t, Option(s.getAs[String](t))))
}).collect();

我确认,如果s.getAs[String](t)不在行中,则表达式t会返回null,方法是编写此备用地图

val selectedColumnsDataset2: Array[List[(String, Option[String])]] = 
    dataset.map(s => {columnsToUseForCorrelation
    .map(t => (t, s.getAs[String](t)))
    .map(t => (t._1, if (t._2 == null) Option(null) else Option(t._2)))
}).collect();

这两个表达式都返回相同的输出,所以我认为我正确地做了。我遇到的问题是当我尝试在这里打印出值时。我要做的第一件事就是将list转换为wrappedarray,我不明白隐式转换发生的位置,但如果我在地图上做了一个地图就会引发异常名单。这是我打印出这些值的代码:

    val selectedColumnsParsed = selectedColumnsDataset.asInstanceOf[Array[mutable.WrappedArray.ofRef[(String, Option[String])]]];

    selectedColumnsParsed.foreach(s => {
        s.foreach(t => {
        println(t._2.getOrElse("0"), t._2)
        })
    })

我从中获得的输出是

(440,Some(440))
(157,Some(157))
(441,Some(441))
(,Some())
(,Some())
(443,Some(443))
(,Some())

空值显示它们是空的,因此它们应该自动转换为None类型,但它们是Some类型,我不明白它们是怎样的他们不应该Some(null)。字符串看起来像是空的长度为0,但是在println语句中调用isEmpty会抛出空指针异常,这意味着getOrElse应该返回默认值0,但是它没有那样做。初始化Option类型以使nullNone类型匹配的正确方法是什么?

1 个答案:

答案 0 :(得分:1)

  

某些行中的值可以为空

空(空白)与null

不同
"".isEmpty
// Boolean = true

"" == null
// Boolean = false

因此Option为空字符串,不是None

Option("")
// Option[String] = Some()
  

我首先要做的一件事是将列表转换为wrappedarray,我不明白隐式转换发生在哪里,

这是因为Dataset中存储的数据已被编码。我们不依赖于具体的实现,而是依赖于接口。在这里你应该使用Seq

为了保持清洁,我会选择更简单的东西:

import org.apache.spark.sql.functions._

val columnsToRead: List[String] = List("__id", "device");
val dataset = Seq( 
  ("foo", null, 0),  // Here we expect None
  ("bar", "", -1),   // Here we expect Some("")
  ("xyz", "zyx", 1)
).toDF("__id", "device", "some_val")

dataset
  .select(array(columnsToRead map col: _*))
  .as[Seq[Option[String]]]
  .map(columnsToRead.zip(_))
  .collect.foreach(println)
// List((__id,Some(foo)), (device,None))
// List((__id,Some(bar)), (device,Some()))
// List((__id,Some(xyz)), (device,Some(zyx)))

dataset
  .select(columnsToRead map(c => struct(lit(c), col(c))): _*)
  .as[((String, Option[String]), (String, Option[String]))]
  .collect.foreach(println)

// ((__id,Some(foo)),(device,None))
// ((__id,Some(bar)),(device,Some()))
// ((__id,Some(xyz)),(device,Some(zyx)))

如果您希望空字符串为None,则必须明确处理此字符串。