andygrove opened a new pull request, #7253:
URL: https://github.com/apache/datafusion-comet/pull/7253

   ## Which issue does this PR close?
   
   Closes #7252.
   
   Stacked on #7251 (`inline` / `stack`), whose commits appear here until it 
merges. Only the last commit is new.
   
   ## Rationale for this change
   
   A `GenerateExec` whose generator Comet has no native implementation of falls 
back to Spark. That costs a columnar-to-row transition before it and a 
row-to-columnar transition after it, and leaves the rest of the stage in Spark. 
This affects:
   - Hive `GenericUDTF`s used in `LATERAL VIEW`;
   - `json_tuple`;
   - the `ReplicateRows` generator that `EXCEPT ALL` and `INTERSECT ALL` plan;
   - custom Catalyst generators.
   
   The generator itself still runs on the JVM one row at a time, so the gain is 
keeping the stage native around it.
   
   ## What changes are included in this PR?
   
   The issue proposed returning generated columns plus a parent-row index. This 
uses a simpler shape that fits the existing UDF bridge, which requires one 
output value per input row:
   - **`CometGeneratorUDF`** (a `CometUDF`): for each input row, it returns the 
rows the generator emits as one `array<struct>` element. `CometExplodeExec` 
then unnests and flattens that the way #7251 does for `inline`. An input row 
that emits nothing gets an empty array, so `outer` keeps it as one row of 
nulls, through the existing null handling.
   - **Inputs and outputs:** it reads the bound generator's columns through 
`CometVector` rows, and writes the output with Comet's `ArrowWriter` into a 
vector from `CometBatchKernelCodegen.allocateOutput`, so the list and struct 
field names match what the native side declares.
   - **State:** each native plan gets its own generator instance, keyed by 
digest and plan, and dropped in `releasePlan`, so the state a Hive UDTF keeps 
carries across batches. The serde folds a per-occurrence number into the 
digest, so two identical generators in one plan don't share an instance.
   - **`terminate()`:** a new `terminate` expression on the `Explode` proto is 
the same UDF called with a flag set. `ExplodeExec` evaluates it once the input 
is exhausted and emits its rows with the last input row's other columns, which 
it keeps as a one-row copy. That matches Spark's `GenerateExec`, which pairs 
them with the last row as Hive does. `outer` does not apply to these rows. With 
no input rows, the other columns are null.
   - **Serde:** `CometGeneratorUDF.declineReason` and 
`CometGeneratorUDF.calls`. The generator falls back when:
     - it is nondeterministic (the existing gate);
     - its tree holds a subquery, an unevaluable node or a native UDF call;
     - it calls code outside Spark (`CometInvokeTargets`);
     - its output type cannot be serialized.
   - **Config:** `spark.comet.exec.jvmGenerator.enabled`, on by default.
   - **Small refactors:** `CometScalaUDF.closureSerialize` is pulled out for 
reuse, and `ArrowWriter` and `ArrowFieldWriter` are widened from 
`private[arrow]` to `private[comet]`.
   - **Docs:** a Generators section in the Scala/Java UDF page, plus the 
operator, expression and plan pages.
   
   Python UDTFs (`@udtf`) plan as their own exec nodes and are not covered.
   
   ## How are these changes tested?
   
   - **Rust `ExplodeExec` tests:**
     - `terminate` rows carry the last input row across several batches;
     - with no input rows the other columns are null;
     - an empty `terminate` adds no `outer` row.
   - **`CometGenerateExecSuite`:**
     - a test Hive `GenericUDTF` (registered without a Hive session) that keeps 
a running count and emits a total from `close()`. The suite checks it runs 
natively against Spark: with and without `LATERAL VIEW OUTER`, with no input 
rows, and as two identical UDTFs in one plan;
     - a three-partition run with AQE off, checking that each partition ends 
with its own `close()` row;
     - `json_tuple`, and `EXCEPT ALL` through `ReplicateRows`, both checked to 
run natively;
     - the fallback reason when the config is off.
   - **Local runs:** on the default Spark 4.1 profile, `CometGenerateExecSuite` 
(59 passed), `CometSetOpWithGroupBySuite`, and the `inline`, `stack`, `explode` 
and `posexplode` SQL files.
   


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