按聚合(求和)双精度分组会在火花中产生不一致的结果
grouping by aggregated (summed) double produces inconsistent results in spark
我发现 Scala 和 Spark 2.0 在聚合双打然后按聚合值分组时存在一些不一致的行为。这只发生在集群模式下,我相信它与双精度相加的顺序有关,产生的数字略有不同。在初始聚合之后,我对结果进行透视并按总和值进行分组。有时会看到 1 行,有时会看到 2 行,具体取决于小数点后 20 位左右的值略有变化。我无法展示完整的示例,但这是 REPL 中的一个 simplified/contrived 版本,它的行为正确但显示了我正在尝试做的事情:
scala> val df = List((1, "a", 27577661.013638947), (1, "a", 37577661.013538947)).toDF("a", "b", "c")
df: org.apache.spark.sql.DataFrame = [a: int, b: string ... 1 more field]
scala> df.show
+---+---+--------------------+
| a| b| c|
+---+---+--------------------+
| 1| a|2.7577661013638947E7|
| 1| a| 3.757766101353895E7|
+---+---+--------------------+
scala> val grouped = df.groupBy("a", "b").agg(sum("c").as("c"))
grouped: org.apache.spark.sql.DataFrame = [a: int, b: string ... 1 more field]
scala> grouped.show
+---+---+------------------+
| a| b| c|
+---+---+------------------+
| 1| a|6.51553220271779E7|
+---+---+------------------+
scala> val pivoted = grouped.groupBy("c").pivot("a").agg(first("b"))
pivoted: org.apache.spark.sql.DataFrame = [c: double, 1: string]
scala> pivoted.show
+------------------+---+
| c| 1|
+------------------+---+
|6.51553220271779E7| a|
+------------------+---+
问题出现在枢轴之后,我将在这里看到 2 行而不是预期的单行。
这是预期的吗?错误?任何解决方法?我试过使用 BigDecimal 与双精度、舍入、UDF 与列表达式,到目前为止没有任何帮助。谢谢!
预计:
- 浮点运算是not associative。 Spark 中的聚合顺序是不确定的,结果也是如此。
- 浮动键不是分组键的好选择。它们没有有意义的相等性(通常您检查差异是否小于机器精度)。在 Spark 中,聚合基于散列,您甚至不能使用这种相等性概念。
我发现 Scala 和 Spark 2.0 在聚合双打然后按聚合值分组时存在一些不一致的行为。这只发生在集群模式下,我相信它与双精度相加的顺序有关,产生的数字略有不同。在初始聚合之后,我对结果进行透视并按总和值进行分组。有时会看到 1 行,有时会看到 2 行,具体取决于小数点后 20 位左右的值略有变化。我无法展示完整的示例,但这是 REPL 中的一个 simplified/contrived 版本,它的行为正确但显示了我正在尝试做的事情:
scala> val df = List((1, "a", 27577661.013638947), (1, "a", 37577661.013538947)).toDF("a", "b", "c")
df: org.apache.spark.sql.DataFrame = [a: int, b: string ... 1 more field]
scala> df.show
+---+---+--------------------+
| a| b| c|
+---+---+--------------------+
| 1| a|2.7577661013638947E7|
| 1| a| 3.757766101353895E7|
+---+---+--------------------+
scala> val grouped = df.groupBy("a", "b").agg(sum("c").as("c"))
grouped: org.apache.spark.sql.DataFrame = [a: int, b: string ... 1 more field]
scala> grouped.show
+---+---+------------------+
| a| b| c|
+---+---+------------------+
| 1| a|6.51553220271779E7|
+---+---+------------------+
scala> val pivoted = grouped.groupBy("c").pivot("a").agg(first("b"))
pivoted: org.apache.spark.sql.DataFrame = [c: double, 1: string]
scala> pivoted.show
+------------------+---+
| c| 1|
+------------------+---+
|6.51553220271779E7| a|
+------------------+---+
问题出现在枢轴之后,我将在这里看到 2 行而不是预期的单行。
这是预期的吗?错误?任何解决方法?我试过使用 BigDecimal 与双精度、舍入、UDF 与列表达式,到目前为止没有任何帮助。谢谢!
预计:
- 浮点运算是not associative。 Spark 中的聚合顺序是不确定的,结果也是如此。
- 浮动键不是分组键的好选择。它们没有有意义的相等性(通常您检查差异是否小于机器精度)。在 Spark 中,聚合基于散列,您甚至不能使用这种相等性概念。