Skip to content

Commit 812d768

Browse files
committed
wip
1 parent e709f8a commit 812d768

File tree

8 files changed

+449
-4
lines changed

8 files changed

+449
-4
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,3 +26,6 @@ integration/e2e/deployments/e2e_integration_test[0-9]*
2626
/tmp
2727
gh-token.txt
2828
.cache
29+
.devcontainer
30+
testdata
31+
k6

tempodb/encoding/vparquet2/block_traceql.go

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1759,6 +1759,45 @@ func createIntPredicate(op traceql.Operator, operands traceql.Operands) (parquet
17591759
}
17601760
}
17611761

1762+
// createIntPredicateFromFloat adapts float comparisons for integer fields.
1763+
// If the float has no fractional part, it's treated as an integer directly.
1764+
// Otherwise, depending on the operator, the comparison boundary is shifted up or down
1765+
// to the nearest integer, or a trivial true/false predicate is returned as needed.
1766+
func createIntPredicateFromFloat(op traceql.Operator, operands traceql.Operands) (parquetquery.Predicate, error) {
1767+
if op == traceql.OpNone {
1768+
return nil, nil
1769+
}
1770+
1771+
f := operands[0].Float()
1772+
1773+
// Treat it as an integer if the fractional part of the float is zero
1774+
if _, frac := math.Modf(f); frac == 0 {
1775+
operands := traceql.Operands{traceql.NewStaticInt(int(f))}
1776+
return createIntPredicate(op, operands)
1777+
}
1778+
1779+
switch op {
1780+
case traceql.OpEqual:
1781+
// No reason to search for an exact match among integers if the float has a fractional part
1782+
return nil, nil
1783+
case traceql.OpNotEqual:
1784+
// An integer always differs from a float with a fraction
1785+
return parquetquery.NewCallbackPredicate(func() bool { return true }), nil
1786+
case traceql.OpGreater, traceql.OpGreaterEqual:
1787+
// Shift to the next integer for a float with a fraction
1788+
// { .attr > 123.4 } -> { .attr >= 124 }
1789+
// { .attr >= 123.4 } -> { .attr >= 124 }
1790+
return createIntPredicate(traceql.OpGreaterEqual, traceql.Operands{traceql.NewStaticInt(int(f) + 1)})
1791+
case traceql.OpLess, traceql.OpLessEqual:
1792+
// Use the integer floor for a float with a fraction
1793+
// { .attr < 123.4 } -> { .attr <= 123 }
1794+
// { .attr <= 123.4 } -> { .attr <= 123 }
1795+
return createIntPredicate(traceql.OpLessEqual, traceql.Operands{traceql.NewStaticInt(int(f))})
1796+
default:
1797+
return nil, fmt.Errorf("operator not supported for integers(from float): %+v", op)
1798+
}
1799+
}
1800+
17621801
func createFloatPredicate(op traceql.Operator, operands traceql.Operands) (parquetquery.Predicate, error) {
17631802
if op == traceql.OpNone {
17641803
return nil, nil
@@ -1846,13 +1885,33 @@ func createAttributeIterator(makeIter makeIterFn, conditions []traceql.Condition
18461885
attrStringPreds = append(attrStringPreds, pred)
18471886

18481887
case traceql.TypeInt:
1888+
// Create a predicate specifically for integer comparisons
18491889
pred, err := createIntPredicate(cond.Op, cond.Operands)
18501890
if err != nil {
18511891
return nil, fmt.Errorf("creating attribute predicate: %w", err)
18521892
}
18531893
attrIntPreds = append(attrIntPreds, pred)
18541894

1895+
// If the operand can also be interpreted as a float, create an additional predicate
1896+
if i, ok := cond.Operands[0].Int(); ok {
1897+
// Convert the integer operand to a float to handle cross-type comparisons
1898+
operands := traceql.Operands{traceql.NewStaticFloat(float64(i))}
1899+
pred, err := createFloatPredicate(cond.Op, operands)
1900+
if err != nil {
1901+
return nil, fmt.Errorf("creating attribute predicate: %w", err)
1902+
}
1903+
attrFltPreds = append(attrFltPreds, pred)
1904+
}
1905+
18551906
case traceql.TypeFloat:
1907+
// Attempt to create a predicate for integer comparisons, if applicable
1908+
if pred, err := createIntPredicateFromFloat(cond.Op, cond.Operands); err != nil {
1909+
return nil, fmt.Errorf("creating attribute predicate: %w", err)
1910+
} else if pred != nil {
1911+
attrIntPreds = append(attrIntPreds, pred)
1912+
}
1913+
1914+
// Create a predicate specifically for float comparisons
18561915
pred, err := createFloatPredicate(cond.Op, cond.Operands)
18571916
if err != nil {
18581917
return nil, fmt.Errorf("creating attribute predicate: %w", err)

tempodb/encoding/vparquet2/block_traceql_test.go

Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,31 @@ func TestBackendBlockSearchTraceQL(t *testing.T) {
209209
parse(t, `{resource.`+LabelServiceName+` <= 124}`),
210210
},
211211
},
212+
// Cross-type comparisons
213+
traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossint > 122.9}`),
214+
traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossint >= 122.9}`),
215+
traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossint <= 123.0}`),
216+
traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossint = 123.0}`),
217+
traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossint != 123.1}`),
218+
traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossint >= 123.0}`),
219+
traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossint < 123.1}`),
220+
traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossint <= 123.1}`),
221+
traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossfloat_nofrag > 455}`),
222+
traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossfloat_nofrag >= 455}`),
223+
traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossfloat_nofrag <= 456}`),
224+
traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossfloat_nofrag = 456}`),
225+
traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossfloat_nofrag != 457}`),
226+
traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossfloat_nofrag >= 456}`),
227+
traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossfloat_nofrag <= 457}`),
228+
traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossfloat_nofrag < 457}`),
229+
traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossfloat_frag != 455}`),
230+
traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossfloat_frag > 455}`),
231+
traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossfloat_frag >= 455}`),
232+
traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossfloat_frag > 456}`),
233+
traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossfloat_frag >= 456}`),
234+
traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossfloat_frag <= 457}`),
235+
traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossfloat_frag < 457}`),
236+
traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossfloat_frag != 457}`),
212237
}
213238

