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 3e084be06b .
This commit is contained in:
Aliaksandr Valialkin 2021-10-07 12:52:24 +03:00
parent 3e084be06b
commit c45210a6f9
No known key found for this signature in database
GPG key ID: A72BEC6CD3D0DED1
3 changed files with 39 additions and 4 deletions

View file

@ -6239,6 +6239,39 @@ func TestExecSuccess(t *testing.T) {
resultExpected := []netstorage.Result{r} resultExpected := []netstorage.Result{r}
f(q, resultExpected) 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.Run(`delta(time())`, func(t *testing.T) {
t.Parallel() t.Parallel()
q := `delta(time())` q := `delta(time())`

View file

@ -151,7 +151,6 @@ var rollupFuncsCannotAdjustWindow = map[string]bool{
"holt_winters": true, "holt_winters": true,
"idelta": true, "idelta": true,
"increase": true, "increase": true,
"deriv": true,
"predict_linear": true, "predict_linear": true,
"resets": true, "resets": true,
"avg_over_time": true, "avg_over_time": true,
@ -865,9 +864,13 @@ func linearRegression(rfa *rollupFuncArg) (float64, float64) {
// before calling rollup funcs. // before calling rollup funcs.
values := rfa.values values := rfa.values
timestamps := rfa.timestamps timestamps := rfa.timestamps
if len(values) < 2 { n := float64(len(values))
if n == 0 {
return nan, nan return nan, nan
} }
if n == 1 {
return values[0], 0
}
// See https://en.wikipedia.org/wiki/Simple_linear_regression#Numerical_example // See https://en.wikipedia.org/wiki/Simple_linear_regression#Numerical_example
interceptTime := rfa.currTimestamp interceptTime := rfa.currTimestamp
@ -882,7 +885,6 @@ func linearRegression(rfa *rollupFuncArg) (float64, float64) {
tvSum += dt * v tvSum += dt * v
ttSum += dt * dt ttSum += dt * dt
} }
n := float64(len(values))
k := (tvSum - tSum*vSum/n) / (ttSum - tSum*tSum/n) k := (tvSum - tSum*vSum/n) / (ttSum - tSum*tSum/n)
v := vSum/n - k*tSum/n v := vSum/n - k*tSum/n
return v, k return v, k

View file

@ -979,7 +979,7 @@ func TestRollupFuncsNoWindow(t *testing.T) {
} }
rc.Timestamps = getTimestamps(rc.Start, rc.End, rc.Step) rc.Timestamps = getTimestamps(rc.Start, rc.End, rc.Step)
values := rc.Do(nil, testValues, testTimestamps) 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} timestampsExpected := []int64{0, 40, 80, 120, 160}
testRowsEqual(t, values, rc.Timestamps, valuesExpected, timestampsExpected) testRowsEqual(t, values, rc.Timestamps, valuesExpected, timestampsExpected)
}) })