app/vmselect/promql: properly override label values from group_left and group_right lists like Prometheus does

Updates https://github.com/VictoriaMetrics/VictoriaMetrics/issues/577
This commit is contained in:
Aliaksandr Valialkin 2020-06-21 16:32:00 +03:00
parent 50aa34bcbe
commit 70bf8218bb
3 changed files with 46 additions and 28 deletions

View File

@ -206,7 +206,7 @@ func groupJoin(singleTimeseriesSide string, be *metricsql.BinaryOpExpr, rvsLeft,
resetMetricGroupIfRequired(be, tsLeft) resetMetricGroupIfRequired(be, tsLeft)
if len(tssRight) == 1 { if len(tssRight) == 1 {
// Easy case - right part contains only a single matching time series. // Easy case - right part contains only a single matching time series.
tsLeft.MetricName.AddMissingTags(joinTags, &tssRight[0].MetricName) tsLeft.MetricName.SetTags(joinTags, &tssRight[0].MetricName)
rvsLeft = append(rvsLeft, tsLeft) rvsLeft = append(rvsLeft, tsLeft)
rvsRight = append(rvsRight, tssRight[0]) rvsRight = append(rvsRight, tssRight[0])
continue continue
@ -225,7 +225,7 @@ func groupJoin(singleTimeseriesSide string, be *metricsql.BinaryOpExpr, rvsLeft,
for _, tsRight := range tssRight { for _, tsRight := range tssRight {
var tsCopy timeseries var tsCopy timeseries
tsCopy.CopyFromShallowTimestamps(tsLeft) tsCopy.CopyFromShallowTimestamps(tsLeft)
tsCopy.MetricName.AddMissingTags(joinTags, &tsRight.MetricName) tsCopy.MetricName.SetTags(joinTags, &tsRight.MetricName)
bb.B = marshalMetricTagsSorted(bb.B[:0], &tsCopy.MetricName) bb.B = marshalMetricTagsSorted(bb.B[:0], &tsCopy.MetricName)
if tsExisting := m[string(bb.B)]; tsExisting != nil { if tsExisting := m[string(bb.B)]; tsExisting != nil {
// Try merging tsExisting with tsRight if they don't overlap. // Try merging tsExisting with tsRight if they don't overlap.

View File

@ -2009,25 +2009,37 @@ func TestExecSuccess(t *testing.T) {
}) })
t.Run(`scalar * ignoring(foo) group_right vector`, func(t *testing.T) { t.Run(`scalar * ignoring(foo) group_right vector`, func(t *testing.T) {
t.Parallel() t.Parallel()
q := `sort_desc(2 * ignoring(foo) group_right(a,foo) (label_set(time(), "foo", "bar") or label_set(10, "foo", "qwert")))` q := `sort_desc(label_set(2, "a", "2") * ignoring(foo,a) group_right(a) (label_set(time(), "foo", "bar", "a", "1"), label_set(10, "foo", "qwert")))`
r1 := netstorage.Result{ r1 := netstorage.Result{
MetricName: metricNameExpected, MetricName: metricNameExpected,
Values: []float64{2000, 2400, 2800, 3200, 3600, 4000}, Values: []float64{2000, 2400, 2800, 3200, 3600, 4000},
Timestamps: timestampsExpected, Timestamps: timestampsExpected,
} }
r1.MetricName.Tags = []storage.Tag{{ r1.MetricName.Tags = []storage.Tag{
Key: []byte("foo"), {
Value: []byte("bar"), Key: []byte("a"),
}} Value: []byte("2"),
},
{
Key: []byte("foo"),
Value: []byte("bar"),
},
}
r2 := netstorage.Result{ r2 := netstorage.Result{
MetricName: metricNameExpected, MetricName: metricNameExpected,
Values: []float64{20, 20, 20, 20, 20, 20}, Values: []float64{20, 20, 20, 20, 20, 20},
Timestamps: timestampsExpected, Timestamps: timestampsExpected,
} }
r2.MetricName.Tags = []storage.Tag{{ r2.MetricName.Tags = []storage.Tag{
Key: []byte("foo"), {
Value: []byte("qwert"), Key: []byte("a"),
}} Value: []byte("2"),
},
{
Key: []byte("foo"),
Value: []byte("qwert"),
},
}
resultExpected := []netstorage.Result{r1, r2} resultExpected := []netstorage.Result{r1, r2}
f(q, resultExpected) f(q, resultExpected)
}) })
@ -2342,9 +2354,9 @@ func TestExecSuccess(t *testing.T) {
t.Run(`vector + vector on group_left matching`, func(t *testing.T) { t.Run(`vector + vector on group_left matching`, func(t *testing.T) {
t.Parallel() t.Parallel()
q := `sort_desc( q := `sort_desc(
(label_set(time(), "t1", "v123", "t2", "v3") or label_set(10, "t2", "v3", "xxx", "yy")) (label_set(time(), "t1", "v123", "t2", "v3"), label_set(10, "t2", "v3", "xxx", "yy"))
+ on (foo, t2) group_left (t1, noxxx) + on (foo, t2) group_left (t1, noxxx)
(label_set(100, "t1", "v1") or label_set(time(), "t2", "v3", "noxxx", "aa")) (label_set(100, "t1", "v1"), label_set(time(), "t2", "v3", "noxxx", "aa"))
)` )`
r1 := netstorage.Result{ r1 := netstorage.Result{
MetricName: metricNameExpected, MetricName: metricNameExpected,
@ -2356,10 +2368,6 @@ func TestExecSuccess(t *testing.T) {
Key: []byte("noxxx"), Key: []byte("noxxx"),
Value: []byte("aa"), Value: []byte("aa"),
}, },
{
Key: []byte("t1"),
Value: []byte("v123"),
},
{ {
Key: []byte("t2"), Key: []byte("t2"),
Value: []byte("v3"), Value: []byte("v3"),

View File

@ -298,20 +298,30 @@ func (mn *MetricName) GetTagValue(tagKey string) []byte {
return nil return nil
} }
// AddMissingTags adds tags from src with keys matching addTags. // SetTags sets tags from src with keys matching addTags.
func (mn *MetricName) AddMissingTags(addTags []string, src *MetricName) { func (mn *MetricName) SetTags(addTags []string, src *MetricName) {
if hasTag(addTags, metricGroupTagKey) { for _, tagName := range addTags {
mn.MetricGroup = append(mn.MetricGroup[:0], src.MetricGroup...) if tagName == string(metricGroupTagKey) {
} mn.MetricGroup = append(mn.MetricGroup[:0], src.MetricGroup...)
for i := range src.Tags { continue
srcTag := &src.Tags[i] }
if !hasTag(addTags, srcTag.Key) { var srcTag *Tag
for i := range src.Tags {
t := &src.Tags[i]
if string(t.Key) == tagName {
srcTag = t
break
}
}
if srcTag == nil {
mn.RemoveTag(tagName)
continue continue
} }
found := false found := false
for j := range mn.Tags { for i := range mn.Tags {
tag := &mn.Tags[j] t := &mn.Tags[i]
if string(tag.Key) == string(srcTag.Key) { if string(t.Key) == tagName {
t.Value = append(t.Value[:0], srcTag.Value...)
found = true found = true
break break
} }