首页 > 解决方案 > BigDecimal setScale 在 Spark UDF 中不起作用

问题描述

我试图将 json 列转换为映射。我尝试使用 udf 将 json 转换为 map。但它没有按预期工作。

val df1 = Seq(("{\"k\":10.004}")).toDF("json")
def udfJsonStrToMapDecimal = udf((jsonStr: String)=> { var jsonMap:Map[String,Any] = parse(jsonStr).values.asInstanceOf[Map[String, Any]]
     jsonMap.map{case(k,v) => (k,BigDecimal.decimal(v.asInstanceOf[Double]).setScale(6))}.toMap
})
val f = df1.withColumn("map",udfJsonStrToMapDecimal($"json"))
scala> f.printSchema
root
 |-- json: string (nullable = true)
 |-- map: map (nullable = true)
 |    |-- key: string
 |    |-- value: decimal(38,18) (valueContainsNull = true)

而不是十进制(38,6)它将值转换为十进制(38,18) 这里需要帮助

标签: scalaapache-spark

解决方案


默认的十进制精度是DecimalType(38, 18),我不确定您要做什么,但是

您可以将当前的十进制类型转换为

df1.withColumn("map",udfJsonStrToMapDecimal($"json").cast("map<string, decimal(38,6)>"))

架构:

root
 |-- json: string (nullable = true)
 |-- map: map (nullable = true)
 |    |-- key: string
 |    |-- value: decimal(38,6) (valueContainsNull = true)

或者您也可以定义模式并直接读取为 JSON

val schema = StructType(StructField("k", DecimalType(38, 6), nullable = false) :: Nil)

val df1 = Seq(("{\"k\":10.004}")).toDF("json")

val result = df1.withColumn("value", from_json($"json", schema))

架构:

root
 |-- json: string (nullable = true)
 |-- value: struct (nullable = true)
 |    |-- k: decimal(38,6) (nullable = true)

推荐阅读