Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
ndk committed Jan 10, 2025
1 parent e709f8a commit 812d768
Show file tree
Hide file tree
Showing 8 changed files with 449 additions and 4 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,6 @@ integration/e2e/deployments/e2e_integration_test[0-9]*
/tmp
gh-token.txt
.cache
.devcontainer
testdata
k6
59 changes: 59 additions & 0 deletions tempodb/encoding/vparquet2/block_traceql.go
Original file line number Diff line number Diff line change
Expand Up @@ -1759,6 +1759,45 @@ func createIntPredicate(op traceql.Operator, operands traceql.Operands) (parquet
}
}

// createIntPredicateFromFloat adapts float comparisons for integer fields.
// If the float has no fractional part, it's treated as an integer directly.
// Otherwise, depending on the operator, the comparison boundary is shifted up or down
// to the nearest integer, or a trivial true/false predicate is returned as needed.
func createIntPredicateFromFloat(op traceql.Operator, operands traceql.Operands) (parquetquery.Predicate, error) {
if op == traceql.OpNone {
return nil, nil
}

f := operands[0].Float()

// Treat it as an integer if the fractional part of the float is zero
if _, frac := math.Modf(f); frac == 0 {
operands := traceql.Operands{traceql.NewStaticInt(int(f))}
return createIntPredicate(op, operands)
}

switch op {
case traceql.OpEqual:
// No reason to search for an exact match among integers if the float has a fractional part
return nil, nil
case traceql.OpNotEqual:
// An integer always differs from a float with a fraction
return parquetquery.NewCallbackPredicate(func() bool { return true }), nil
case traceql.OpGreater, traceql.OpGreaterEqual:
// Shift to the next integer for a float with a fraction
// { .attr > 123.4 } -> { .attr >= 124 }
// { .attr >= 123.4 } -> { .attr >= 124 }
return createIntPredicate(traceql.OpGreaterEqual, traceql.Operands{traceql.NewStaticInt(int(f) + 1)})
case traceql.OpLess, traceql.OpLessEqual:
// Use the integer floor for a float with a fraction
// { .attr < 123.4 } -> { .attr <= 123 }
// { .attr <= 123.4 } -> { .attr <= 123 }
return createIntPredicate(traceql.OpLessEqual, traceql.Operands{traceql.NewStaticInt(int(f))})
default:
return nil, fmt.Errorf("operator not supported for integers(from float): %+v", op)
}
}

func createFloatPredicate(op traceql.Operator, operands traceql.Operands) (parquetquery.Predicate, error) {
if op == traceql.OpNone {
return nil, nil
Expand Down Expand Up @@ -1846,13 +1885,33 @@ func createAttributeIterator(makeIter makeIterFn, conditions []traceql.Condition
attrStringPreds = append(attrStringPreds, pred)

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

// If the operand can also be interpreted as a float, create an additional predicate
if i, ok := cond.Operands[0].Int(); ok {
// Convert the integer operand to a float to handle cross-type comparisons
operands := traceql.Operands{traceql.NewStaticFloat(float64(i))}
pred, err := createFloatPredicate(cond.Op, operands)
if err != nil {
return nil, fmt.Errorf("creating attribute predicate: %w", err)
}
attrFltPreds = append(attrFltPreds, pred)
}

case traceql.TypeFloat:
// Attempt to create a predicate for integer comparisons, if applicable
if pred, err := createIntPredicateFromFloat(cond.Op, cond.Operands); err != nil {
return nil, fmt.Errorf("creating attribute predicate: %w", err)
} else if pred != nil {
attrIntPreds = append(attrIntPreds, pred)
}

// Create a predicate specifically for float comparisons
pred, err := createFloatPredicate(cond.Op, cond.Operands)
if err != nil {
return nil, fmt.Errorf("creating attribute predicate: %w", err)
Expand Down
55 changes: 54 additions & 1 deletion tempodb/encoding/vparquet2/block_traceql_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,31 @@ func TestBackendBlockSearchTraceQL(t *testing.T) {
parse(t, `{resource.`+LabelServiceName+` <= 124}`),
},
},
// Cross-type comparisons
traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossint > 122.9}`),
traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossint >= 122.9}`),
traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossint <= 123.0}`),
traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossint = 123.0}`),
traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossint != 123.1}`),
traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossint >= 123.0}`),
traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossint < 123.1}`),
traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossint <= 123.1}`),
traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossfloat_nofrag > 455}`),
traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossfloat_nofrag >= 455}`),
traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossfloat_nofrag <= 456}`),
traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossfloat_nofrag = 456}`),
traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossfloat_nofrag != 457}`),
traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossfloat_nofrag >= 456}`),
traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossfloat_nofrag <= 457}`),
traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossfloat_nofrag < 457}`),
traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossfloat_frag != 455}`),
traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossfloat_frag > 455}`),
traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossfloat_frag >= 455}`),
traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossfloat_frag > 456}`),
traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossfloat_frag >= 456}`),
traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossfloat_frag <= 457}`),
traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossfloat_frag < 457}`),
traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossfloat_frag != 457}`),
}