214239
for _, req := range searchesThatMatch {
@@ -316,6 +341,31 @@ func TestBackendBlockSearchTraceQL(t *testing.T) {
316341
parse(t, `{`+LabelDuration+` = 100s }`), // Match
317342
},
318343
},
344+
// Cross-type comparisons
345+
traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossint < 122.9}`),
346+
traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossint = 122.9}`),
347+
traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossint <= 122.9}`),
348+
traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossint < 123.0}`),
349+
traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossint != 123.0}`),
350+
traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossint > 123.0}`),
351+
traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossint >= 123.1}`),
352+
traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossint = 123.1}`),
353+
traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossint > 123.1}`),
354+
traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossfloat_nofrag < 455}`),
355+
traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossfloat_nofrag = 455}`),
356+
traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossfloat_nofrag <= 455}`),
357+
traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossfloat_nofrag < 456}`),
358+
traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossfloat_nofrag != 456}`),
359+
traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossfloat_nofrag > 456}`),
360+
traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossfloat_nofrag >= 457}`),
361+
traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossfloat_nofrag = 457}`),
362+
traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossfloat_nofrag > 457}`),
363+
traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossfloat_frag < 456}`),
364+
traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossfloat_frag = 456}`),
365+
traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossfloat_frag <= 456}`),
366+
traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossfloat_frag >= 457}`),
367+
traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossfloat_frag = 457}`),
368+
traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossfloat_frag > 457}`),
319369
}
320370

