通过聚合(求和)double进行分组会在spark中产生不一致的结果

时间:2017-03-07 21:46:10

标签: scala apache-spark pivot rounding aggregation

我看到Scala和Spark 2.0在聚合双精度然后按聚合值分组时会出现一些不一致的行为。这只发生在集群模式下,我认为它与双精度相加的顺序有关,产生的数字略有不同。在最初的聚合之后,我将结果和分组转换为求和值。有时看到1行,有时2行基于在小数点后20位左右稍微改变的值。我无法展示完整的示例,但这里是REPL中的一个简化/设计版本,其行为正确但显示了我正在尝试做的事情:

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行而不是预期的单行。

这是预期的吗?一个bug?任何解决方法?我已经尝试过使用BigDecimal vs double,舍入,UDF vs列表达式,到目前为止没有任何帮助。谢谢!

1 个答案:

答案 0 :(得分:1)

预计:

  • 浮点算术是not associative。 Spark中的聚合顺序是非确定性的,结果也是如此。
  • 浮动不是分组键的好选择。它们没有有意义的相等性(通常检查差异是否小于机器精度)。在Spark中,聚合基于哈希,你甚至不能使用这种平等概念。