getOrElse для Option (null) не возвращает тип None или значение по умолчанию, если в Scala значение NULL. - PullRequest
0 голосов
/ 30 апреля 2018

Я пытаюсь инициализировать список в Spark, используя scala, из столбца данных. Значение в некоторых строках может быть пустым, а в некоторых строках оно заполнено. Итак, я делаю свой список типа Option[String]. Но когда я обращаюсь к элементам в нем, scala возвращает Some для каждого элемента, включая пустые значения, даже если они были инициализированы с использованием Option(null). Это означает, что когда я пытаюсь получить значение как getOrElse("0"), он печатает Some(), если значение должно было быть «0». В коде это то, что я делаю:

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 не находится в строке, написав эту альтернативную карту

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, но вызов isEmpty в операторах println выдает исключение нулевого указателя, что означает, что getOrElse должен возвращать значение по умолчанию 0, но это не делает. Как правильно инициализировать тип Option, чтобы null соответствовал типу None?

1 Ответ

0 голосов
/ 30 апреля 2018

Значение в некоторых строках может быть пустым

Пусто (пусто) не совпадает с null:

"".isEmpty
// Boolean = true

"" == null
// Boolean = false

, следовательно, Option пустой строки, не None:

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

Одна вещь, которую я должен сделать в первую очередь, - преобразовать список в упакованный массив, который я не понимаю, где происходит неявное преобразование,

Это происходит потому, что данные, хранящиеся в 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, вам придется обрабатывать это явно.

...