diff --git a/CHANGELOG.md b/CHANGELOG.md
index a60dea169..e515bd370 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,7 @@
## unreleased
+* [CHANGE] `holt_winters` is now called `double_exponential_smoothing` and moves behind the [experimental-promql-functions feature flag](https://prometheus.io/docs/prometheus/latest/feature_flags/#experimental-promql-functions). #14930
* [BUGFIX] PromQL: Only return "possible non-counter" annotation when `rate` returns points. #14910
## 3.0.0-beta.0 / 2024-09-05
diff --git a/docs/querying/functions.md b/docs/querying/functions.md
index e13628c5c..9d73b5344 100644
--- a/docs/querying/functions.md
+++ b/docs/querying/functions.md
@@ -380,15 +380,22 @@ do not show up in the returned vector.
Similarly, `histogram_stdvar(v instant-vector)` returns the estimated standard
variance of observations in a native histogram.
-## `holt_winters()`
+## `double_exponential_smoothing()`
-`holt_winters(v range-vector, sf scalar, tf scalar)` produces a smoothed value
+**This function has to be enabled via the [feature flag](../feature_flags.md#experimental-promql-functions) `--enable-feature=promql-experimental-functions`.**
+
+`double_exponential_smoothing(v range-vector, sf scalar, tf scalar)` produces a smoothed value
for time series based on the range in `v`. The lower the smoothing factor `sf`,
the more importance is given to old data. The higher the trend factor `tf`, the
more trends in the data is considered. Both `sf` and `tf` must be between 0 and
1.
+For additional details, refer to [NIST Engineering Statistics Handbook](https://www.itl.nist.gov/div898/handbook/pmc/section4/pmc433.htm).
+In Prometheus V2 this function was called `holt_winters`. This caused confusion
+since the Holt-Winters method usually refers to triple exponential smoothing.
+Double exponential smoothing as implemented here is also referred to as "Holt
+Linear".
-`holt_winters` should only be used with gauges.
+`double_exponential_smoothing` should only be used with gauges.
## `hour()`
diff --git a/promql/bench_test.go b/promql/bench_test.go
index 74e85b054..cd6d1190c 100644
--- a/promql/bench_test.go
+++ b/promql/bench_test.go
@@ -117,7 +117,7 @@ func rangeQueryCases() []benchCase {
},
// Holt-Winters and long ranges.
{
- expr: "holt_winters(a_X[1d], 0.3, 0.3)",
+ expr: "double_exponential_smoothing(a_X[1d], 0.3, 0.3)",
},
{
expr: "changes(a_X[1d])",
diff --git a/promql/functions.go b/promql/functions.go
index 5bdcce65d..c4a7ee4a4 100644
--- a/promql/functions.go
+++ b/promql/functions.go
@@ -350,7 +350,7 @@ func calcTrendValue(i int, tf, s0, s1, b float64) float64 {
// data. A lower smoothing factor increases the influence of historical data. The trend factor (0 < tf < 1) affects
// how trends in historical data will affect the current data. A higher trend factor increases the influence.
// of trends. Algorithm taken from https://en.wikipedia.org/wiki/Exponential_smoothing titled: "Double exponential smoothing".
-func funcHoltWinters(vals []parser.Value, args parser.Expressions, enh *EvalNodeHelper) (Vector, annotations.Annotations) {
+func funcDoubleExponentialSmoothing(vals []parser.Value, args parser.Expressions, enh *EvalNodeHelper) (Vector, annotations.Annotations) {
samples := vals[0].(Matrix)[0]
// The smoothing factor argument.
@@ -1657,82 +1657,82 @@ func funcYear(vals []parser.Value, args parser.Expressions, enh *EvalNodeHelper)
// FunctionCalls is a list of all functions supported by PromQL, including their types.
var FunctionCalls = map[string]FunctionCall{
- "abs": funcAbs,
- "absent": funcAbsent,
- "absent_over_time": funcAbsentOverTime,
- "acos": funcAcos,
- "acosh": funcAcosh,
- "asin": funcAsin,
- "asinh": funcAsinh,
- "atan": funcAtan,
- "atanh": funcAtanh,
- "avg_over_time": funcAvgOverTime,
- "ceil": funcCeil,
- "changes": funcChanges,
- "clamp": funcClamp,
- "clamp_max": funcClampMax,
- "clamp_min": funcClampMin,
- "cos": funcCos,
- "cosh": funcCosh,
- "count_over_time": funcCountOverTime,
- "days_in_month": funcDaysInMonth,
- "day_of_month": funcDayOfMonth,
- "day_of_week": funcDayOfWeek,
- "day_of_year": funcDayOfYear,
- "deg": funcDeg,
- "delta": funcDelta,
- "deriv": funcDeriv,
- "exp": funcExp,
- "floor": funcFloor,
- "histogram_avg": funcHistogramAvg,
- "histogram_count": funcHistogramCount,
- "histogram_fraction": funcHistogramFraction,
- "histogram_quantile": funcHistogramQuantile,
- "histogram_sum": funcHistogramSum,
- "histogram_stddev": funcHistogramStdDev,
- "histogram_stdvar": funcHistogramStdVar,
- "holt_winters": funcHoltWinters,
- "hour": funcHour,
- "idelta": funcIdelta,
- "increase": funcIncrease,
- "irate": funcIrate,
- "label_replace": funcLabelReplace,
- "label_join": funcLabelJoin,
- "ln": funcLn,
- "log10": funcLog10,
- "log2": funcLog2,
- "last_over_time": funcLastOverTime,
- "mad_over_time": funcMadOverTime,
- "max_over_time": funcMaxOverTime,
- "min_over_time": funcMinOverTime,
- "minute": funcMinute,
- "month": funcMonth,
- "pi": funcPi,
- "predict_linear": funcPredictLinear,
- "present_over_time": funcPresentOverTime,
- "quantile_over_time": funcQuantileOverTime,
- "rad": funcRad,
- "rate": funcRate,
- "resets": funcResets,
- "round": funcRound,
- "scalar": funcScalar,
- "sgn": funcSgn,
- "sin": funcSin,
- "sinh": funcSinh,
- "sort": funcSort,
- "sort_desc": funcSortDesc,
- "sort_by_label": funcSortByLabel,
- "sort_by_label_desc": funcSortByLabelDesc,
- "sqrt": funcSqrt,
- "stddev_over_time": funcStddevOverTime,
- "stdvar_over_time": funcStdvarOverTime,
- "sum_over_time": funcSumOverTime,
- "tan": funcTan,
- "tanh": funcTanh,
- "time": funcTime,
- "timestamp": funcTimestamp,
- "vector": funcVector,
- "year": funcYear,
+ "abs": funcAbs,
+ "absent": funcAbsent,
+ "absent_over_time": funcAbsentOverTime,
+ "acos": funcAcos,
+ "acosh": funcAcosh,
+ "asin": funcAsin,
+ "asinh": funcAsinh,
+ "atan": funcAtan,
+ "atanh": funcAtanh,
+ "avg_over_time": funcAvgOverTime,
+ "ceil": funcCeil,
+ "changes": funcChanges,
+ "clamp": funcClamp,
+ "clamp_max": funcClampMax,
+ "clamp_min": funcClampMin,
+ "cos": funcCos,
+ "cosh": funcCosh,
+ "count_over_time": funcCountOverTime,
+ "days_in_month": funcDaysInMonth,
+ "day_of_month": funcDayOfMonth,
+ "day_of_week": funcDayOfWeek,
+ "day_of_year": funcDayOfYear,
+ "deg": funcDeg,
+ "delta": funcDelta,
+ "deriv": funcDeriv,
+ "exp": funcExp,
+ "floor": funcFloor,
+ "histogram_avg": funcHistogramAvg,
+ "histogram_count": funcHistogramCount,
+ "histogram_fraction": funcHistogramFraction,
+ "histogram_quantile": funcHistogramQuantile,
+ "histogram_sum": funcHistogramSum,
+ "histogram_stddev": funcHistogramStdDev,
+ "histogram_stdvar": funcHistogramStdVar,
+ "double_exponential_smoothing": funcDoubleExponentialSmoothing,
+ "hour": funcHour,
+ "idelta": funcIdelta,
+ "increase": funcIncrease,
+ "irate": funcIrate,
+ "label_replace": funcLabelReplace,
+ "label_join": funcLabelJoin,
+ "ln": funcLn,
+ "log10": funcLog10,
+ "log2": funcLog2,
+ "last_over_time": funcLastOverTime,
+ "mad_over_time": funcMadOverTime,
+ "max_over_time": funcMaxOverTime,
+ "min_over_time": funcMinOverTime,
+ "minute": funcMinute,
+ "month": funcMonth,
+ "pi": funcPi,
+ "predict_linear": funcPredictLinear,
+ "present_over_time": funcPresentOverTime,
+ "quantile_over_time": funcQuantileOverTime,
+ "rad": funcRad,
+ "rate": funcRate,
+ "resets": funcResets,
+ "round": funcRound,
+ "scalar": funcScalar,
+ "sgn": funcSgn,
+ "sin": funcSin,
+ "sinh": funcSinh,
+ "sort": funcSort,
+ "sort_desc": funcSortDesc,
+ "sort_by_label": funcSortByLabel,
+ "sort_by_label_desc": funcSortByLabelDesc,
+ "sqrt": funcSqrt,
+ "stddev_over_time": funcStddevOverTime,
+ "stdvar_over_time": funcStdvarOverTime,
+ "sum_over_time": funcSumOverTime,
+ "tan": funcTan,
+ "tanh": funcTanh,
+ "time": funcTime,
+ "timestamp": funcTimestamp,
+ "vector": funcVector,
+ "year": funcYear,
}
// AtModifierUnsafeFunctions are the functions whose result
diff --git a/promql/parser/functions.go b/promql/parser/functions.go
index 99b41321f..9d7b56053 100644
--- a/promql/parser/functions.go
+++ b/promql/parser/functions.go
@@ -202,10 +202,11 @@ var Functions = map[string]*Function{
ArgTypes: []ValueType{ValueTypeScalar, ValueTypeVector},
ReturnType: ValueTypeVector,
},
- "holt_winters": {
- Name: "holt_winters",
- ArgTypes: []ValueType{ValueTypeMatrix, ValueTypeScalar, ValueTypeScalar},
- ReturnType: ValueTypeVector,
+ "double_exponential_smoothing": {
+ Name: "double_exponential_smoothing",
+ ArgTypes: []ValueType{ValueTypeMatrix, ValueTypeScalar, ValueTypeScalar},
+ ReturnType: ValueTypeVector,
+ Experimental: true,
},
"hour": {
Name: "hour",
diff --git a/promql/promqltest/testdata/functions.test b/promql/promqltest/testdata/functions.test
index 4b025448a..c9af6c4c9 100644
--- a/promql/promqltest/testdata/functions.test
+++ b/promql/promqltest/testdata/functions.test
@@ -651,7 +651,7 @@ eval_ordered instant at 50m sort_by_label(node_uname_info, "release")
node_uname_info{job="node_exporter", instance="4m5", release="1.11.3"} 100
node_uname_info{job="node_exporter", instance="4m1000", release="1.111.3"} 100
-# Tests for holt_winters
+# Tests for double_exponential_smoothing
clear
# positive trends
@@ -661,7 +661,7 @@ load 10s
http_requests{job="api-server", instance="0", group="canary"} 0+30x1000 300+80x1000
http_requests{job="api-server", instance="1", group="canary"} 0+40x2000
-eval instant at 8000s holt_winters(http_requests[1m], 0.01, 0.1)
+eval instant at 8000s double_exponential_smoothing(http_requests[1m], 0.01, 0.1)
{job="api-server", instance="0", group="production"} 8000
{job="api-server", instance="1", group="production"} 16000
{job="api-server", instance="0", group="canary"} 24000
@@ -675,7 +675,7 @@ load 10s
http_requests{job="api-server", instance="0", group="canary"} 0+30x1000 300-80x1000
http_requests{job="api-server", instance="1", group="canary"} 0-40x1000 0+40x1000
-eval instant at 8000s holt_winters(http_requests[1m], 0.01, 0.1)
+eval instant at 8000s double_exponential_smoothing(http_requests[1m], 0.01, 0.1)
{job="api-server", instance="0", group="production"} 0
{job="api-server", instance="1", group="production"} -16000
{job="api-server", instance="0", group="canary"} 24000
diff --git a/ui-commits b/ui-commits
new file mode 100644
index 000000000..7f34e1f95
--- /dev/null
+++ b/ui-commits
@@ -0,0 +1,12 @@
+dfec29d8e Fix border color for target pools with one target that is failing
+65743bf9b ui: drop template readme
+a7c1a951d Add general Mantine overrides CSS file
+0757fbbec Make sure that alert element table headers are not wrapped
+0180cf31a Factor out common icon and card styles
+50af7d589 Fix tree line drawing by using a callback ref
+ac01dc903 Explain, vector-to-vector: Do not compute results for set operators
+9b0dc68d0 PromQL explain view: Support set operators
+57898c792 Refactor and fix time formatting functions, add tests
+091fc403c Fiddle with targets table styles to try and improve things a bit
+a1908df92 Don't wrap action buttons below metric name in metrics explorer
+ac5377873 mantine UI: Distinguish between Not Ready and Stopping
diff --git a/web/ui/mantine-ui/src/promql/functionDocs.tsx b/web/ui/mantine-ui/src/promql/functionDocs.tsx
index 36c081e86..45fcd03b7 100644
--- a/web/ui/mantine-ui/src/promql/functionDocs.tsx
+++ b/web/ui/mantine-ui/src/promql/functionDocs.tsx
@@ -1277,17 +1277,17 @@ const funcDocs: Record
- holt_winters(v range-vector, sf scalar, tf scalar)
produces a smoothed value for time series based on
+ double_exponential_smoothing(v range-vector, sf scalar, tf scalar)
produces a smoothed value for time series based on
the range in v
. The lower the smoothing factor sf
, the more importance is given to old
data. The higher the trend factor tf
, the more trends in the data is considered. Both sf
{' '}
and tf
must be between 0 and 1.
- holt_winters
should only be used with gauges.
+ double_exponential_smoothing
should only be used with gauges.