Yuan Yusi created SPARK-59127:
---------------------------------

             Summary:  Incorrect count() result on cached sampled DataFrame 
when AQE is enabled Incorrect count() result on cached sampled DataFrame when 
AQE is enabled
                 Key: SPARK-59127
                 URL: https://issues.apache.org/jira/browse/SPARK-59127
             Project: Spark
          Issue Type: Bug
          Components: SQL
    Affects Versions: 4.2.0
            Reporter: Yuan Yusi


h1. Incorrect count() result on cached sampled DataFrame when AQE is enabled
h2. What is the issue?

On Apache Spark 4.2.0, a seeded non-replacement sample followed by {{cache()}} 
can return inconsistent results with AQE enabled. The same cached DataFrame 
reports zero rows from {{count()}} while {{collect()}} returns one row. AQE 
also changes the selected sample for the fixed seed.
h2. Minimum reproduce query
{code:python}
sampled = (spark.range(1, 5, 1, 2)
    .selectExpr("CAST(id AS INT) AS id")
    .sort("id")
    .sample(False, 0.25, 0))

cached = sampled.cache()
cached.count()       # AQE on: 0
cached.collect()     # AQE on: [Row(id=3)]
{code}
The range creates IDs 1 through 4 in two partitions. The sample uses fraction 
0.25 and seed 0, then the sampled relation is cached before the two actions are 
evaluated.
h2. Reproduction

Reproduction

Enable AQE in Spark, i.e.
{code:sql}
spark.conf.set("spark.sql.adaptive.enabled", "true")
{code}
Then run the SQL query above.

Compare the result of {{cached.collect().sizet()}} and {{cached.count()}}
h2. Test oracle

For one cached DataFrame, {{cached.count()}} must equal 
{{{}cached.collect().size{}}}. With a fixed seed, the sampling must return 
stable and consistent result across runs.
h2. Expected behavior

The cached relation and every action over it must agree. In particular:
{noformat}
cached_count == len(cached.collect())
{noformat}
h2. Actual behavior
{noformat}
AQE off: before=[], after=[], cached_count=0
AQE on:  before=[3], after=[3], cached_count=0
{noformat}
With AQE enabled, {{cached.count()}} returns 0 while {{cached.collect()}} 
returns {{{}[Row(id=3)]{}}}. The same cached result therefore has contradictory 
cardinality and row contents.
h2. Plan evidence

AQE-off uses a plain {{{}Sort{}}}; AQE-on uses {{AdaptiveSparkPlan}} above the 
sort. The cached collection includes an {{{}InMemoryTableScan{}}}, but the 
count action still reports zero rows.
h2. Suspected root cause

{{SampleExec}} derives its seeded random stream from the input partition index. 
AQE changes the post-shuffle partition layout through coalescing, and cache 
materialization and count statistics are then computed at different partition 
boundaries. This can leave stale or incomplete cached row-count metadata (zero) 
even though a subsequent cached scan yields id 3. Disabling AQE restores 
count/collect agreement.
h2. Environment

Apache Spark 4.2.0, PySpark 4.2.0, Java 17, macOS, {{{}local[2]{}}}, fraction 
{{{}0.25{}}}, seed {{{}0{}}}, range {{{}(1, 5, step=1, splits=2){}}}.



--
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