【发布时间】:2019-02-11 23:42:34
【问题描述】:
我正在尝试按 DataFrame 的一列进行分组,并在每个结果组中生成 BigDecimal 列的 min 和 max 值。结果总是产生一个非常小的值(大约为 0)。
(类似的 min/max 调用 Double 列会产生预期的非零值。)
举个简单的例子:
如果我创建以下 DataFrame:
import org.apache.spark.sql.{functions => f}
case class Foo(group: String, bd_value: BigDecimal, d_value: Double)
val rdd = spark.sparkContext.parallelize(Seq(
Foo("A", BigDecimal("1.0"), 1.0),
Foo("B", BigDecimal("10.0"), 10.0),
Foo("B", BigDecimal("1.0"), 1.0),
Foo("C", BigDecimal("10.0"), 10.0),
Foo("C", BigDecimal("10.0"), 10.0),
Foo("C", BigDecimal("10.0"), 10.0)
))
val df = rdd.toDF()
在 Double 或 BigDecimal 列中选择 max 会返回预期结果:
df.select(f.max("d_value")).show()
// +------------+
// |max(d_value)|
// +------------+
// | 10.0|
// +------------+
df.select(f.max("bd_value")).show()
// +--------------------+
// | max(bd_value)|
// +--------------------+
// |10.00000000000000...|
// +--------------------+
但如果我分组然后聚合,我会得到 Double 列的合理结果,但 BigDecimal 列的值接近于零:
df.groupBy("group").agg(f.max("d_value")).show()
// +-----+------------+
// |group|max(d_value)|
// +-----+------------+
// | B| 10.0|
// | C| 10.0|
// | A| 1.0|
// +-----+------------+
df.groupBy("group").agg(f.max("bd_value")).show()
// +-----+-------------+
// |group|max(bd_value)|
// +-----+-------------+
// | B| 1.00E-16|
// | C| 1.00E-16|
// | A| 1.0E-17|
// +-----+-------------+
为什么 spark 对于这些 min/max 调用返回零结果?
【问题讨论】:
-
尝试一些不同的测试用例有助于优化问题 -
f.max返回的值似乎是正确值乘以 10^-17。例如,更改示例以使C组中的最大值为123456.0导致1.234560E-12作为最大值。因此,我们可以将问题缩小到“为什么在 groupBy 之后指数在 max 中被破坏?” -
另一个有趣的花絮:如果我将 RDD 创建为
Rows 的Seq并自己创建架构(使用与使用案例创建 DF 的架构中出现的相同Decimal(38, 18)类),我得到正确的行为。从元组序列中生成 DF 会产生同样的错误行为。所以,现在我们可以问“当我们从具有显式模式的 RDD 的行创建 DataFrame 时会发生什么,这与使用案例类或 Seq 不同,为什么后一种情况会破坏 BigDecimals 中的指数?”
标签: apache-spark apache-spark-sql bigdecimal