app/vmselect/promql: allow passing inf arg into functions, which accept numeric limit on the number of output time series

Updates https://github.com/VictoriaMetrics/VictoriaMetrics/issues/3461
This commit is contained in:
Aliaksandr Valialkin 2022-12-10 22:47:30 -08:00
parent afa232eebb
commit 808ce815e4
No known key found for this signature in database
GPG Key ID: A72BEC6CD3D0DED1
5 changed files with 41 additions and 13 deletions

View File

@ -748,7 +748,7 @@ func getIntK(k float64, kMax int) int {
if math.IsNaN(k) { if math.IsNaN(k) {
return 0 return 0
} }
kn := int(k) kn := floatToIntBounded(k)
if kn < 0 { if kn < 0 {
return 0 return 0
} }
@ -999,14 +999,10 @@ func aggrFuncLimitK(afa *aggrFuncArg) ([]*timeseries, error) {
if err := expectTransformArgsNum(args, 2); err != nil { if err := expectTransformArgsNum(args, 2); err != nil {
return nil, err return nil, err
} }
limits, err := getScalar(args[0], 0) limit, err := getIntNumber(args[0], 0)
if err != nil { if err != nil {
return nil, fmt.Errorf("cannot obtain limit arg: %w", err) return nil, fmt.Errorf("cannot obtain limit arg: %w", err)
} }
limit := 0
if len(limits) > 0 {
limit = int(limits[0])
}
if limit < 0 { if limit < 0 {
limit = 0 limit = 0
} }
@ -1155,3 +1151,13 @@ func lessWithNaNs(a, b float64) bool {
} }
return a < b return a < b
} }
func floatToIntBounded(f float64) int {
if f > math.MaxInt {
return math.MaxInt
}
if f < math.MinInt {
return math.MinInt
}
return int(f)
}

View File

