app/vmselect: add label_map(q, label, srcValue1, dstValue1, ... srcValueN, dstValueN) function to MetricsQL

Updates https://github.com/VictoriaMetrics/VictoriaMetrics/issues/369
This commit is contained in:
Aliaksandr Valialkin 2020-03-12 19:13:28 +02:00
parent 92d67e2592
commit fdc2a9d1d7
4 changed files with 76 additions and 0 deletions

View file

@ -974,6 +974,49 @@ func TestExecSuccess(t *testing.T) {
resultExpected := []netstorage.Result{r}
f(q, resultExpected)
})
t.Run(`label_map(match)`, func(t *testing.T) {
t.Parallel()
q := `sort(label_map((
label_set(time(), "label", "v1"),
label_set(time()+100, "label", "v2"),
label_set(time()+200, "label", "v3"),
label_set(time()+300, "x", "y"),
), "label", "v1", "foo", "v2", "bar"))`
r1 := netstorage.Result{
MetricName: metricNameExpected,
Values: []float64{1000, 1200, 1400, 1600, 1800, 2000},
Timestamps: timestampsExpected,
}
r1.MetricName.Tags = []storage.Tag{{
Key: []byte("label"),
Value: []byte("foo"),
}}
r2 := netstorage.Result{
MetricName: metricNameExpected,
Values: []float64{1100, 1300, 1500, 1700, 1900, 2100},
Timestamps: timestampsExpected,
}
r2.MetricName.Tags = []storage.Tag{{
Key: []byte("label"),
Value: []byte("bar"),
}}
r3 := netstorage.Result{
MetricName: metricNameExpected,
Values: []float64{1200, 1400, 1600, 1800, 2000, 2200},
Timestamps: timestampsExpected,
}
r4 := netstorage.Result{
MetricName: metricNameExpected,
Values: []float64{1300, 1500, 1700, 1900, 2100, 2300},
Timestamps: timestampsExpected,
}
r4.MetricName.Tags = []storage.Tag{{
Key: []byte("x"),
Value: []byte("y"),
}}
resultExpected := []netstorage.Result{r1, r2, r3, r4}
f(q, resultExpected)
})
t.Run(`label_copy(new_tag)`, func(t *testing.T) {
t.Parallel()
q := `label_copy(

View file

@ -59,6 +59,7 @@ var transformFuncs = map[string]transformFunc{
// New funcs
"label_set": transformLabelSet,
"label_map": transformLabelMap,
"label_del": transformLabelDel,
"label_keep": transformLabelKeep,
"label_copy": transformLabelCopy,
@ -1026,6 +1027,36 @@ func transformLabelSet(tfa *transformFuncArg) ([]*timeseries, error) {
return rvs, nil
}
func transformLabelMap(tfa *transformFuncArg) ([]*timeseries, error) {
args := tfa.args
if len(args) < 2 {
return nil, fmt.Errorf(`not enough args; got %d; want at least %d`, len(args), 2)
}
label, err := getString(args[1], 1)
if err != nil {
return nil, fmt.Errorf("cannot read label name: %s", err)
}
srcValues, dstValues, err := getStringPairs(args[2:])
if err != nil {
return nil, err
}
m := make(map[string]string, len(srcValues))
for i, srcValue := range srcValues {
m[srcValue] = dstValues[i]
}
rvs := args[0]
for _, ts := range rvs {
mn := &ts.MetricName
dstValue := getDstValue(mn, label)
value := m[string(*dstValue)]
*dstValue = append((*dstValue)[:0], value...)
if len(value) == 0 {
mn.RemoveTag(label)
}
}
return rvs, nil
}
func transformLabelCopy(tfa *transformFuncArg) ([]*timeseries, error) {
return transformLabelCopyExt(tfa, false)
}

View file

@ -46,6 +46,7 @@ This functionality can be tried at [an editable Grafana dashboard](http://play-g
- Functions for label manipulation:
- `alias(q, name)` for setting metric name across all the time series `q`.
- `label_set(q, label1, value1, ... labelN, valueN)` for setting the given values for the given labels on `q`.
- `label_map(q, label, srcValue1, dstValue1, ... srcValueN, dstValueN)` for mapping `label` values from `src*` to `dst*`.
- `label_del(q, label1, ... labelN)` for deleting the given labels from `q`.
- `label_keep(q, label1, ... labelN)` for deleting all the labels except the given labels from `q`.
- `label_copy(q, src_label1, dst_label1, ... src_labelN, dst_labelN)` for copying label values from `src_*` to `dst_*`.

View file

@ -38,6 +38,7 @@ var transformFuncs = map[string]bool{
// New funcs from MetricsQL
"label_set": true,
"label_map": true,
"label_del": true,
"label_keep": true,
"label_copy": true,