diff --git a/src/query/functions/binary/binary.go b/src/query/functions/binary/binary.go index e6cd237314..14fc70892e 100644 --- a/src/query/functions/binary/binary.go +++ b/src/query/functions/binary/binary.go @@ -251,6 +251,9 @@ func intersect( if rIdx, ok := rightSigs[id]; ok { takeLeft = append(takeLeft, lIdx) correspondingRight = append(correspondingRight, rIdx) + if matching.On && matching.Card == CardOneToOne && len(matching.MatchingLabels) > 0 { + ls.Tags = ls.Tags.TagsWithKeys(matching.MatchingLabels) + } leftMetas = append(leftMetas, ls) } } diff --git a/src/query/functions/binary/binary_test.go b/src/query/functions/binary/binary_test.go index 048675d1e5..5dc03b4337 100644 --- a/src/query/functions/binary/binary_test.go +++ b/src/query/functions/binary/binary_test.go @@ -1027,3 +1027,94 @@ func TestBinaryFunctionWithDifferentNames(t *testing.T) { assert.Equal(t, expectedMeta, sink.Meta) assert.Equal(t, expectedMetas, sink.Metas) } + +func TestOneToOneMatcher(t *testing.T) { + now := time.Now() + + meta := func(bounds models.Bounds, name string, m block.ResultMetadata) block.Metadata { + return block.Metadata{ + Bounds: bounds, + Tags: models.NewTags(1, models.NewTagOptions()).SetName([]byte(name)), + ResultMetadata: m, + } + } + + var ( + bounds = models.Bounds{ + Start: now, + Duration: time.Minute * 3, + StepSize: time.Minute, + } + + lhsResultMeta = block.ResultMetadata{ + LocalOnly: true, + Exhaustive: false, + Warnings: []block.Warning{}, + } + + lhsMeta = meta(bounds, "left", lhsResultMeta) + lhsMetas = test.NewSeriesMeta("a", 2) + lhs = [][]float64{{1, 2, 3}, {4, 5, 6}} + left = test.NewBlockFromValuesWithMetaAndSeriesMeta( + lhsMeta, lhsMetas, lhs, + ) + + rhsResultMeta = block.ResultMetadata{ + LocalOnly: false, + Exhaustive: true, + Warnings: []block.Warning{{Name: "foo", Message: "bar"}}, + } + + rhsMeta = meta(bounds, "right", rhsResultMeta) + rhsMetas = test.NewSeriesMeta("a", 3)[1:] + rhs = [][]float64{{10, 20, 30}, {40, 50, 60}} + right = test.NewBlockFromValuesWithMetaAndSeriesMeta( + rhsMeta, rhsMetas, rhs, + ) + + expected = [][]float64{{41, 52, 63}, {14, 25, 36}} + ) + + op, err := NewOp( + PlusType, + NodeParams{ + LNode: parser.NodeID(0), + RNode: parser.NodeID(1), + VectorMatcherBuilder: oneToOneVectorMatchingBuilder, + }, + ) + require.NoError(t, err) + + c, sink := executor.NewControllerWithSink(parser.NodeID(2)) + node := op.(baseOp).Node(c, transform.Options{}) + + err = node.Process(models.NoopQueryContext(), parser.NodeID(0), left) + require.NoError(t, err) + + err = node.Process(models.NoopQueryContext(), parser.NodeID(1), right) + require.NoError(t, err) + + test.EqualsWithNans(t, expected, sink.Values) + + expectedMetas := []block.SeriesMeta{ + { + Name: []byte("a0"), + Tags: models.EmptyTags(), + }, + { + Name: []byte("a1"), + Tags: models.NewTags(1, models.NewTagOptions()).AddTag(toTag("a1", "a1")), + }, + } + + assert.Equal(t, expectedMetas, sink.Metas) +} + +func oneToOneVectorMatchingBuilder(_, _ block.Block) VectorMatching { + return VectorMatching{ + Set: true, + Card: CardOneToOne, + On: true, + MatchingLabels: [][]byte{[]byte("a1")}, + } +} diff --git a/src/query/test/compatibility/testdata/operators.test b/src/query/test/compatibility/testdata/operators.test index a7c541af62..33137786c9 100644 --- a/src/query/test/compatibility/testdata/operators.test +++ b/src/query/test/compatibility/testdata/operators.test @@ -198,11 +198,11 @@ eval instant at 50m (http_requests{group="canary"} + 1) and ignoring(group, job) # http_requests{group="canary", instance="1", job="api-server"} 400 # http_requests{group="canary", instance="1", job="app-server"} 800 -# FAILING issue #36. eval instant at 50m http_requests{group="canary"} / on(instance,job) http_requests{group="production"} -# {instance="0", job="api-server"} 3 -# {instance="0", job="app-server"} 1.4 -# {instance="1", job="api-server"} 2 -# {instance="1", job="app-server"} 1.3333333333333333 +eval instant at 50m http_requests{group="canary"} / on(instance,job) http_requests{group="production"} + {instance="0", job="api-server"} 3 + {instance="0", job="app-server"} 1.4 + {instance="1", job="api-server"} 2 + {instance="1", job="app-server"} 1.3333333333333333 # FAILING issue #35. eval instant at 50m http_requests{group="canary"} unless ignoring(group, instance) http_requests{instance="0"}