Aditya Ranjan created SPARK-60865:
-------------------------------------

             Summary: assertDataFrameEqual fails for unordered rows with 
floating-point tolerance
                 Key: SPARK-60865
                 URL: https://issues.apache.org/jira/browse/SPARK-60865
             Project: Spark
          Issue Type: Bug
          Components: PySpark
    Affects Versions: 4.2.0
            Reporter: Aditya Ranjan


h3. Problem

{{pyspark.testing.assertDataFrameEqual}} can incorrectly report unequal rows 
when {{checkRowOrder=False}} and floating-point values compare equal within the 
configured {{rtol}} and {{atol}} tolerances.

The current implementation sorts rows using their string representations and 
compares the sorted rows positionally. Lexicographic string ordering does not 
preserve tolerance-aware numerical equality.

Consequently, two collections of rows can have a valid one-to-one matching 
while the positional comparison fails.
h3. Steps to Reproduce

{{from pyspark.sql import Row
from pyspark.testing import assertDataFrameEqual

actual = [
    Row(value=0.0),
    Row(value=0.1),
]

expected = [
    Row(value=0.1),
    Row(value=0.2),
]

assertDataFrameEqual(
    actual,
    expected,
    rtol=0,
    atol=0.11,
    checkRowOrder=False,
)}}
h3. Actual Behavior

The assertion can fail even though every actual row can be matched uniquely to 
an expected row within the configured absolute tolerance.
h3. Expected Behavior

When {{{}checkRowOrder=False{}}}, the assertion should succeed if a complete 
one-to-one matching exists between the actual and expected rows under the 
configured comparison tolerances.

When {{{}checkRowOrder=True{}}}, positional comparison should remain enforced.

Genuinely unequal rows must continue to fail.
h3. Root Cause

Sorting rows by {{str(row)}} followed by positional comparison is not 
sufficient for unordered, tolerance-aware comparisons.

A greedy matching strategy can also fail when tolerance ranges overlap and an 
earlier match needs reassignment.
h3. Proposed Fix

Retain the existing deterministic sorting and fast positional comparison.

If positional comparison fails for equally sized unordered collections, attempt 
one-to-one row matching using the existing tolerance-aware comparison logic.

Allow previously matched rows to be reassigned when necessary to obtain a 
complete matching.
h3. Testing

The proposed implementation includes regression tests for:
 * Approximate floating-point equality across unordered rows.

 * Overlapping tolerance ranges requiring reassignment.

 * Ordered comparisons that must detect differences.

 * Unequal rows that must continue to fail.

Local validation included seven focused tests, randomized and exhaustive 
matching checks, Python compilation, and Git whitespace validation.
h3. References

Original GitHub issue: [https://github.com/apache/spark/issues/60027]

Implementation PR: [https://github.com/apache/spark/pull/60047]

Note: GitHub issue #60027 is distinct from Jira SPARK-60027, which tracks an 
unrelated Spark SQL issue.



--
This message was sent by Atlassian Jira
(v10.3.26#10030026)

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

Reply via email to