Yaoxuan Wu created SPARK-60150:
----------------------------------

             Summary: A filter pushed below a DISTINCT on a float key returns a 
row that fails the predicate
                 Key: SPARK-60150
                 URL: https://issues.apache.org/jira/browse/SPARK-60150
             Project: Spark
          Issue Type: Bug
          Components: Optimizer
    Affects Versions: 4.1.1, 4.2.0, 3.5.8, 4.0.0, 5.0.0
            Reporter: Yaoxuan Wu


A DISTINCT (or GROUP BY, INTERSECT ALL) on a DOUBLE key outputs -0.0 as 0.0. A 
filter above it is pushed below the aggregate, where it sees the raw -0.0. The 
output then contains 0.0 although the predicate is false for 0.0.

 
{code:java}
from pyspark.sql import SparkSession
spark = SparkSession.builder.getOrCreate()
spark.createDataFrame([(-0.0,)], "x double").createOrReplaceTempView("t")

spark.sql("SELECT x, cast(x AS STRING) = '-0.0' AS p FROM (SELECT DISTINCT x 
FROM t)").collect()
# [Row(x=0.0, p=False)]

spark.sql("SELECT * FROM (SELECT DISTINCT x FROM t) WHERE cast(x AS STRING) = 
'-0.0'").collect()
# expected:    []
# Spark 4.2.0: [Row(x=0.0)] {code}
The same happens with {{GROUP BY x}} ({{{}[Row(x=0.0, c=1)]{}}}), {{{}INTERSECT 
ALL{}}}, {{subtract}} and {{{}dropDuplicates{}}}, on 3.5.8, 4.0.0, 4.1.1, 4.2.0 
and master. With {{spark.sql.optimizer.excludedRules}} set to 
{{PushDownPredicates,PushPredicateThroughNonJoin}} the result is {{{}[]{}}}.

 

Optimized plan:
{code:java}
Aggregate [x#0], [x#0]
+- Filter (isnotnull(x#0) AND (cast(x#0 as string) = -0.0))
   +- LogicalRDD [x#0], false {code}
and in the physical plan the aggregate groups by 
{{{}knownfloatingpointnormalized(normalizenanandzero(x#0)){}}}.

*Cause:* the rule treats a grouping key as having the same value above and 
below the Aggregate. {{NormalizeFloatingNumbers}} breaks this for float/double 
keys (-0.0 to 0.0, NaN canonicalization). The rule should not push a predicate 
that reads such a key, or should normalize the key inside the pushed predicate.

This is the same assumption as in SPARK-60093 
({{{}RemoveRedundantAggregates{}}}), in a different rule.

How it was found: a property-based testing tool checked that splitting a query 
result by a predicate p into the rows where p is true, false and NULL gives 
back the original result. Here the row 0.0 was counted under both {{p}} and 
{{{}p IS NULL{}}}.



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to