当前位置: 首页 > 知识库问答 >
问题:

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

慕阳
2023-03-14

我之前已将Dataset[T]写入csv文件。

在本例中,T是一个case类,它包含字段x:Option[BigDecimal]

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

Exception in thread "main" org.apache.spark.sql.AnalysisException: Cannot up cast `x` from double to decimal(38,18) as it may truncate.

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

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

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

在本地机器上读写csv文件时,我已经编写了一些代码来读写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类现在包含所有,而不是预期的值。如果我只是将csv加载为具有推断类型的DF,则所有列值都被正确填充。

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

  1. 从双精度转换-

如有任何帮助/建议,将不胜感激。如果很容易从csv文件中写入/读取选项/大小数有问题,我很乐意调整我的方法。

共有1个答案

方焱
2023-03-14

首先,我将用dfB填充空值。不适用。填充(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()

首先将列cost显式转换为DecimalType(38,18),然后检索数据集[MyCaseClass]。我认为这里的问题是spark无法在没有明确指定缩放精度的情况下将double转换为BigDecimal,因此需要首先将其转换为特定的十进制类型,然后将其用作BigDecimal。

更新:我稍微修改了之前的代码,以便也可以处理Option[BigDecimal]类型的成员

祝你好运

 类似资料:
  • 问题内容: 在我的存储过程中,我通过了一个过滤器(使用“ WHERE Column IN”子句)作为参数。参数的值以CSV形式给出。将CSV转换为记录集的最佳方法是什么。 例子:- 我需要将名称作为参数传递给CSV字符串,例如 。 问题答案: 看看Erland Sommarskog的文章。他对做这种事情的不同方式有深入的了解: SQL Server中的数组和列表

  • 我只是想说清楚,我的意思是这样的- 另外,如果我访问第一个数组以外的元素,也会遇到同样的问题,即(INT*)arr+13。它会属于越界访问的条款吗?因为我是在第一个数组的边界之外访问的。

  • 主要内容:精确数字类型,数字类型,日期和时间类型,字符串,Unicode字符串,二进制字符串,T-SQL中使用的其他数据类型,T-SQL中流量控制的关键词SQL Server 中的数据类型是一个属性,它生成对象的数据。每个变量、列和表达式都与 T-SQL 中的数据类型相关。创建表时将根据需要为基于列的表选择特定的数据类型。 SQL Server 有七大类,包括多种数据类型。 精确数字类型 类型 最小值 最大值 Bigint -9,223,372,036,854,775,808 9,223,372

  • 问题内容: 我正在尝试在子句中构建case / if语句。 问题在于该列包含文本和数字。我要与之比较的列是一个整数。 有没有一种方法可以检测列是否包含字符或数字,然后将其设置为0,然后将其设置为0? 这是一个伪查询可以帮助您: 问题答案: 您正在寻找IsNumeric,但它并不总是有效(+,-和。是数字),因此您需要使用GBN所描述的解决方案,即在您的varchar中添加.0e0

  • 基本上,我想读取Apache Ignite上的查询返回的所有值,该查询返回一个IgniteCursor。 我想以非阻塞的方式读取光标。 我可以写: 也许我错过了什么? 换句话说,有一种方法可以使用“异步非阻塞IO”从Ignite获取记录列表?

  • 我使用的是Azure.data.tables nuget包的12.0.0-beta.6。当我尝试调用TableClient.GetQueryAsync时,它会给出错误: “类型”T“必须是引用类型,才能将其用作泛型类型或方法”TableClient.GetEntityAsync(string,string,IEnumerable,CancellationToken)“中的参数”T“。” 我看不出我