Skip to content

fix(spark): atomic renames, ordered keep-aware dedup, NaN/inf handling, exact numeric type names - #378

Merged
kevincostner17 merged 1 commit into
mainfrom
fix/spark-engine
Sep 15, 2026
Merged

kevincostner17 merged 1 commit into
mainfrom
fix/spark-engine

Conversation

@kevincostner17

Copy link
Copy Markdown
Contributor

Summary

Fixes four Spark engine divergences from the pandas reference:

Docs: docs/backends.md and docs/fallback-matrix.md updated for NaN handling, finite outlier fences and Spark dedup order.

Tests

New tests/test_execution/test_spark_engine_fixes.py:

  • pyspark-free tests using a small evaluating fake of pyspark.sql (DataFrame, functions, Window), including end-to-end SparkEngine.execute() runs compared against the pandas engine (dedup keep first/last, NaN missing counts and drops, mean impute with null+NaN, zscore flags with ±inf, interval columns skipped, rename collisions).
  • The same repros on a real local SparkSession, skipped when pyspark or a JVM is unavailable.

Verification

  • ruff check . clean; mypy src/freshdata clean.
  • Full suite (-m "not online and not large"): py3.12 4275 passed / 13 skipped; py3.9 4271 passed / 17 skipped.
  • Not run against real Spark: pyspark is not installed locally and CI has no Spark job, so the real-Spark tests skip. The fixes were verified by inspection and the fake-DataFrame tests; a run on a real Spark session before merging would be worthwhile.

Closes #330
Closes #331
Closes #332
Closes #333

…g, exact numeric type names

- #330: _stage_rename applied the rename map one withColumnRenamed call at a
  time. withColumnRenamed renames every case-insensitive match, so a
  deduplicated map such as {"a b": "a_b", "a_b": "a_b_2"} or {"A": "a",
  "a": "a_2"} renamed both columns in the second call and left duplicate
  names that later F.col() references could not resolve. The map is now
  applied in one positional projection with sdf.toDF(...).
- #331: full-row dedup used dropDuplicates(), a shuffle aggregate that ignores
  duplicate_keep and returns rows in arbitrary order. An ordinal
  (monotonically_increasing_id) is taken before any shuffle, row_number() over
  a window partitioned by every column keeps the first (ascending) or last
  (descending) occurrence, and sorting by the ordinal restores the input order.
  The ordinal follows the input DataFrame's partition order; docs say so.
  Detection-only runs still count with dropDuplicates().count().
- #332: Spark keeps float NaN as a value, so missing counts, empty column/row
  drops and impute missed it, and a column holding both nulls and NaN was
  "imputed" with a NaN mean. Float/double NaN is now read as null at ingestion,
  as the Polars and DuckDB engines do. Outlier fences are computed from finite
  values only (pandas drop_infinite); +-inf is still tested against them.
  Impute statistics are unchanged, since the pandas reference includes inf.
- #333: numeric detection prefix-matched simpleString dtypes, so "interval day
  to second" counted as "int" and reached approxQuantile / float(timedelta).
  Type names are now matched exactly after stripping parameters
  (decimal(10,2) -> decimal), with the integer subset for _is_integer_column.

pyspark is not available locally, so these were verified by inspection and by
unit tests that drive SparkEngine through an evaluating fake pyspark.sql
(DataFrame, functions, Window), including end-to-end execute() runs compared
with the pandas engine. Real-SparkSession versions of each repro are included
and skip without pyspark or a JVM.

Closes #330
Closes #331
Closes #332
Closes #333
@coderabbitai

coderabbitai Bot commented Sep 15, 2026

Copy link
Copy Markdown
Contributor

Important

  • 🔍 Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Advanced

Run ID: 5387c6b5-cff5-4d00-b73a-f3971c8926a2


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions

Copy link
Copy Markdown

FreshData benchmark report — performance

  • freshdata: ?
  • python: ?
  • platform: ?
fixture n_rows n_cols p50 s p95 s peak MB repair % false-repair % preserve % trust monotonic export %

Authored-code reduction (Metric 6)

@kevincostner17
kevincostner17 merged commit 82dba99 into main Sep 15, 2026
21 checks passed
kevincostner17 added a commit that referenced this pull request Sep 15, 2026
Add Unreleased Added, Changed and Fixed entries for merged PRs #351,
#352, #353, #354, #356, #357, #358, #360, #361, #362, #363, #364, #365,
#367, #368, #369, #370, #371, #372, #374, #375, #377, #378 and #379.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment