Spark SQL - 将csv读入数据集[T],其中T是Option [BigDecimal]字段的case类

时间:2018-03-26 12:10:09

标签: apache-spark-sql apache-spark-dataset

我之前已将数据集[T]写入csv文件。

在这种情况下,T是包含字段x的案例类:Option [BigDecimal]

当我尝试将文件加载回数据集[T]时,我看到以下错误:

线程“main”中的异常org.apache.spark.sql.AnalysisException:无法将x从double转换为十进制(38,18),因为它可能会被截断。

我想原因是推断的架构包含double而不是BigDecimal列。有没有解决这个问题的方法?我希望避免基于列名进行强制转换,因为读取的代码是泛型函数的一部分。我的阅读代码如下:

   val a = spark
    .read
    .format("com.databricks.spark.csv")
    .option("header", "true")
    .option("inferSchema", "true")
    .load(file)
    .as[T]

我的案例类反映了从JDBC读取的表,其中Option [T]用于表示可空字段。 Option [BigDecimal]用于从JDBC接收Decimal字段。

在本地计算机上读/写时,我已经对一些代码进行了读/写csv文件的操作,因此我可以轻松地检查内容。

所以我的下一次尝试是这样的:

   var df = spark
    .read
    .format("com.databricks.spark.csv")
    .option("header", "true")
    .schema(implicitly[Encoder[T]].schema)
    .load(file)

  val schema = df.schema

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

  schema.foreach{ field =>
    field.dataType match {
      case t: DoubleType =>
        df = df.withColumn(field.name, 
          col(field.name).cast(DecimalType(38,18)))
      case _ => // do nothing
    }
  }

  df.as[T]

不幸的是,我的case类现在包含所有Nones而不是预期的值。如果我只是将csv加载为具有推断类型的DF,则会正确填充所有列值。

看起来我实际上有两个问题。

  1. 从双人转换 - > BigDecimal的。
  2. Nullable字段未包含在Options中。
  3. 感谢任何帮助/建议。如果从csv文件中轻松地编写/读取Options / BigDecimals是有问题的,那么很乐意调整我的方法。

1 个答案:

答案 0 :(得分:1)

首先我会用dfB.na.fill(0.0)填充空值然后我会尝试下一个解决方案:

case class MyCaseClass(id: String, cost: Option[BigDecimal])
var dfB = spark.createDataset(Seq(
  ("a", Option(12.45)),
  ("b", Option(null.asInstanceOf[Double])),
  ("c", Option(123.33)),
  ("d", Option(1.3444))
)).toDF("id", "cost")

dfB
  .na.fill(0.0)
  .withColumn("cost", col("cost").cast(DecimalType(38,18)))
  .as[MyCaseClass]
  .show()

首先将列成本显式转换为DecimalType(38,18),然后检索数据集[MyCaseClass]。我认为这里的问题是,火花不能将double转换为BigDecimal而不明确指定缩放精度,因此您首先需要将其转换为特定的十进制类型,然后将其用作BigDecimal。

<强>更新 我稍微修改了以前的代码,以便能够处理类型为Option [BigDecimal]的成员

祝你好运