From dbd8beccfac9e2cd9176db56cdcc075e68a99ff6 Mon Sep 17 00:00:00 2001 From: Aliaksandr Valialkin Date: Thu, 21 May 2020 12:05:08 +0300 Subject: [PATCH] app/vmselect/promql: add `ascent_over_time(m[d])` and `descent_over_time(m[d])` functions These functions could be useful in GPS tracking apps for calculating the summary for height gain/loss over the given duration `d`. --- app/vmselect/promql/rollup.go | 53 +++++++++++++++++++ app/vmselect/promql/rollup_test.go | 3 ++ docs/MetricsQL.md | 2 + go.mod | 2 +- go.sum | 4 +- .../VictoriaMetrics/metricsql/rollup.go | 2 + vendor/modules.txt | 2 +- 7 files changed, 64 insertions(+), 4 deletions(-) diff --git a/app/vmselect/promql/rollup.go b/app/vmselect/promql/rollup.go index 1e234d810..8ae3045b7 100644 --- a/app/vmselect/promql/rollup.go +++ b/app/vmselect/promql/rollup.go @@ -72,6 +72,8 @@ var rollupFuncs = map[string]newRollupFunc{ "aggr_over_time": newRollupFuncTwoArgs(rollupFake), "hoeffding_bound_upper": newRollupHoeffdingBoundUpper, "hoeffding_bound_lower": newRollupHoeffdingBoundLower, + "ascent_over_time": newRollupFuncOneArg(rollupAscentOverTime), + "descent_over_time": newRollupFuncOneArg(rollupDescentOverTime), // `timestamp` function must return timestamp for the last datapoint on the current window // in order to properly handle offset and timestamps unaligned to the current step. @@ -116,6 +118,9 @@ var rollupAggrFuncs = map[string]rollupFunc{ "scrape_interval": rollupScrapeInterval, "tmin_over_time": rollupTmin, "tmax_over_time": rollupTmax, + "ascent_over_time": rollupAscentOverTime, + "descent_over_time": rollupDescentOverTime, + "timestamp": rollupTimestamp, } var rollupFuncsCannotAdjustWindow = map[string]bool{ @@ -138,6 +143,8 @@ var rollupFuncsCannotAdjustWindow = map[string]bool{ "increases_over_time": true, "decreases_over_time": true, "integrate": true, + "ascent_over_time": true, + "descent_over_time": true, } var rollupFuncsRemoveCounterResets = map[string]bool{ @@ -1527,6 +1534,52 @@ func rollupTimestamp(rfa *rollupFuncArg) float64 { return float64(timestamps[len(timestamps)-1]) / 1e3 } +func rollupAscentOverTime(rfa *rollupFuncArg) float64 { + // There is no need in handling NaNs here, since they must be cleaned up + // before calling rollup funcs. + values := rfa.values + prevValue := rfa.prevValue + if math.IsNaN(prevValue) { + if len(values) == 0 { + return nan + } + prevValue = values[0] + values = values[1:] + } + s := float64(0) + for _, v := range values { + d := v - prevValue + if d > 0 { + s += d + } + prevValue = v + } + return s +} + +func rollupDescentOverTime(rfa *rollupFuncArg) float64 { + // There is no need in handling NaNs here, since they must be cleaned up + // before calling rollup funcs. + values := rfa.values + prevValue := rfa.prevValue + if math.IsNaN(prevValue) { + if len(values) == 0 { + return nan + } + prevValue = values[0] + values = values[1:] + } + s := float64(0) + for _, v := range values { + d := prevValue - v + if d > 0 { + s += d + } + prevValue = v + } + return s +} + func rollupFirst(rfa *rollupFuncArg) float64 { // There is no need in handling NaNs here, since they must be cleaned up // before calling rollup funcs. diff --git a/app/vmselect/promql/rollup_test.go b/app/vmselect/promql/rollup_test.go index 08a1b055d..06b021e83 100644 --- a/app/vmselect/promql/rollup_test.go +++ b/app/vmselect/promql/rollup_test.go @@ -389,6 +389,9 @@ func TestRollupNewRollupFuncSuccess(t *testing.T) { f("ideriv", 0) f("decreases_over_time", 5) f("increases_over_time", 5) + f("ascent_over_time", 142) + f("descent_over_time", 231) + f("timestamp", 0.13) } func TestRollupNewRollupFuncError(t *testing.T) { diff --git a/docs/MetricsQL.md b/docs/MetricsQL.md index 9543f4707..127b75dea 100644 --- a/docs/MetricsQL.md +++ b/docs/MetricsQL.md @@ -120,3 +120,5 @@ This functionality can be tried at [an editable Grafana dashboard](http://play-g - `first_over_time(m[d])` - returns the first value for `m` on the time range `d`. - `outliersk(N, m)` - returns up to `N` outlier time series for `m`. Outlier time series have the highest deviation from the `median(m)`. This aggregate function is useful to detect anomalies across groups of similar time series. +- `ascent_over_time(m[d])` - returns the sum of positive deltas between adjancent data points in `m` over `d`. Useful for tracking height gains in GPS track. +- `descent_over_time(m[d])` - returns the absolute sum of negative deltas between adjancent data points in `m` over `d`. Useful for tracking height loss in GPS track. diff --git a/go.mod b/go.mod index 36db98ea7..04e56aeeb 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,7 @@ require ( // like https://github.com/valyala/fasthttp/commit/996610f021ff45fdc98c2ce7884d5fa4e7f9199b github.com/VictoriaMetrics/fasthttp v1.0.1 github.com/VictoriaMetrics/metrics v1.11.3 - github.com/VictoriaMetrics/metricsql v0.2.2 + github.com/VictoriaMetrics/metricsql v0.2.3 github.com/aws/aws-sdk-go v1.30.28 github.com/cespare/xxhash/v2 v2.1.1 github.com/golang/protobuf v1.4.2 // indirect diff --git a/go.sum b/go.sum index 284abce9b..e4fc8ad54 100644 --- a/go.sum +++ b/go.sum @@ -47,8 +47,8 @@ github.com/VictoriaMetrics/metrics v1.11.2 h1:t/ceLP6SvagUqypCKU7cI7+tQn54+TIV/t github.com/VictoriaMetrics/metrics v1.11.2/go.mod h1:LU2j9qq7xqZYXz8tF3/RQnB2z2MbZms5TDiIg9/NHiQ= github.com/VictoriaMetrics/metrics v1.11.3 h1:eSfXc0CrquKa1VTNUvhP+dhNjLUZHQGTFfp19mYCQWE= github.com/VictoriaMetrics/metrics v1.11.3/go.mod h1:LU2j9qq7xqZYXz8tF3/RQnB2z2MbZms5TDiIg9/NHiQ= -github.com/VictoriaMetrics/metricsql v0.2.2 h1:3PhBV4g2z7lm8adPShC4vr1PfSkRcLoSq5XOEpSgJPg= -github.com/VictoriaMetrics/metricsql v0.2.2/go.mod h1:UIjd9S0W1UnTWlJdM0wLS+2pfuPqjwqKoK8yTos+WyE= +github.com/VictoriaMetrics/metricsql v0.2.3 h1:xGscDmLoeIV7+8qX/mdHnOY0vu4m+wHIVGMoy/nBovY= +github.com/VictoriaMetrics/metricsql v0.2.3/go.mod h1:UIjd9S0W1UnTWlJdM0wLS+2pfuPqjwqKoK8yTos+WyE= github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156 h1:eMwmnE/GDgah4HI848JfFxHt+iPb26b4zyfspmqY0/8= github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM= github.com/aws/aws-sdk-go v1.30.28 h1:SaPM7dlmp7h3Lj1nJ4jdzOkTdom08+g20k7AU5heZYg= diff --git a/vendor/github.com/VictoriaMetrics/metricsql/rollup.go b/vendor/github.com/VictoriaMetrics/metricsql/rollup.go index e36083355..da32c308d 100644 --- a/vendor/github.com/VictoriaMetrics/metricsql/rollup.go +++ b/vendor/github.com/VictoriaMetrics/metricsql/rollup.go @@ -57,6 +57,8 @@ var rollupFuncs = map[string]bool{ "aggr_over_time": true, "hoeffding_bound_upper": true, "hoeffding_bound_lower": true, + "ascent_over_time": true, + "descent_over_time": true, // `timestamp` func has been moved here because it must work properly with offsets and samples unaligned to the current step. // See https://github.com/VictoriaMetrics/VictoriaMetrics/issues/415 for details. diff --git a/vendor/modules.txt b/vendor/modules.txt index ff5d9f3fd..3c7fb8db9 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -18,7 +18,7 @@ github.com/VictoriaMetrics/fasthttp/fasthttputil github.com/VictoriaMetrics/fasthttp/stackless # github.com/VictoriaMetrics/metrics v1.11.3 github.com/VictoriaMetrics/metrics -# github.com/VictoriaMetrics/metricsql v0.2.2 +# github.com/VictoriaMetrics/metricsql v0.2.3 github.com/VictoriaMetrics/metricsql github.com/VictoriaMetrics/metricsql/binaryop # github.com/aws/aws-sdk-go v1.30.28