Repository navigation
[SPARK-60322][SQL] Fix Parquet and ORC filter pushdown dropping rows for comparisons with a zero - #59574
Open
SEPURI-SAI-KRISHNA wants to merge 1 commit into
Conversation
…for comparisons with a zero Spark treats 0.0 and -0.0 as equal, but ParquetFilters and OrcFilters pushed a FLOAT or DOUBLE zero down unchanged, and Parquet and ORC tell the two zeros apart: dictionary and bloom filters hold one of them, and statistics order -0.0 before 0.0. A row group, stripe or file that holds only the other zero was skipped, so e.g. `f = 0` returned no rows for a column of -0.0. Push a comparison with a zero down in a form that keeps exactly the values that the Spark predicate keeps: an equality or IN names both zeros, and a range takes the zero on its side as the bound, -0.0 for `<` and `>=` and 0.0 for `<=` and `>`, so that a negated predicate is right as well.
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What changes were proposed in this pull request?
ParquetFiltersandOrcFilterspush a comparison of aFLOATorDOUBLEcolumn with 0.0 or -0.0 down in a form that keeps exactly the values that the Spark predicate keeps:z= 0.0 or -0.0f = z,f <=> zor(eq(f, 0.0), eq(f, -0.0))or(equals(f, 0.0), equals(f, -0.0)),nullSafeEqualsfor<=>f IN (z, ...)f != zand(notEq(f, 0.0), notEq(f, -0.0))not(equals), covered above)f < z,f >= zlessThanwith bound -0.0 (>=isnot(lessThan))f <= z,f > zlessThanEqualswith bound 0.0 (>isnot(lessThanEquals))Other values are pushed down as before.
Why are the changes needed?
Spark treats 0.0 and -0.0 as equal (
SELECT 0.0D = -0.0Dis true), but both formats tell them apart, and the pushed predicate compared with the literal unchanged. A row group, stripe or file that holds only the other zero was skipped, and the Filter above the scan never saw its rows. With the default configuration, on 3.5.3, 4.0.3 and 4.2.0 (official binaries) and on master:With
spark.sql.parquet.filterPushdown=false/spark.sql.orc.filterPushdown=falsethey return 1000, 999 and 999.Where the formats tell the zeros apart:
Double.compareTo, so a min and max of -0.0 rule outf = 0.0andf >= 0.0.FLOATandDOUBLEcolumns with the IEEE 754 total order and exact bounds, so on master they skip rows too.A range takes the zero on its side as the bound, rather than any zero that keeps enough values, because a pushed
Notnegates the pushed predicate: with a bound that keeps more values,NOT (f < 0.0)would becomenot(lt(f, 0.0)), which skips a file of -0.0 values. ORC builds>and>=that way, asnot(lessThanEquals)andnot(lessThan).Does this PR introduce any user-facing change?
Yes. Queries that compare a
FLOATorDOUBLEcolumn of a Parquet or ORC table with 0.0 or -0.0 now return the rows that hold the other zero, where they could return fewer rows before.How was this patch tested?
New tests in
ParquetFilterSuiteandOrcFilterSuite, which run with DSv1 and DSv2. They write one file of 0.0, one of -0.0 and one of 1.0, forFLOATandDOUBLE, and compare 30 predicates with each zero (=,<=>,INbelow and above the IN threshold,!=,<,<=,>,>=, andNOTof them withBooleanSimplificationexcluded) with the same filter on the data in memory. The Parquet test writes the files once dictionary encoded and once with a bloom filter, checks that in the footer, and reads them with the record-level filter on. Both tests fail without this change. Each part of the change was also reverted on its own (equality, IN, not-equal and each of the four range bounds, for each format), and each of the 14 reverts fails the tests.ParquetV1FilterSuite,ParquetV2FilterSuite,OrcFilterSuite,OrcV1FilterSuiteand the other suites in theparquetandorcpackages pass.A separate matrix compared these predicates, and BETWEEN and OR built from them, with pushdown on and off over files of 0.0, -0.0, other values and NULL: Parquet and ORC,
FLOATandDOUBLE, DSv1 and DSv2, vectorized and not, dictionaries and bloom filters on and off, only the statistics, the column index or the dictionary filter on, the record-level filter and the storage filter on and off. 3,558 of 7,904 combinations were wrong before this change and none after.Was this patch authored or co-authored using generative AI tooling?
Generated-by: Claude Code (Claude Opus 5.5)