andygrove opened a new issue, #7206:
URL: https://github.com/apache/datafusion-comet/issues/7206

   ### Describe the bug
   
   With `spark.sql.parquet.fieldId.read.enabled=true`, the native Parquet scan 
returns NULL for a root column that matches a file column by name when an 
unread field of the read schema selects the same file column by id. Spark reads 
the value.
   
   Take a file with `A` (id 1) = 7 and `z` (id 2) = 9, read with the schema `[x 
(id 1), a (no id), z (id 2)]`. The query reads `a` and `z` but not `x`. Spark's 
`clipParquetGroupFields` only resolves the required schema `[a, z]`, so `a` 
matches `A` by name and both Spark readers return 7.
   
   Comet resolves the root over the whole data schema instead. 
`CometNativeScan` serializes the relation's data schema together with a 
projection, and `SparkPhysicalExprAdapterFactory::create` receives that data 
schema as its logical file schema, the same mechanism behind #7006. The unread 
`x` claims `A` by id, which outranks `a`'s name claim, so 
`remap_physical_schema` renames `A` to `x` and `a` reads as a missing column. 
Id matching is on only when the required schema carries an id, which is why 
`select("a")` alone reads correctly.
   
   ### Steps to reproduce
   
   In a `CometTestBase` suite on the default Spark 4.1.3 profile:
   
   ```scala
   def withId(id: Int) =
     new MetadataBuilder().putLong(ParquetUtils.FIELD_ID_METADATA_KEY, 
id.toLong).build()
   val writeSchema = new StructType()
     .add("A", LongType, true, withId(1))
     .add("z", LongType, true, withId(2))
   withSQLConf(SQLConf.PARQUET_FIELD_ID_WRITE_ENABLED.key -> "true") {
     spark
       .createDataFrame(spark.sparkContext.parallelize(Seq(Row(7L, 9L))), 
writeSchema)
       .write
       .parquet(path)
   }
   val readSchema = new StructType()
     .add("x", LongType, true, withId(1))
     .add("a", LongType, true)
     .add("z", LongType, true, withId(2))
   withSQLConf(SQLConf.PARQUET_FIELD_ID_READ_ENABLED.key -> "true") {
     spark.read.schema(readSchema).parquet(path).select("a", "z").collect()
   }
   ```
   
   On `main` at 330b29cf10:
   
   | Query | Spark vectorized | Spark parquet-mr | Comet native scan |
   |---|---|---|---|
   | `select("a", "z")` | `[7, 9]` | `[7, 9]` | `[null, 9]` |
   | `select("a", "z")`, schema order `[a, x, z]` | `[7, 9]` | `[7, 9]` | 
`[null, 9]` |
   | `select("a", "z")`, case-sensitive, file column named `a` | `[7, 9]` | 
`[7, 9]` | `[null, 9]` |
   | `select("a")` | `[7]` | `[7]` | `[7]` |
   | `select("x", "a", "z")` | `[7, <stale memory>, 9]` | `[7, null, 9]` | `[7, 
null, 9]` |
   
   ### Expected behavior
   
   Comet should return `[7, 9]`, as both Spark readers do. Root claims should 
be resolved among the columns the read requires, the way Spark clips only the 
required schema.
   
   ### Additional context
   
   Found while reviewing #7196. That PR adds a JVM fallback for the repeated-id 
version of this shape, a required root that shares its id with another root of 
the data schema. This shape repeats no id, so the fallback doesn't cover it. 
@sam-1112 suggested limiting claim arbitration to the required roots in 
https://github.com/apache/datafusion-comet/pull/7196#discussion_r4369441283. 
That would fix both shapes, and the fallback could then go. `branch-1.2` has 
the same root resolution code as `main`.
   
   The shape needs field-id reads and a read schema that mixes fields with and 
without ids, so it should be rare in practice.
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


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

Reply via email to