diff --git a/app/vmselect/promql/exec_test.go b/app/vmselect/promql/exec_test.go index e298e729f..b39887bea 100644 --- a/app/vmselect/promql/exec_test.go +++ b/app/vmselect/promql/exec_test.go @@ -5826,6 +5826,17 @@ func TestExecSuccess(t *testing.T) { resultExpected := []netstorage.Result{r} f(q, resultExpected) }) + t.Run(`share_eq_over_time`, func(t *testing.T) { + t.Parallel() + q := `share_eq_over_time(round(5*rand(0))[200s:10s], 1)` + r := netstorage.Result{ + MetricName: metricNameExpected, + Values: []float64{0.1, 0.2, 0.25, 0.1, 0.3, 0.3}, + Timestamps: timestampsExpected, + } + resultExpected := []netstorage.Result{r} + f(q, resultExpected) + }) t.Run(`count_gt_over_time`, func(t *testing.T) { t.Parallel() q := `count_gt_over_time(rand(0)[200s:10s], 0.7)` diff --git a/app/vmselect/promql/rollup.go b/app/vmselect/promql/rollup.go index f585440e5..d7c742bec 100644 --- a/app/vmselect/promql/rollup.go +++ b/app/vmselect/promql/rollup.go @@ -78,6 +78,7 @@ var rollupFuncs = map[string]newRollupFunc{ "scrape_interval": newRollupFuncOneArg(rollupScrapeInterval), "share_gt_over_time": newRollupShareGT, "share_le_over_time": newRollupShareLE, + "share_eq_over_time": newRollupShareEQ, "stale_samples_over_time": newRollupFuncOneArg(rollupStaleSamples), "stddev_over_time": newRollupFuncOneArg(rollupStddev), "stdvar_over_time": newRollupFuncOneArg(rollupStdvar), @@ -1106,6 +1107,10 @@ func countFilterGT(values []float64, gt float64) int { return n } +func newRollupShareEQ(args []interface{}) (rollupFunc, error) { + return newRollupShareFilter(args, countFilterEQ) +} + func countFilterEQ(values []float64, eq float64) int { n := 0 for _, v := range values { diff --git a/app/vmselect/promql/rollup_test.go b/app/vmselect/promql/rollup_test.go index 25caa7c32..970b0b3ba 100644 --- a/app/vmselect/promql/rollup_test.go +++ b/app/vmselect/promql/rollup_test.go @@ -261,6 +261,25 @@ func TestRollupShareGTOverTime(t *testing.T) { f(1000, 0) } +func TestRollupShareEQOverTime(t *testing.T) { + f := func(eq, vExpected float64) { + t.Helper() + eqs := []*timeseries{{ + Values: []float64{eq}, + Timestamps: []int64{123}, + }} + var me metricsql.MetricExpr + args := []interface{}{&metricsql.RollupExpr{Expr: &me}, eqs} + testRollupFunc(t, "share_eq_over_time", args, &me, vExpected) + } + + f(-123, 0) + f(34, 0.3333333333333333) + f(44, 0.16666666666666666) + f(123, 0.08333333333333333) + f(1000, 0) +} + func TestRollupCountLEOverTime(t *testing.T) { f := func(le, vExpected float64) { t.Helper() diff --git a/docs/MetricsQL.md b/docs/MetricsQL.md index 2f59fda7e..e5106fe6c 100644 --- a/docs/MetricsQL.md +++ b/docs/MetricsQL.md @@ -744,6 +744,14 @@ Metric names are stripped from the resulting rollups. Add [keep_metric_names](#k See also [share_gt_over_time](#share_gt_over_time). +#### share_eq_over_time + +`share_eq_over_time(series_selector[d], eq)` is a [rollup function](#rollup-functions), which returns share (in the range `[0...1]`) of raw samples +on the given lookbehind window `d`, which are equal to `eq`. It is calculated independently per each time series returned +from the given [series_selector](https://docs.victoriametrics.com/keyConcepts.html#filtering). + +Metric names are stripped from the resulting rollups. Add [keep_metric_names](#keep_metric_names) modifier in order to keep metric names. + #### stale_samples_over_time `stale_samples_over_time(series_selector[d])` is a [rollup function](#rollup-functions), which calculates the number