321371
for _, req := range searchesThatDontMatch {
@@ -431,7 +481,10 @@ func fullyPopulatedTestTrace(id common.ID) *Trace {
431481
{Key: "bar", ValueInt: intPtr(123)},
432482
{Key: "float", ValueDouble: fltPtr(456.78)},
433483
{Key: "bool", ValueBool: boolPtr(false)},
434-
484+
// For cross-type comparisons
485+
{Key: "crossint", ValueInt: intPtr(123)},
486+
{Key: "crossfloat_nofrag", ValueDouble: fltPtr(456.0)},
487+
{Key: "crossfloat_frag", ValueDouble: fltPtr(456.78)},
435488
// Edge-cases
436489
{Key: LabelName, Value: strPtr("Bob")}, // Conflicts with intrinsic but still looked up by .name
437490
{Key: LabelServiceName, Value: strPtr("spanservicename")}, // Overrides resource-level dedicated column

tempodb/encoding/vparquet3/block_traceql.go

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2063,6 +2063,45 @@ func createIntPredicate(op traceql.Operator, operands traceql.Operands) (parquet
20632063
}
20642064
}
20652065

2066+
// createIntPredicateFromFloat adapts float comparisons for integer fields.
2067+
// If the float has no fractional part, it's treated as an integer directly.
2068+
// Otherwise, depending on the operator, the comparison boundary is shifted up or down
2069+
// to the nearest integer, or a trivial true/false predicate is returned as needed.
2070+
func createIntPredicateFromFloat(op traceql.Operator, operands traceql.Operands) (parquetquery.Predicate, error) {
2071+
if op == traceql.OpNone {
2072+
return nil, nil
2073+
}
2074+
2075+
f := operands[0].Float()
2076+
2077+
// Treat it as an integer if the fractional part of the float is zero
2078+
if _, frac := math.Modf(f); frac == 0 {
2079+
operands := traceql.Operands{traceql.NewStaticInt(int(f))}
2080+
return createIntPredicate(op, operands)
2081+
}
2082+
2083+
switch op {
2084+
case traceql.OpEqual:
2085+
// No reason to search for an exact match among integers if the float has a fractional part
2086+
return nil, nil
2087+
case traceql.OpNotEqual:
2088+
// An integer always differs from a float with a fraction
2089+
return parquetquery.NewCallbackPredicate(func() bool { return true }), nil
2090+
case traceql.OpGreater, traceql.OpGreaterEqual:
2091+
// Shift to the next integer for a float with a fraction
2092+
// { .attr > 123.4 } -> { .attr >= 124 }
2093+
// { .attr >= 123.4 } -> { .attr >= 124 }
2094+
return createIntPredicate(traceql.OpGreaterEqual, traceql.Operands{traceql.NewStaticInt(int(f) + 1)})
2095+
case traceql.OpLess, traceql.OpLessEqual:
2096+
// Use the integer floor for a float with a fraction
2097+
// { .attr < 123.4 } -> { .attr <= 123 }
2098+
// { .attr <= 123.4 } -> { .attr <= 123 }
2099+
return createIntPredicate(traceql.OpLessEqual, traceql.Operands{traceql.NewStaticInt(int(f))})
2100+
default:
2101+
return nil, fmt.Errorf("operator not supported for integers(from float): %+v", op)
2102+
}
2103+
}
2104+
20662105
func createFloatPredicate(op traceql.Operator, operands traceql.Operands) (parquetquery.Predicate, error) {
20672106
if op == traceql.OpNone {
20682107
return nil, nil
@@ -2164,13 +2203,33 @@ func createAttributeIterator(makeIter makeIterFn, conditions []traceql.Condition
21642203
attrStringPreds = append(attrStringPreds, pred)
21652204

21662205
case traceql.TypeInt:
2206+
// Create a predicate specifically for integer comparisons
21672207
pred, err := createIntPredicate(cond.Op, cond.Operands)
21682208
if err != nil {
21692209
return nil, fmt.Errorf("creating attribute predicate: %w", err)
21702210
}
21712211
attrIntPreds = append(attrIntPreds, pred)
21722212

2213+
// If the operand can also be interpreted as a float, create an additional predicate
2214+
if i, ok := cond.Operands[0].Int(); ok {
2215+
// Convert the integer operand to a float to handle cross-type comparisons
2216+
operands := traceql.Operands{traceql.NewStaticFloat(float64(i))}
2217+
pred, err := createFloatPredicate(cond.Op, operands)
2218+
if err != nil {
2219+
return nil, fmt.Errorf("creating attribute predicate: %w", err)
2220+
}
2221+
attrFltPreds = append(attrFltPreds, pred)
2222+
}
2223+
21732224
case traceql.TypeFloat:
2225+
// Attempt to create a predicate for integer comparisons, if applicable
2226+
if pred, err := createIntPredicateFromFloat(cond.Op, cond.Operands); err != nil {
2227+
return nil, fmt.Errorf("creating attribute predicate: %w", err)
2228+
} else if pred != nil {
2229+
attrIntPreds = append(attrIntPreds, pred)
2230+
}
2231+
2232+
// Create a predicate specifically for float comparisons
21742233
pred, err := createFloatPredicate(cond.Op, cond.Operands)
21752234
if err != nil {
21762235
return nil, fmt.Errorf("creating attribute predicate: %w", err)

tempodb/encoding/vparquet3/block_traceql_test.go

Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,31 @@ func TestBackendBlockSearchTraceQL(t *testing.T) {
222222
},
223223
},
224224
},
225+
// Cross-type comparisons
226+
{".crossint > 122.9", traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossint > 122.9}`)},
227+
{".crossint >= 122.9", traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossint >= 122.9}`)},
228+
{".crossint <= 123.0", traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossint <= 123.0}`)},
229+
{".crossint = 123.0", traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossint = 123.0}`)},
230+
{".crossint != 123.1", traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossint != 123.1}`)},
231+
{".crossint >= 123.0", traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossint >= 123.0}`)},
232+
{".crossint < 123.1", traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossint < 123.1}`)},
233+
{".crossint <= 123.1", traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossint <= 123.1}`)},
234+
{".crossfloat_nofrag > 455", traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossfloat_nofrag > 455}`)},
235+
{".crossfloat_nofrag >= 455", traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossfloat_nofrag >= 455}`)},
236+
{".crossfloat_nofrag <= 456", traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossfloat_nofrag <= 456}`)},
237+
{".crossfloat_nofrag = 456", traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossfloat_nofrag = 456}`)},
238+
{".crossfloat_nofrag != 457", traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossfloat_nofrag != 457}`)},
239+
{".crossfloat_nofrag >= 456", traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossfloat_nofrag >= 456}`)},
240+
{".crossfloat_nofrag <= 457", traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossfloat_nofrag <= 457}`)},
241+
{".crossfloat_nofrag < 457", traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossfloat_nofrag < 457}`)},
242+
{".crossfloat_frag != 455", traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossfloat_frag != 455}`)},
243+
{".crossfloat_frag > 455", traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossfloat_frag > 455}`)},
244+
{".crossfloat_frag >= 455", traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossfloat_frag >= 455}`)},
245+
{".crossfloat_frag > 456", traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossfloat_frag > 456}`)},
246+
{".crossfloat_frag >= 456", traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossfloat_frag >= 456}`)},
247+
{".crossfloat_frag <= 457", traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossfloat_frag <= 457}`)},
248+
{".crossfloat_frag < 457", traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossfloat_frag < 457}`)},
249+
{".crossfloat_frag != 457", traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossfloat_frag != 457}`)},
225250
}
226251

