From 7e6ec0bbe91f2909e63215d0485ee44a7d7994be Mon Sep 17 00:00:00 2001 From: Aliaksandr Valialkin Date: Thu, 7 Oct 2021 12:52:24 +0300 Subject: [PATCH] app/vmselect/promql: return back the behaviour for `deriv()` function when the lookbehind window doesnt contain enough points It is expected that the `deriv(m[d])` returns non-empty value if the lookbehind window `d` contains less than 2 samples in the same way as `rate()` does. This is a follow-up after 3e084be06b6f48440ea3ffc8cb04f770ae10dbca . --- app/vmselect/promql/exec_test.go | 33 ++++++++++++++++++++++++++++++ app/vmselect/promql/rollup.go | 8 +++++--- app/vmselect/promql/rollup_test.go | 2 +- 3 files changed, 39 insertions(+), 4 deletions(-) diff --git a/app/vmselect/promql/exec_test.go b/app/vmselect/promql/exec_test.go index 8ea18549c..6c7df0b1a 100644 --- a/app/vmselect/promql/exec_test.go +++ b/app/vmselect/promql/exec_test.go @@ -6249,6 +6249,39 @@ func TestExecSuccess(t *testing.T) { resultExpected := []netstorage.Result{r} f(q, resultExpected) }) + t.Run(`deriv(1)`, func(t *testing.T) { + t.Parallel() + q := `deriv(1)` + r := netstorage.Result{ + MetricName: metricNameExpected, + Values: []float64{0, 0, 0, 0, 0, 0}, + Timestamps: timestampsExpected, + } + resultExpected := []netstorage.Result{r} + f(q, resultExpected) + }) + t.Run(`deriv(time())`, func(t *testing.T) { + t.Parallel() + q := `deriv(2*time())` + r := netstorage.Result{ + MetricName: metricNameExpected, + Values: []float64{2, 2, 2, 2, 2, 2}, + Timestamps: timestampsExpected, + } + resultExpected := []netstorage.Result{r} + f(q, resultExpected) + }) + t.Run(`deriv(-time())`, func(t *testing.T) { + t.Parallel() + q := `deriv(-time())` + r := netstorage.Result{ + MetricName: metricNameExpected, + Values: []float64{-1, -1, -1, -1, -1, -1}, + Timestamps: timestampsExpected, + } + resultExpected := []netstorage.Result{r} + f(q, resultExpected) + }) t.Run(`delta(time())`, func(t *testing.T) { t.Parallel() q := `delta(time())` diff --git a/app/vmselect/promql/rollup.go b/app/vmselect/promql/rollup.go index d306067ff..e569add97 100644 --- a/app/vmselect/promql/rollup.go +++ b/app/vmselect/promql/rollup.go @@ -151,7 +151,6 @@ var rollupFuncsCannotAdjustWindow = map[string]bool{ "holt_winters": true, "idelta": true, "increase": true, - "deriv": true, "predict_linear": true, "resets": true, "avg_over_time": true, @@ -865,9 +864,13 @@ func linearRegression(rfa *rollupFuncArg) (float64, float64) { // before calling rollup funcs. values := rfa.values timestamps := rfa.timestamps - if len(values) < 2 { + n := float64(len(values)) + if n == 0 { return nan, nan } + if n == 1 { + return values[0], 0 + } // See https://en.wikipedia.org/wiki/Simple_linear_regression#Numerical_example interceptTime := rfa.currTimestamp @@ -882,7 +885,6 @@ func linearRegression(rfa *rollupFuncArg) (float64, float64) { tvSum += dt * v ttSum += dt * dt } - n := float64(len(values)) k := (tvSum - tSum*vSum/n) / (ttSum - tSum*tSum/n) v := vSum/n - k*tSum/n return v, k diff --git a/app/vmselect/promql/rollup_test.go b/app/vmselect/promql/rollup_test.go index f4af400f4..e1c22eb6d 100644 --- a/app/vmselect/promql/rollup_test.go +++ b/app/vmselect/promql/rollup_test.go @@ -979,7 +979,7 @@ func TestRollupFuncsNoWindow(t *testing.T) { } rc.Timestamps = getTimestamps(rc.Start, rc.End, rc.Step) values := rc.Do(nil, testValues, testTimestamps) - valuesExpected := []float64{nan, -2879.310344827588, 127.87627310448904, -496.5831435079728, nan} + valuesExpected := []float64{nan, -2879.310344827588, 127.87627310448904, -496.5831435079728, 0} timestampsExpected := []int64{0, 40, 80, 120, 160} testRowsEqual(t, values, rc.Timestamps, valuesExpected, timestampsExpected) })