Skip to content

feat(data-explore): Add support in EAP to filter Array by elements#7898

Merged
manessaraj merged 8 commits intomasterfrom
EXP-912_add_support_in_eap_to_search_array_includes
Apr 27, 2026
Merged

feat(data-explore): Add support in EAP to filter Array by elements#7898
manessaraj merged 8 commits intomasterfrom
EXP-912_add_support_in_eap_to_search_array_includes

Conversation

@manessaraj
Copy link
Copy Markdown
Contributor

@manessaraj manessaraj commented Apr 24, 2026

Current implementation of arrays in TraceItemTable endpoint transforms arrays as array of strings, and then only allows LIKE/NOT_LIKE filter on them.

With this change, arrays will preserve their original type, and client can filter EAP items by element of an array attribute.
To preserve the type, array is converted to JSON string, (clickhouse-driver doesn't support Array(JSON) type, as discussed in this PR), and post processing of results recovers the original array by decoding JSON string.

To filter, predicate maps arrays to corresponding type and use array exists with element filter.

Example Clickhouse query is:


SELECT (
    cast(lower(leftPad(hex(item_id), if(
        greater(length(hex(item_id)), 16), 32, 16), '0')), 'String'
    ) AS `sentry.item_id_TYPE_STRING`
), (toJSONString(attributes_array.`tags`::Array(
    JSON)) AS tags_TYPE_ARRAY
)
FROM eap_items_1_local
WHERE in(
    project_id, [1, 2, 3]
)
AND equals(organization_id, 1)
AND less(
    timestamp, toDateTime('2026-04-24 14:00:00')
)
AND greaterOrEquals(timestamp, toDateTime('2026-04-24 08:00:00'))
AND arrayExists(x -> equals(lower(x), lower('error')), (arrayMap(x -> coalesce(
    x.`String`::Nullable(String), toString(x.`Int`::Nullable(Int64)), toString(x.`Double`::Nullable(Float64)), x.`Bool`::Nullable(String)), attributes_array.`tags`::Array(
        JSON)) AS tags_TYPE_ARRAY__array_members
    )
)
AND lessOrEquals(sampling_factor, 1)
AND greater(sampling_factor, 0)
AND equals(item_type, 1)
LIMIT 10001 OFFSET 0

@manessaraj manessaraj requested review from a team as code owners April 24, 2026 15:19
@linear-code
Copy link
Copy Markdown

linear-code Bot commented Apr 24, 2026

Comment thread snuba/web/rpc/common/common.py Outdated
Comment thread snuba/web/rpc/common/common.py
Comment thread snuba/protos/common.py
Allow searching EAP Items by arrays where a given value is included within array (as an item, membership test)
Test to check types of array columns
Attempt to return the column as it is

SELECT (
    cast(lower(leftPad(hex(item_id), if(
        greater(length(hex(item_id)), 16), 32, 16), '0')), 'String'
    ) AS
), (attributes_array.::Array(
    JSON) AS frame_linenos_TYPE_ARRAY
)
FROM eap_items_1_local

Attempt(Works) return the columns as it is
Fix the filter path.. and update the tests..
Update the comments in code
Remove query printing
Remove query printing
@manessaraj manessaraj force-pushed the EXP-912_add_support_in_eap_to_search_array_includes branch from 66bc9b5 to ee6a796 Compare April 24, 2026 20:13
return field, existence
elif aggregation.key.type == AttributeKey.Type.TYPE_ARRAY:
field = type_array_to_stored_array_json_path(aggregation.key)
return field, 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.

Array aggregation uses wrong existence check after field type change

Medium Severity

_resolve_field_and_existence correctly computes f.notEmpty(field) for TYPE_ARRAY, but aggregation_to_expression discards this field_exists and calls _array_aggregation_to_expression without it. Inside _array_aggregation_to_expression, get_field_existence_expression(field) is re-computed on the JsonPath object, which falls through to f.isNotNull(field) since JsonPath isn't a FunctionCall. Per the codebase comment, missing JSON array keys return empty arrays (not NULL), so isNotNull incorrectly treats missing attributes as present. This changes the aggregation result from NULL to 0 when no rows have the attribute.

Additional Locations (2)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit ee6a796. Configure here.

Copy link
Copy Markdown
Contributor

@onewland onewland left a comment

Choose a reason for hiding this comment

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

seems generally fine, I think, pending tests passing. Have we documented clearly somewhere what the right behavior is for null because I'm confused and not really following. Maybe literally a NULL.md somewhere in snuba/protos?

Comment on lines +321 to +334
match value_type:
case "val_str":
return literal(v.val_str)
case "val_int":
return f.toString(literal(v.val_int))
case "val_double":
return f.toString(literal(v.val_double))
case "val_float":
return f.toString(literal(v.val_float))
case "val_bool":
return literal(str(v.val_bool).lower())
case _:
raise BadSnubaRPCRequestException(
f"unsupported AttributeValue for array membership: {value_type}"
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.

Is there a repeat of this logic tree elsewhere that could be reused or put in a common place?

@manessaraj
Copy link
Copy Markdown
Contributor Author

manessaraj commented Apr 24, 2026

seems generally fine, I think, pending tests passing. Have we documented clearly somewhere what the right behavior is for null because I'm confused and not really following. Maybe literally a NULL.md somewhere in snuba/protos?

Good Idea. let me finalize this, I need to ask product about this.

@manessaraj
Copy link
Copy Markdown
Contributor Author

seems generally fine, I think, pending tests passing. Have we documented clearly somewhere what the right behavior is for null because I'm confused and not really following. Maybe literally a NULL.md somewhere in snuba/protos?

Good Idea. let me finalize this, I need to ask product about this.

  1. None/Null Values: Arrays with None/Null are silently dropped in EAP Items processor.
  2. If array is empty, you have empty values in the JSON.
  3. If array has null values, null values are skipped.

Comment thread snuba/web/rpc/common/common.py Outdated
Comment thread snuba/web/rpc/common/common.py Outdated
Copy link
Copy Markdown

@cursor cursor Bot left a comment

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 2 potential issues.

There are 3 total unresolved issues (including 1 from previous review).

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 13cd6ba. Configure here.

Comment thread snuba/web/rpc/common/common.py
Comment thread snuba/web/rpc/v1/resolvers/common/trace_item_table.py
@manessaraj manessaraj enabled auto-merge (squash) April 27, 2026 20:55
@manessaraj manessaraj merged commit 2d5b397 into master Apr 27, 2026
49 checks passed
@manessaraj manessaraj deleted the EXP-912_add_support_in_eap_to_search_array_includes branch April 27, 2026 21:23
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