【发布时间】:2021-08-17 18:25:46
【问题描述】:
我们使用的是 Spark 2.4.x。
我们的一个除法运算有精度损失(69362.86 / 111862.86) 这两个值在表上都定义为十进制(38,3)。当通过直线运行时,它会产生0.620070504187002,但当通过火花运行时,它会产生0.6200710。正如我们所看到的,spark 的结果有一个小数截断。在阅读更多内容后,我们偶然发现了 Spark 的故事 SPARK-29123。 comment 要求我们将参数spark.sql.decimalOperations.allowPrecisionLoss 设置为false 以避免精度损失。但是,在同一故事中还有另一个 comment 在无法精确表示十进制值时警告我们 null。堆栈溢出thread 没有谈到第二条评论中提到的警告。将此参数 spark.sql.decimalOperations.allowPrecisionLoss 设置为 false 并运行计算 (69362.86 / 111862.86) 会得到 0.620070504187002,这很好,但我们担心第二条评论中的警告。
根据sourcecode 中规定的规则,除法的精度和小数位数由以下公式确定。
Operation Result Precision Result Scale
e1 / e2 p1 - s1 + s2 + max(6, s1 + p2 + 1) max(6, s1 + p2 + 1)
根据这些规则,我的精度是(38 -3 +3 + max(6,3 +38 +1)) => 80,比例是max(6,3 +38 +1) => 42。由于这些都超过了 Precision 和 Scale 的默认限制 38,因此它们被减少到 38 和 6。修复此小数截断的一种方法是为输入列使用适当的小数精度和小数位数。我认为根据我们表中的数据,我们可以轻松地将除法中涉及的两列的输入精度设置为 18,比例设置为 5。在这种情况下,结果精度将是 38 和 24。这是足够好的精度和比例来表示我们的数据而没有任何明显的截断。但是我们不能对空间中的所有数字列手动执行此操作。所以我们正在考虑在集群级别将spark.sql.decimalOperations.allowPrecisionLoss 设置为false。我们有兴趣进一步了解当我们将此参数设置为 false 时结果将为 NULL 的情况,但如果将此参数保留为默认值,则会导致精度损失。
现在我的问题是,在什么情况下将此参数 spark.sql.decimalOperations.allowPrecisionLoss 设置为 false 会导致 null 但是当将其保留为默认值 (true) 时,我们会得到一些精度损失的值。你能提供任何我可以用来复制的例子吗?如果我们找不到这样的例子,我们是否可以在集群级别将此参数设置为 false,以便算术运算可以产生更好的结果?。
【问题讨论】:
标签: apache-spark apache-spark-sql decimal