@ -5559,6 +5559,30 @@ func TestExecSuccess(t *testing.T) {
resultExpected := []netstorage.Result{r1, r2} resultExpected := []netstorage.Result{r1, r2}
f(q, resultExpected) f(q, resultExpected)
}) })
t.Run(`limitk(inf)`, func(t *testing.T) {
t.Parallel()
q := `sort(limitk(inf, label_set(10, "foo", "bar") or label_set(time()/150, "baz", "sss")))`
r1 := netstorage.Result{
MetricName: metricNameExpected,
Values: []float64{10, 10, 10, 10, 10, 10},
Timestamps: timestampsExpected,
}
r1.MetricName.Tags = []storage.Tag{{
Key: []byte("foo"),
Value: []byte("bar"),
}}
r2 := netstorage.Result{
MetricName: metricNameExpected,
Values: []float64{6.666666666666667, 8, 9.333333333333334, 10.666666666666666, 12, 13.333333333333334},
Timestamps: timestampsExpected,
}
r2.MetricName.Tags = []storage.Tag{{
Key: []byte("baz"),
Value: []byte("sss"),
}}
resultExpected := []netstorage.Result{r1, r2}
f(q, resultExpected)
})
t.Run(`any()`, func(t *testing.T) { t.Run(`any()`, func(t *testing.T) {
t.Parallel() t.Parallel()
q := `any(label_set(10, "__name__", "x", "foo", "bar") or label_set(time()/150, "__name__", "y", "baz", "sss"))` q := `any(label_set(10, "__name__", "x", "foo", "bar") or label_set(time()/150, "__name__", "y", "baz", "sss"))`

View File

@ -2127,7 +2127,7 @@ func getIntNumber(arg interface{}, argNum int) (int, error) {
} }
n := 0 n := 0
if len(v) > 0 { if len(v) > 0 {
n = int(v[0]) n = floatToIntBounded(v[0])
} }
return n, nil return n, nil
} }

View File

@ -371,14 +371,10 @@ func transformBucketsLimit(tfa *transformFuncArg) ([]*timeseries, error) {
if err := expectTransformArgsNum(args, 2); err != nil { if err := expectTransformArgsNum(args, 2); err != nil {
return nil, err return nil, err
} }
limits, err := getScalar(args[0], 1) limit, err := getIntNumber(args[0], 0)
if err != nil { if err != nil {
return nil, err return nil, err
} }
limit := 0
if len(limits) > 0 {
limit = int(limits[0])
}
if limit <= 0 { if limit <= 0 {
return nil, nil return nil, nil
} }
@ -390,6 +386,7 @@ func transformBucketsLimit(tfa *transformFuncArg) ([]*timeseries, error) {
if len(tss) == 0 { if len(tss) == 0 {
return nil, nil return nil, nil
} }
pointsCount := len(tss[0].Values)
// Group timeseries by all MetricGroup+tags excluding `le` tag. // Group timeseries by all MetricGroup+tags excluding `le` tag.
type x struct { type x struct {
@ -437,7 +434,7 @@ func transformBucketsLimit(tfa *transformFuncArg) ([]*timeseries, error) {
sort.Slice(leGroup, func(i, j int) bool { sort.Slice(leGroup, func(i, j int) bool {
return leGroup[i].le < leGroup[j].le return leGroup[i].le < leGroup[j].le
}) })
for n := range limits { for n := 0; n < pointsCount; n++ {
prevValue := float64(0) prevValue := float64(0)
for i := range leGroup { for i := range leGroup {
xx := &leGroup[i] xx := &leGroup[i]

View File

@ -64,6 +64,7 @@ The following tip changes can be tested by building VictoriaMetrics components f
* FEATURE: [vmui](https://docs.victoriametrics.com/#vmui): allow changing timezones for the requested data. See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/3075). * FEATURE: [vmui](https://docs.victoriametrics.com/#vmui): allow changing timezones for the requested data. See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/3075).
* FEATURE: [vmui](https://docs.victoriametrics.com/#vmui): provide fast path for hiding results for all the queries except the given one by clicking `eye` icon with `ctrl` key pressed. See [this feature request](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/3446). * FEATURE: [vmui](https://docs.victoriametrics.com/#vmui): provide fast path for hiding results for all the queries except the given one by clicking `eye` icon with `ctrl` key pressed. See [this feature request](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/3446).
* FEATURE: [MetricsQL](https://docs.victoriametrics.com/MetricsQL.html): add `range_trim_spikes(phi, q)` function for trimming `phi` percent of the largest spikes per each time series returned by `q`. See [these docs](https://docs.victoriametrics.com/MetricsQL.html#range_trim_spikes). * FEATURE: [MetricsQL](https://docs.victoriametrics.com/MetricsQL.html): add `range_trim_spikes(phi, q)` function for trimming `phi` percent of the largest spikes per each time series returned by `q`. See [these docs](https://docs.victoriametrics.com/MetricsQL.html#range_trim_spikes).
* FEATURE: [MetricsQL](https://docs.victoriametrics.com/MetricsQL.html): allow passing `inf` arg into [limitk](https://docs.victoriametrics.com/MetricsQL.html#limitk), [topk](https://docs.victoriametrics.com/MetricsQL.html#topk), [bottomk](https://docs.victoriametrics.com/MetricsQL.html) and other functions, which accept numeric arg, which limits the number of output time series. See [this feature request](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/3461).
* FEATURE: [vmgateway](https://docs.victoriametrics.com/vmgateway.html): add support for JWT token signature verification. See [these docs](https://docs.victoriametrics.com/vmgateway.html#jwt-signature-verification) for details. * FEATURE: [vmgateway](https://docs.victoriametrics.com/vmgateway.html): add support for JWT token signature verification. See [these docs](https://docs.victoriametrics.com/vmgateway.html#jwt-signature-verification) for details.
* FEATURE: put the version of VictoriaMetrics in the first message of [query trace](https://docs.victoriametrics.com/#query-tracing). This should simplify debugging. * FEATURE: put the version of VictoriaMetrics in the first message of [query trace](https://docs.victoriametrics.com/#query-tracing). This should simplify debugging.