[FEA] null handling for empty groups in pds-ds benchmarks
- Dominant language
- C++
- Stars
- 9.8k
- Forks
- 1.1k
- Avg merge
- 3d 6m
- Merged PRs (30d)
- 278
Description
***Problem***
In introducing tpc-ds derived benchmarks for cudf-polars (see #19200), we have a number of different validation options:
1. validate CPU polars against GPU polars
2. validate CPU polars against duckdb
3. validate GPU polars against duckdb
Validation against duckdb requires post-processing of many queries that aggregate columns with nulls. This is because the semantics of `sum(all_null_group_or_column)` differ between Polars and SQL (duckdb).
Specifically: Polars says "the size of the empty set is zero", and so `sum(all_nulls) == 0`. In contrast SQL says "the size of the empty set is undefined", and so `sum(all_nulls) == null`.
To produce results aggregating groups that might be null in polars that match the SQL semantics, we have used the following pattern in the queries:
```python
df.group_by("key").agg(
pl.col("value").sum(), pl.col("value").count().alias("value_count")
).with_columns(
pl.when(pl.col("value_count") > 0).then(pl.col("value")).otherwise(None)
).drop(pl.col("value_count"))
```
It is useful to be able to validate polars against an external reference, certainly while we are ensuring all the features are supported in GPU polars.
That said, this workaround may introduce a noticeable performance penalty since we double the number of aggregations we perform, and increase the memory footprint.
***Aside***
In GPU polars, since libcudf aggregations follow SQL semantics, we already postprocess the aggs _in the other direction_ internally to match polars, so there are _two_ performance hits in the GPU engine.
***Proposed solution***
It is likely that the semantics of the queries don't change with this semantic change in the result of `sum(all_nulls)`. However, we would like to be able to validate the Polars results against both different polars engines and also third-party SQL-compatible tooling.
I think we should introduce an option to the benchmarks that allows us to select the behaviour (apply workaround in polars or not). We could do it by writing a little transformation function that optionally applies the workaround. It would need a little bit of thought because correctly producing the aggregated column in the `with_columns` call needs to know the name of the output column (we would have to provide this separately since expressions can't report their names in polars).
Contributor guide
Assessment
This issue has not been assessed yet.