for _, req := range searchesThatMatch {
Expand Down Expand Up @@ -316,6 +341,31 @@ func TestBackendBlockSearchTraceQL(t *testing.T) {
parse(t, `{`+LabelDuration+` = 100s }`), // Match
},
},
// Cross-type comparisons
traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossint < 122.9}`),
traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossint = 122.9}`),
traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossint <= 122.9}`),
traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossint < 123.0}`),
traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossint != 123.0}`),
traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossint > 123.0}`),
traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossint >= 123.1}`),
traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossint = 123.1}`),
traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossint > 123.1}`),
traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossfloat_nofrag < 455}`),
traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossfloat_nofrag = 455}`),
traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossfloat_nofrag <= 455}`),
traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossfloat_nofrag < 456}`),
traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossfloat_nofrag != 456}`),
traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossfloat_nofrag > 456}`),
traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossfloat_nofrag >= 457}`),
traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossfloat_nofrag = 457}`),
traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossfloat_nofrag > 457}`),
traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossfloat_frag < 456}`),
traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossfloat_frag = 456}`),
traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossfloat_frag <= 456}`),
traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossfloat_frag >= 457}`),
traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossfloat_frag = 457}`),
traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossfloat_frag > 457}`),
}

for _, req := range searchesThatDontMatch {
Expand Down Expand Up @@ -431,7 +481,10 @@ func fullyPopulatedTestTrace(id common.ID) *Trace {
{Key: "bar", ValueInt: intPtr(123)},
{Key: "float", ValueDouble: fltPtr(456.78)},
{Key: "bool", ValueBool: boolPtr(false)},

// For cross-type comparisons
{Key: "crossint", ValueInt: intPtr(123)},
{Key: "crossfloat_nofrag", ValueDouble: fltPtr(456.0)},
{Key: "crossfloat_frag", ValueDouble: fltPtr(456.78)},
// Edge-cases
{Key: LabelName, Value: strPtr("Bob")}, // Conflicts with intrinsic but still looked up by .name
{Key: LabelServiceName, Value: strPtr("spanservicename")}, // Overrides resource-level dedicated column
Expand Down
59 changes: 59 additions & 0 deletions tempodb/encoding/vparquet3/block_traceql.go
Original file line number Diff line number Diff line change
Expand Up @@ -2063,6 +2063,45 @@ func createIntPredicate(op traceql.Operator, operands traceql.Operands) (parquet
}
}

// createIntPredicateFromFloat adapts float comparisons for integer fields.
// If the float has no fractional part, it's treated as an integer directly.
// Otherwise, depending on the operator, the comparison boundary is shifted up or down
// to the nearest integer, or a trivial true/false predicate is returned as needed.
func createIntPredicateFromFloat(op traceql.Operator, operands traceql.Operands) (parquetquery.Predicate, error) {
if op == traceql.OpNone {
return nil, nil
}

f := operands[0].Float()

// Treat it as an integer if the fractional part of the float is zero
if _, frac := math.Modf(f); frac == 0 {
operands := traceql.Operands{traceql.NewStaticInt(int(f))}
return createIntPredicate(op, operands)
}

switch op {
case traceql.OpEqual:
// No reason to search for an exact match among integers if the float has a fractional part
return nil, nil
case traceql.OpNotEqual:
// An integer always differs from a float with a fraction
return parquetquery.NewCallbackPredicate(func() bool { return true }), nil
case traceql.OpGreater, traceql.OpGreaterEqual:
// Shift to the next integer for a float with a fraction
// { .attr > 123.4 } -> { .attr >= 124 }
// { .attr >= 123.4 } -> { .attr >= 124 }
return createIntPredicate(traceql.OpGreaterEqual, traceql.Operands{traceql.NewStaticInt(int(f) + 1)})
case traceql.OpLess, traceql.OpLessEqual:
// Use the integer floor for a float with a fraction
// { .attr < 123.4 } -> { .attr <= 123 }
// { .attr <= 123.4 } -> { .attr <= 123 }
return createIntPredicate(traceql.OpLessEqual, traceql.Operands{traceql.NewStaticInt(int(f))})
default:
return nil, fmt.Errorf("operator not supported for integers(from float): %+v", op)
}
}

func createFloatPredicate(op traceql.Operator, operands traceql.Operands) (parquetquery.Predicate, error) {
if op == traceql.OpNone {
return nil, nil
Expand Down Expand Up @@ -2164,13 +2203,33 @@ func createAttributeIterator(makeIter makeIterFn, conditions []traceql.Condition
attrStringPreds = append(attrStringPreds, pred)

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

// If the operand can also be interpreted as a float, create an additional predicate
if i, ok := cond.Operands[0].Int(); ok {
// Convert the integer operand to a float to handle cross-type comparisons
operands := traceql.Operands{traceql.NewStaticFloat(float64(i))}
pred, err := createFloatPredicate(cond.Op, operands)
if err != nil {
return nil, fmt.Errorf("creating attribute predicate: %w", err)
}
attrFltPreds = append(attrFltPreds, pred)
}

case traceql.TypeFloat:
// Attempt to create a predicate for integer comparisons, if applicable
if pred, err := createIntPredicateFromFloat(cond.Op, cond.Operands); err != nil {
return nil, fmt.Errorf("creating attribute predicate: %w", err)
} else if pred != nil {
attrIntPreds = append(attrIntPreds, pred)
}

// Create a predicate specifically for float comparisons
pred, err := createFloatPredicate(cond.Op, cond.Operands)
if err != nil {
return nil, fmt.Errorf("creating attribute predicate: %w", err)
Expand Down
55 changes: 54 additions & 1 deletion tempodb/encoding/vparquet3/block_traceql_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,31 @@ func TestBackendBlockSearchTraceQL(t *testing.T) {
},
},
},
// Cross-type comparisons
{".crossint > 122.9", traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossint > 122.9}`)},
{".crossint >= 122.9", traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossint >= 122.9}`)},
{".crossint <= 123.0", traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossint <= 123.0}`)},
{".crossint = 123.0", traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossint = 123.0}`)},
{".crossint != 123.1", traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossint != 123.1}`)},
{".crossint >= 123.0", traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossint >= 123.0}`)},
{".crossint < 123.1", traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossint < 123.1}`)},
{".crossint <= 123.1", traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossint <= 123.1}`)},
{".crossfloat_nofrag > 455", traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossfloat_nofrag > 455}`)},
{".crossfloat_nofrag >= 455", traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossfloat_nofrag >= 455}`)},
{".crossfloat_nofrag <= 456", traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossfloat_nofrag <= 456}`)},
{".crossfloat_nofrag = 456", traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossfloat_nofrag = 456}`)},
{".crossfloat_nofrag != 457", traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossfloat_nofrag != 457}`)},
{".crossfloat_nofrag >= 456", traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossfloat_nofrag >= 456}`)},
{".crossfloat_nofrag <= 457", traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossfloat_nofrag <= 457}`)},
{".crossfloat_nofrag < 457", traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossfloat_nofrag < 457}`)},
{".crossfloat_frag != 455", traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossfloat_frag != 455}`)},
{".crossfloat_frag > 455", traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossfloat_frag > 455}`)},
{".crossfloat_frag >= 455", traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossfloat_frag >= 455}`)},
{".crossfloat_frag > 456", traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossfloat_frag > 456}`)},
{".crossfloat_frag >= 456", traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossfloat_frag >= 456}`)},
{".crossfloat_frag <= 457", traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossfloat_frag <= 457}`)},
{".crossfloat_frag < 457", traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossfloat_frag < 457}`)},
{".crossfloat_frag != 457", traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossfloat_frag != 457}`)},
}

