diff --git a/pkg/parquetquery/iters.go b/pkg/parquetquery/iters.go index 7d8aea60bc4..1544efca9bb 100644 --- a/pkg/parquetquery/iters.go +++ b/pkg/parquetquery/iters.go @@ -7,6 +7,8 @@ import ( "fmt" "io" "math" + "slices" + "strings" "sync" "sync/atomic" @@ -1805,10 +1807,12 @@ func (j *LeftJoinIterator) String() string { for _, r := range j.required { srequired += "\n\t" + util.TabOut(r) } - soptional := "optional: " - for _, o := range j.optional { - soptional += "\n\t" + util.TabOut(o) + optional := make([]string, len(j.optional)) + for i, o := range j.optional { + optional[i] = "\n\t" + util.TabOut(o) } + slices.Sort(optional) + soptional := "optional: " + strings.Join(optional, "") return fmt.Sprintf("LeftJoinIterator: %d: %s\n%s\n%s", j.definitionLevel, j.pred, srequired, soptional) } diff --git a/tempodb/encoding/vparquet4/block_traceql_test.go b/tempodb/encoding/vparquet4/block_traceql_test.go index 646ed2f0972..120fe93d60e 100644 --- a/tempodb/encoding/vparquet4/block_traceql_test.go +++ b/tempodb/encoding/vparquet4/block_traceql_test.go @@ -3,6 +3,7 @@ package vparquet4 import ( "bytes" "context" + "embed" "fmt" "math/rand" "os" @@ -52,6 +53,65 @@ func TestOne(t *testing.T) { fmt.Println(spanSet) } +//go:embed testqt/intattr.txt testqt/floatattr.txt +var testqt embed.FS + +func TestMixedTypesQuery(t *testing.T) { + t.Run("integer attribute with float", func(t *testing.T) { + wantTr := fullyPopulatedTestTrace(nil) + b := makeBackendBlockWithTraces(t, []*Trace{wantTr}) + ctx := context.Background() + q := `{.crossint > 122.9}` + req := traceql.MustExtractFetchSpansRequestWithMetadata(q) + + req.StartTimeUnixNanos = uint64(1000 * time.Second) + req.EndTimeUnixNanos = uint64(1001 * time.Second) + + resp, err := b.Fetch(ctx, req, common.DefaultSearchOptions()) + require.NoError(t, err, "search request:", req) + + spanSet, err := resp.Results.Next(ctx) + require.NoError(t, err, "search request:", req) + + fmt.Println(q) + fmt.Println("-----------") + fmt.Println(resp.Results.(*spansetIterator).iter) + fmt.Println("-----------") + fmt.Println(spanSet) + + queryTree, err := testqt.ReadFile("testqt/intattr.txt") + require.NoError(t, err) + require.Equal(t, string(queryTree), resp.Results.(*spansetIterator).iter.String()) + }) + + t.Run("float attribute with integer", func(t *testing.T) { + wantTr := fullyPopulatedTestTrace(nil) + b := makeBackendBlockWithTraces(t, []*Trace{wantTr}) + ctx := context.Background() + q := `{.crossfloat = 456}` + req := traceql.MustExtractFetchSpansRequestWithMetadata(q) + + req.StartTimeUnixNanos = uint64(1000 * time.Second) + req.EndTimeUnixNanos = uint64(1001 * time.Second) + + resp, err := b.Fetch(ctx, req, common.DefaultSearchOptions()) + require.NoError(t, err, "search request:", req) + + spanSet, err := resp.Results.Next(ctx) + require.NoError(t, err, "search request:", req) + + fmt.Println(q) + fmt.Println("-----------") + fmt.Println(resp.Results.(*spansetIterator).iter) + fmt.Println("-----------") + fmt.Println(spanSet) + + queryTree, err := testqt.ReadFile("testqt/floatattr.txt") + require.NoError(t, err) + require.Equal(t, string(queryTree), resp.Results.(*spansetIterator).iter.String()) + }) +} + func TestBackendBlockSearchTraceQL(t *testing.T) { numTraces := 250 traces := make([]*Trace, 0, numTraces) diff --git a/tempodb/encoding/vparquet4/testqt/floatattr.txt b/tempodb/encoding/vparquet4/testqt/floatattr.txt new file mode 100644 index 00000000000..af470ad56e5 --- /dev/null +++ b/tempodb/encoding/vparquet4/testqt/floatattr.txt @@ -0,0 +1,54 @@ +rebatchIterator: + LeftJoinIterator: 0: traceCollector() + required: + LeftJoinIterator: 1: batchCollector(false, 0) + required: + LeftJoinIterator: 2: instrumentationCollector(0) + required: + LeftJoinIterator: 3: spanCollector(0) + required: + bridgeIterator: + rebatchIterator: + LeftJoinIterator: 0: traceCollector() + required: + LeftJoinIterator: 1: batchCollector(true, 0) + required: + LeftJoinIterator: 2: instrumentationCollector(0) + required: + LeftJoinIterator: 3: spanCollector(0) + required: + SyncIterator: rs.list.element.ss.list.element.Spans.list.element.StatusCode : nil + optional: + LeftJoinIterator: 4: attributeCollector{} + required: + SyncIterator: rs.list.element.ss.list.element.Spans.list.element.Attrs.list.element.Key : StringInPredicate{crossfloat} + optional: + SyncIterator: rs.list.element.ss.list.element.Spans.list.element.Attrs.list.element.ValueDouble.list.element : FloatEqualPredicate{456.000000} + SyncIterator: rs.list.element.ss.list.element.Spans.list.element.Attrs.list.element.ValueInt.list.element : IntEqualPredicate{456} + optional: + optional: + LeftJoinIterator: 2: attributeCollector{} + required: + SyncIterator: rs.list.element.Resource.Attrs.list.element.Key : StringInPredicate{crossfloat} + optional: + SyncIterator: rs.list.element.Resource.Attrs.list.element.ValueDouble.list.element : FloatEqualPredicate{456.000000} + SyncIterator: rs.list.element.Resource.Attrs.list.element.ValueInt.list.element : IntEqualPredicate{456} + SyncIterator: StartTimeUnixNano : IntBetweenPredicate{0,1001000000000} + SyncIterator: EndTimeUnixNano : IntBetweenPredicate{1000000000000,9223372036854775807} + optional: + optional: + SyncIterator: rs.list.element.ss.list.element.Spans.list.element.DurationNano : nil + SyncIterator: rs.list.element.ss.list.element.Spans.list.element.SpanID : nil + SyncIterator: rs.list.element.ss.list.element.Spans.list.element.StartTimeUnixNano : nil + optional: + optional: + optional: + JoinIterator: 1: serviceStatsCollector{} + SyncIterator: ServiceStats.key_value.key : nil + SyncIterator: ServiceStats.key_value.value.SpanCount : nil + SyncIterator: ServiceStats.key_value.value.ErrorCount : nil) + SyncIterator: DurationNano : nil + SyncIterator: RootServiceName : nil + SyncIterator: RootSpanName : nil + SyncIterator: StartTimeUnixNano : nil + SyncIterator: TraceID : nil \ No newline at end of file diff --git a/tempodb/encoding/vparquet4/testqt/intattr.txt b/tempodb/encoding/vparquet4/testqt/intattr.txt new file mode 100644 index 00000000000..7fad43f3a52 --- /dev/null +++ b/tempodb/encoding/vparquet4/testqt/intattr.txt @@ -0,0 +1,54 @@ +rebatchIterator: + LeftJoinIterator: 0: traceCollector() + required: + LeftJoinIterator: 1: batchCollector(false, 0) + required: + LeftJoinIterator: 2: instrumentationCollector(0) + required: + LeftJoinIterator: 3: spanCollector(0) + required: + bridgeIterator: + rebatchIterator: + LeftJoinIterator: 0: traceCollector() + required: + LeftJoinIterator: 1: batchCollector(true, 0) + required: + LeftJoinIterator: 2: instrumentationCollector(0) + required: + LeftJoinIterator: 3: spanCollector(0) + required: + SyncIterator: rs.list.element.ss.list.element.Spans.list.element.StatusCode : nil + optional: + LeftJoinIterator: 4: attributeCollector{} + required: + SyncIterator: rs.list.element.ss.list.element.Spans.list.element.Attrs.list.element.Key : StringInPredicate{crossint} + optional: + SyncIterator: rs.list.element.ss.list.element.Spans.list.element.Attrs.list.element.ValueDouble.list.element : FloatGreaterPredicate{122.900000} + SyncIterator: rs.list.element.ss.list.element.Spans.list.element.Attrs.list.element.ValueInt.list.element : IntGreaterEqualPredicate{123} + optional: + optional: + LeftJoinIterator: 2: attributeCollector{} + required: + SyncIterator: rs.list.element.Resource.Attrs.list.element.Key : StringInPredicate{crossint} + optional: + SyncIterator: rs.list.element.Resource.Attrs.list.element.ValueDouble.list.element : FloatGreaterPredicate{122.900000} + SyncIterator: rs.list.element.Resource.Attrs.list.element.ValueInt.list.element : IntGreaterEqualPredicate{123} + SyncIterator: StartTimeUnixNano : IntBetweenPredicate{0,1001000000000} + SyncIterator: EndTimeUnixNano : IntBetweenPredicate{1000000000000,9223372036854775807} + optional: + optional: + SyncIterator: rs.list.element.ss.list.element.Spans.list.element.DurationNano : nil + SyncIterator: rs.list.element.ss.list.element.Spans.list.element.SpanID : nil + SyncIterator: rs.list.element.ss.list.element.Spans.list.element.StartTimeUnixNano : nil + optional: + optional: + optional: + JoinIterator: 1: serviceStatsCollector{} + SyncIterator: ServiceStats.key_value.key : nil + SyncIterator: ServiceStats.key_value.value.SpanCount : nil + SyncIterator: ServiceStats.key_value.value.ErrorCount : nil) + SyncIterator: DurationNano : nil + SyncIterator: RootServiceName : nil + SyncIterator: RootSpanName : nil + SyncIterator: StartTimeUnixNano : nil + SyncIterator: TraceID : nil \ No newline at end of file