Skip to content

feat(eap): Resolve session_id and gen_ai.conversation.id to their indexed columns#8185

Open
pbhandari wants to merge 3 commits into
masterfrom
ref/use-indexed-columns
Open

feat(eap): Resolve session_id and gen_ai.conversation.id to their indexed columns#8185
pbhandari wants to merge 3 commits into
masterfrom
ref/use-indexed-columns

Conversation

@pbhandari

@pbhandari pbhandari commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

sentry.session_id and gen_ai.conversation.id now resolve to their dedicated top-level columns (session_id, ai_conversation_id) instead of the attributes_string[...] map, so = / IN <literal> filters on them prune
granules through the bf_session_id / bf_ai_conversation_id bloom-filter skip indexes.

The change is in the shared attribute_key_to_expression resolver, so every EAP endpoint (/events/ TraceItemTable, TimeSeries, TraceItemStats, GetTraces, GetTrace, TraceItemDetails, ExportTraceItems) gets it automatically.

To allow this, we refactored NORMALIZED_COLUMNS_EAP_ITEMS so that it now maps an attribute name to an explicit NormalizedColumn(column_name, types) named-tuple rather than deriving the column by stripping the sentry. prefix. That is to facilitategen_ai.conversation.id to map to ai_conversation_id.

We also removed the COLUMN_PREFIX constant, as it's no longer serving it's original purpose. The lone sentry.timestamp check that used it is inlined.

Review focus — absence semantics: a missing value for used to read as NULL (map miss) and now reads as the column default ('' for the String ai_conversation_id, the zero UUID for session_id). This matches how existing normalized columns such as sentry.trace_id already behave. We expect the columns to already have been populated where appropriate.

tests/web/rpc/v1/test_indexed_columns.py runs each filter through a real TraceItemTable query and asserts via EXPLAIN indexes = 1 that the expected skip index is applied, and that the returned rows are correct.

Related PRs

Refs: https://linear.app/getsentry/issue/EAP-620

🤖 Generated with Claude Code

@linear-code

linear-code Bot commented Jul 15, 2026

Copy link
Copy Markdown

EAP-620

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not really sure about this file tbh. Feel bad checking something in without tests, and this was very helpful during local development. But I'm not sure it rises to the level of "useful enough to be checked in"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's useful to verify we're using the right column. I'd keep it.

@pbhandari
pbhandari marked this pull request as ready for review July 15, 2026 16:01
@pbhandari
pbhandari requested review from a team as code owners July 15, 2026 16:01
Comment thread snuba/protos/common.py

@phacops phacops left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The caveat with this PR is once we enable this, we won't be able to select conversations that are not in the index. Make sure the team knows about it. We've been writing conversations for about 3 weeks.

Comment thread snuba/web/rpc/common/common.py Outdated

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's useful to verify we're using the right column. I'd keep it.

Comment thread tests/web/rpc/v1/test_indexed_columns.py
@pbhandari
pbhandari force-pushed the ref/use-indexed-columns branch from 1d71dfc to a8ac385 Compare July 15, 2026 19:59
Comment thread tests/web/rpc/v1/test_indexed_columns.py
Comment thread snuba/web/rpc/v1/resolvers/R_eap_items/resolver_trace_item_table.py
@pbhandari
pbhandari force-pushed the ref/use-indexed-columns branch from a8ac385 to f623713 Compare July 17, 2026 14:11

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit f623713. Configure here.

# (empty) value from a real one.
base = field.parameters[0]
if isinstance(base, Column) and base.column_name in EMPTY_STRING_DEFAULT_COLUMNS:
return f.notEmpty(field)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Null filters disagree with exists

Medium Severity

exists on gen_ai.conversation.id now treats the empty-string default as absent via notEmpty, but = / != null comparisons still go through isNull on the non-nullable column. Unset rows therefore fail exists while still satisfying != null (and never match = null), so null filters no longer align with existence checks after the map-to-column move.

Additional Locations (2)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit f623713. Configure here.

Comment thread snuba/protos/common.py
Comment on lines +61 to +63
sentry_column("session_id"): NormalizedColumn("session_id", [AttributeKey.Type.TYPE_STRING]),
"gen_ai.conversation.id": NormalizedColumn(
"ai_conversation_id", [AttributeKey.Type.TYPE_STRING]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: The session_id column, a UUID, is cast to a String during queries. This CAST operation prevents the ClickHouse bloom filter index from being used, negating performance gains.
Severity: MEDIUM

Suggested Fix

Register session_id with its native UUID type instead of TYPE_STRING. This would likely involve adding a TYPE_UUID to AttributeKey.Type and mapping it correctly to the ClickHouse UUID type. This ensures that queries against session_id do not involve a type cast, allowing the bloom filter index to be utilized effectively for performance.

Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent. Verify if this is a real issue. If it is, propose a fix; if not, explain why it's
not valid.

Location: snuba/protos/common.py#L61-L63

Potential issue: The `attribute_key_to_expression` function registers the `session_id`
column with `AttributeKey.Type.TYPE_STRING`. This causes queries to wrap the column in
`CAST(session_id, 'String')`. Since `session_id` is a native `UUID` column in ClickHouse
with a bloom filter index, this cast prevents the database from using the index to prune
granules. This defeats the purpose of the bloom filter, leading to inefficient queries
that scan more data than necessary and degrading query performance. Although tests pass,
this is likely due to the test environment, and the optimization will probably be
ineffective in production.

Also affects:

  • snuba/protos/common.py:337~341

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants