[ 
https://issues.apache.org/jira/browse/FLINK-38740?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

lincoln lee updated FLINK-38740:
--------------------------------
    Fix Version/s: 2.3.0

> STDDEV related functions may produce invalid results
> ----------------------------------------------------
>
>                 Key: FLINK-38740
>                 URL: https://issues.apache.org/jira/browse/FLINK-38740
>             Project: Flink
>          Issue Type: Bug
>          Components: Table SQL / API
>    Affects Versions: 2.2.0
>            Reporter: dylanhz
>            Assignee: dylanhz
>            Priority: Major
>              Labels: pull-request-available
>             Fix For: 2.3.0
>
>
> Currently, Flink uses Calcite's AggregateReduceFunctionsRule to reduce 
> STDDEV_POP/STDDEV_SAMP/VAR_POP/VAR_SAMP to SUMs and COUNTs. For example:
> {code:java}
> STDDEV_POP(x) = SQRT((SUM(x * x) - SUM(x) * SUM(x) / COUNT(x)) / COUNT(x))
> {code}
> This rewrite rule is known as a naive one-pass algorithm for variance 
> calculation. However, it suffers from significant precision loss and may 
> produce invalid results given the limited precision of Java double and float 
> types. See [1] for reference. For example in Flink:
> {code:sql}
> > select stddev_pop(x) from (values (cast(0.27 as double)), (cast(0.27 as 
> > double)), (cast(0.27 as double))) as T(x)
> -- NaN
> > select var_pop(x) from (values (cast(0.27 as double)), (cast(0.27 as 
> > double)), (cast(0.27 as double))) as T(x)
> -- -9.25185853854297E-18
> > select stddev_pop(x) from (values (cast(100000 as int)), (cast(200000 as 
> > int)), (cast(300000 as int))) as T(x)
> -- 0
> {code}
> Most systems such as Spark/PostgreSQL/MySQL have turned to use a more 
> accurate and stable approach called Welford's online algorithm, you can find 
> its definition in [1]. I'm considering introducing this into Flink as well.
> More specifically, we can introduce a new internal built-in function like 
> WELFORD_M2 to calculate the m2 term in the algorithm, and then rewrite the 
> functions as follows to avoid repeated calculations:
> {code:java}
> stddev_pop(x)  ==> power(m2 / count(x), .5)
> stddev_samp(x) ==> power(m2 / nullif(count(x) - 1, 0), .5)
> var_pop(x)     ==> m2 / count(x)
> var_samp(x)    ==> m2 / nullif(count(x) - 1, 0)
> {code}
> Since this proposal will introduce a breaking change, I think we should 
> discuss the following before I create the pull request:
> 1. Should we provide a configuration option to fall back to the legacy 
> algorithm for backward compatibility?
> 2. What should be the intermediate result type?
>  - Option A: Use decimal for decimal input and double for all other numeric 
> types
>  - Option B: Use double for all types
>  - Option C: Other ideas/suggestions are welcome
> [1][variance 
> calculation|https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Welford's_online_algorithm]



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to