我有一个简单的火花代码,如下所示,我想查询大量的大十进制类型
test("SparkTest 0458") {
val spark = SparkSession.builder().master("local").appName("SparkTest0456").getOrCreate()
import spark.implicits._
val data =
(
new java.math.BigDecimal("819021675302547012738064321"),
new java.math.BigDecimal("819021675302547012738064321"),
new java.math.BigDecimal("819021675302547012738064321")
)
val df = spark.createDataset(Seq(data)).toDF("a", "b", "c")
df.show(truncate = false)
}
但是它显示3个空值
+----+----+----+
|a |b |c |
+----+----+----+
|null|null|null|
+----+----+----+
我会问这是怎么回事,谢谢
答案 0 :(得分:1)
问题的根源是十进制类型的模式推断机制。由于小数位数和精度都不是类型签名的一部分,因此Spark假定输入为decimal(38, 18)
:
df.printSchema
root
|-- a: decimal(38,18) (nullable = true)
|-- b: decimal(38,18) (nullable = true)
|-- c: decimal(38,18) (nullable = true)
这意味着您最多可以在小数点前存储20位数字,并且您使用的数字有26位数字。
据我所知,尚无直接与反射配合使用的解决方法,但可以将数据转换为Row
对象并显式提供架构。例如使用中间RDD
import org.apache.spark.sql.types._
import org.apache.spark.sql.Row
import java.math.BigDecimal
val schema = StructType(
Seq("a", "b", "c") map (c => StructField(c, DecimalType(38, 0)))
)
spark.createDataFrame(
sc.parallelize(Seq(data)) map(t => Row(t.productIterator.toSeq: _*)),
schema
)
或Kryo序列化数据集
import org.apache.spark.sql.{Encoder, Encoders}
import org.apache.spark.sql.catalyst.encoders.RowEncoder
spark.createDataset(Seq(data))(
Encoders.kryo: Encoder[(BigDecimal, BigDecimal, BigDecimal)]
).map(t => Row(t.productIterator.toSeq: _*))(RowEncoder(schema))