for _, tc := range searchesThatMatch {
Expand Down Expand Up @@ -348,6 +373,31 @@ func TestBackendBlockSearchTraceQL(t *testing.T) {
},
},
},
// Cross-type comparisons
{".crossint < 122.9", traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossint < 122.9}`)},
{".crossint = 122.9", traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossint = 122.9}`)},
{".crossint <= 122.9", traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossint <= 122.9}`)},
{".crossint < 123.0", traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossint < 123.0}`)},
{".crossint != 123.0", traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossint != 123.0}`)},
{".crossint > 123.0", traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossint > 123.0}`)},
{".crossint >= 123.1", traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossint >= 123.1}`)},
{".crossint = 123.1", traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossint = 123.1}`)},
{".crossint > 123.1", traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossint > 123.1}`)},
{".crossfloat_nofrag < 455", traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossfloat_nofrag < 455}`)},
{".crossfloat_nofrag = 455", traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossfloat_nofrag = 455}`)},
{".crossfloat_nofrag <= 455", traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossfloat_nofrag <= 455}`)},
{".crossfloat_nofrag < 456", traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossfloat_nofrag < 456}`)},
{".crossfloat_nofrag != 456", traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossfloat_nofrag != 456}`)},
{".crossfloat_nofrag > 456", traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossfloat_nofrag > 456}`)},
{".crossfloat_nofrag >= 457", traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossfloat_nofrag >= 457}`)},
{".crossfloat_nofrag = 457", traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossfloat_nofrag = 457}`)},
{".crossfloat_nofrag > 457", traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossfloat_nofrag > 457}`)},
{".crossfloat_frag < 456", traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossfloat_frag < 456}`)},
{".crossfloat_frag = 456", traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossfloat_frag = 456}`)},
{".crossfloat_frag <= 456", traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossfloat_frag <= 456}`)},
{".crossfloat_frag >= 457", traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossfloat_frag >= 457}`)},
{".crossfloat_frag = 457", traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossfloat_frag = 457}`)},
{".crossfloat_frag > 457", traceql.MustExtractFetchSpansRequestWithMetadata(`{.crossfloat_frag > 457}`)},
}

for _, tc := range searchesThatDontMatch {
Expand Down Expand Up @@ -475,7 +525,10 @@ func fullyPopulatedTestTrace(id common.ID) *Trace {
{Key: "bar", ValueInt: intPtr(123)},
{Key: "float", ValueDouble: fltPtr(456.78)},
{Key: "bool", ValueBool: boolPtr(false)},

// For cross-type comparisons
{Key: "crossint", ValueInt: intPtr(123)},
{Key: "crossfloat_nofrag", ValueDouble: fltPtr(456.0)},
{Key: "crossfloat_frag", ValueDouble: fltPtr(456.78)},
// Edge-cases
{Key: LabelName, Value: strPtr("Bob")}, // Conflicts with intrinsic but still looked up by .name
{Key: LabelServiceName, Value: strPtr("spanservicename")}, // Overrides resource-level dedicated column
Expand Down
Loading

0 comments on commit 812d768

Please sign in to comment.