227252
for _, tc := range searchesThatMatch {
@@ -348,6 +373,31 @@ func TestBackendBlockSearchTraceQL(t *testing.T) {
348373
},
349374
},
350375
},
376+
// Cross-type comparisons
377+
{".crossint < 122.9", traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossint < 122.9}`)},
378+
{".crossint = 122.9", traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossint = 122.9}`)},
379+
{".crossint <= 122.9", traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossint <= 122.9}`)},
380+
{".crossint < 123.0", traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossint < 123.0}`)},
381+
{".crossint != 123.0", traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossint != 123.0}`)},
382+
{".crossint > 123.0", traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossint > 123.0}`)},
383+
{".crossint >= 123.1", traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossint >= 123.1}`)},
384+
{".crossint = 123.1", traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossint = 123.1}`)},
385+
{".crossint > 123.1", traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossint > 123.1}`)},
386+
{".crossfloat_nofrag < 455", traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossfloat_nofrag < 455}`)},
387+
{".crossfloat_nofrag = 455", traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossfloat_nofrag = 455}`)},
388+
{".crossfloat_nofrag <= 455", traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossfloat_nofrag <= 455}`)},
389+
{".crossfloat_nofrag < 456", traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossfloat_nofrag < 456}`)},
390+
{".crossfloat_nofrag != 456", traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossfloat_nofrag != 456}`)},
391+
{".crossfloat_nofrag > 456", traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossfloat_nofrag > 456}`)},
392+
{".crossfloat_nofrag >= 457", traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossfloat_nofrag >= 457}`)},
393+
{".crossfloat_nofrag = 457", traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossfloat_nofrag = 457}`)},
394+
{".crossfloat_nofrag > 457", traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossfloat_nofrag > 457}`)},
395+
{".crossfloat_frag < 456", traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossfloat_frag < 456}`)},
396+
{".crossfloat_frag = 456", traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossfloat_frag = 456}`)},
397+
{".crossfloat_frag <= 456", traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossfloat_frag <= 456}`)},
398+
{".crossfloat_frag >= 457", traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossfloat_frag >= 457}`)},
399+
{".crossfloat_frag = 457", traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossfloat_frag = 457}`)},
400+
{".crossfloat_frag > 457", traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossfloat_frag > 457}`)},
351401
}
352402

353403
for _, tc := range searchesThatDontMatch {
@@ -475,7 +525,10 @@ func fullyPopulatedTestTrace(id common.ID) *Trace {
475525
{Key: "bar", ValueInt: intPtr(123)},
476526
{Key: "float", ValueDouble: fltPtr(456.78)},
477527
{Key: "bool", ValueBool: boolPtr(false)},
478-
528+
// For cross-type comparisons
529+
{Key: "crossint", ValueInt: intPtr(123)},
530+
{Key: "crossfloat_nofrag", ValueDouble: fltPtr(456.0)},
531+
{Key: "crossfloat_frag", ValueDouble: fltPtr(456.78)},
479532
// Edge-cases
480533
{Key: LabelName, Value: strPtr("Bob")}, // Conflicts with intrinsic but still looked up by .name
481534
{Key: LabelServiceName, Value: strPtr("spanservicename")}, // Overrides resource-level dedicated column

0 commit comments

Comments
 (0)