feat(extensions): support int arguments with std_dev and variance functions#1012
feat(extensions): support int arguments with std_dev and variance functions#1012nielspardon wants to merge 11 commits into
Conversation
mbwhite
left a comment
There was a problem hiding this comment.
LGTM - good to get the complete implementation - and following the pattern of avg
76ff67d to
82379c0
Compare
This comment was marked as outdated.
This comment was marked as outdated.
yongchul
left a comment
There was a problem hiding this comment.
+1 for supporting integral types.
…and variance BREAKING CHANGE: changes the function signature of existing functions std_dev and variance Signed-off-by: Niels Pardon <par@zurich.ibm.com>
Signed-off-by: Niels Pardon <par@zurich.ibm.com>
Signed-off-by: Niels Pardon <par@zurich.ibm.com>
Signed-off-by: Niels Pardon <par@zurich.ibm.com>
Signed-off-by: Niels Pardon <par@zurich.ibm.com>
Signed-off-by: Niels Pardon <par@zurich.ibm.com>
Signed-off-by: Niels Pardon <par@zurich.ibm.com>
Signed-off-by: Niels Pardon <par@zurich.ibm.com>
82379c0 to
7219621
Compare
|
rebased on latest #1011 to remove the deprecation |
|
Do we actually need to support calls like
This is slightly different from the For the |
7219621 to
9b21b2b
Compare
Signed-off-by: Niels Pardon <par@zurich.ibm.com>
…ctions Signed-off-by: Niels Pardon <par@zurich.ibm.com>
Signed-off-by: Niels Pardon <par@zurich.ibm.com>
9b21b2b to
a9b2d92
Compare
Currently, the fp32 argument versions also returns an fp32 result: substrait/extensions/functions_arithmetic.yaml Lines 1395 to 1404 in 7b39d4c substrait/extensions/functions_arithmetic.yaml Lines 1418 to 1427 in 7b39d4c |
I think not offering function signatures with all numeric types makes it only less convenient for Substrait adopters since they need to add and parse extra cast expressions which they otherwise would not need. Sure, we could force them to do so but then I also feel that the Substrait specification is under-specified on the expected casting behavior like e.g. when casting from fp32 to i64 does it round up or down? |
Should have been clearer. The integer args versions all return fp64.
I agree actually, but that sounds like something worth pinning down as well.
It makes the producers life more difficult, but lessens the burden on the consumer because the surface area of functions to implement/support is smaller. I haven't figured out a good criteria to express when we should push for a plan producer to cast, but I don't think think we need to provide 1-1 functions for everything in SQL. This actually might be a case where it's worth it, but forcing producers to cast is also a mechanism to get them to capture their type coercion behaviors explicitly. |
created an issue for the casting docs improvement: #1023 |
If you wanted to enforce such a behavior you would have to analyze all of the existing function signatures and deprecate/remove the ones that are "too convenient", not forcing producers to expose their type coercion behavior. Also this will require a major rewrite of the isthmus aggregate function mapping (at least for std_dev, variance but also for scalar, windowing functions prospectively) since the way it is implemented today does not allow to explicitly coerce types using casts since in the function conversion logic we have only access to field indices of fields used in aggregate functions but not their types. |
|
I opened a PR in substrait-java that shows how casting arguments explicitly in a plan producer (isthmus) looks like: substrait-io/substrait-java#780 |
jacques-n
left a comment
There was a problem hiding this comment.
It is hard to look at the current patch and confirm whether it is a breaking change. It definitely looks like one but I suppose it is possible that you moved function location around and this is net new functions. It doesn't seem like this needs to be a breaking change.
This is mainly because it is based on other PRs that I originally posted in parallel. I have not updated this PR recently given the discussion around whether we want to have additional function signatures with int types or force users to explicitly cast non floating point arguments. @jacques-n What is your point of view on asking users to cast vs. offering more convenience by offering alternative function signatures accepting int arguments? |
I'm inclined to look at the nature of the underlying operation. I would avoid creating composite "friendly versions" of operations that are simply going to be cross-cast immediately with potential lossy-ness and errors. For example, I don't believe there are any amd64 instructions that take in integer arguments for trigonometric or statistical functions. If there are first class integer ops, then I'd be inclined to include them. I believe that was the original thinking I tried to apply when creating the functions I added. |
|
I'm closing this PR for now in favor of adding explicit casts to floating point in the plan producer. |
This PR implements the bidirectional conversion between Calcite and Substrait for the statistical aggregate functions standard deviation and variance (`STDDEV_POP`, `STDDEV_SAMP`, `VAR_POP`, `VAR_SAMP`). ### Problem Substrait uses a single function name for both the population and sample variants: - `std_dev` for both `STDDEV_POP` and `STDDEV_SAMP` - `variance` for both `VAR_POP` and `VAR_SAMP` The population (n denominator) vs. sample (n-1 denominator) distinction is captured by a `distribution` value (`POPULATION` or `SAMPLE`). Previously these functions were not mapped, so the existing TPC-DS test cases using them were silently mis-mapped to `AVG` (Calcite represents these statistical functions with `SqlAvgAggFunction`). ### Solution This uses the **non-deprecated** signatures introduced in substrait-io/substrait#1011 (Substrait v0.87.0), which carry the distinction as an **enum function argument** (the leading `distribution` argument, e.g. `std_dev:req_fp64`), rather than the deprecated function-option form (substrait-io/substrait#1019). Resolves #803 Resolves #807 Since the input arguments are cast to `FP64` when necessary, the integer-based signatures proposed in substrait-io/substrait#1012 are not required. **Calcite → Substrait:** - Added function mappings in `FunctionMappings` for all four statistical operators. - `AggregateFunctionConverter` synthesizes the leading `distribution` enum operand based on the Calcite `SqlKind`, so the generic function matcher resolves the enum-arg variant and builds the `EnumArg` automatically (no bespoke option plumbing). - Statistical inputs are cast to `FP64` where necessary. **Substrait → Calcite:** - `FunctionConverter.getSqlOperatorFromSubstraitFunc` disambiguates the population/sample operator from the `distribution` enum argument. - `SubstraitRelNodeConverter` and `PreCalciteAggregateValidator` skip the non-value enum argument when building Calcite aggregate operands. **DSL & shared enum:** - A shared `StatisticalDistribution` enum (in `:core`) is the single source of truth for the `SAMPLE` / `POPULATION` values used by both the DSL builder and isthmus. - `SubstraitBuilder` gains `stddevPopulation`, `stddevSample`, `variancePopulation`, and `varianceSample` convenience methods. ### Non-floating-point inputs `std_dev` / `variance` only define `fp32` / `fp64` signatures, so a statistical aggregate over an integer (or other non-fp) column is rewritten in `SubstraitRelVisitor` to cast the argument to `fp64` (appending a cast column so other aggregates over the same column are unaffected) and cast the result back to the type Calcite inferred. The rewrite is idempotent, so the converted plan is stable under further round trips. ### Testing - `AggregationFunctionsTest` exercises full round trips (POJO ⇄ proto and Substrait ⇄ Calcite) for all four functions, with and without grouping. - `StatisticalFunctionTest` verifies the SQL round trip, asserts that each SQL operator maps to the enum-arg signature (`std_dev:req_fp64` etc.) with the correct `distribution` `EnumArg` and no function options, and covers non-fp (integer) inputs — including a column shared with a non-statistical aggregate, and with grouping. 🤖 Generated with AI --------- Signed-off-by: Niels Pardon <par@zurich.ibm.com>
This PR depends on #1010 and #1011 since it uses the new enum argument syntax in the test cases and adds additional generated test cases using integer arguments to the generated test cases in #1011.
The main changes for this PR are in commit 714d363.
This PR adds new function signatures for
std_devandvariancewhich accept integer arguments. Most SQL systems support any numeric arguments not just floating point arguments as the current Substrait function signatures suggest.Integer arguments are used in TPC-DS and are required so we can correctly convert TPC-DS queries with isthmus in substrait-java. See: substrait-io/substrait-java#68
This change is