Implement Event Filtering and Queue Routing
Company: Amazon
Role: Software Engineer
Category: Coding & Algorithms
Difficulty: medium
Interview Round: Technical Screen
Quick Answer: This question evaluates parsing and evaluation of domain-specific filter expressions, JSON traversal and type-aware comparisons, boolean logic handling, and in-memory routing with subscription-order preservation.
Constraints
- 0 <= len(operations) <= 200
- queueName values are unique across subscribe operations
- Each filterExpression is syntactically valid and has length at most 500
- Event JSON strings are valid JSON objects with nested objects, strings, numbers, booleans, and null values
- Dot paths contain object field names separated by '.', and array indexing is not required
- Ordering operators >, >=, <, <= only match when both compared values are numbers; booleans are not considered numbers
Examples
Input: ([('subscribe', 'usOrders', 'type == "order" AND region == "us"'), ('subscribe', 'largeOrders', 'type == "order" AND amount >= 100'), ('subscribe', 'errors', 'detail.level == "error" OR type == "failure"'), ('route', '{"type":"order","region":"us","amount":125}')],)
Expected Output: [['usOrders', 'largeOrders']]
Explanation: The event is a US order with amount 125, so it matches the first two subscriptions. It has no detail.level and type is not failure, so errors does not match.
Input: ([],)
Expected Output: []
Explanation: There are no operations, so there are no route results.
Input: ([('subscribe', 'missingRegion', 'region == null'), ('subscribe', 'nonNullRegion', 'region != null'), ('route', '{"type":"order"}')],)
Expected Output: [['missingRegion']]
Explanation: The event has no region field, so region is treated as null. Therefore region == null matches, while region != null does not.
Input: ([('subscribe', 'urgentUs', '(type == "alert" OR detail.level == "error") AND region == "us"'), ('subscribe', 'activeUs', 'active == true AND region == "us"'), ('subscribe', 'notDebug', 'NOT detail.level == "debug"'), ('route', '{"type":"metric","detail":{"level":"debug"},"region":"us","active":true}'), ('route', '{"type":"metric","detail":{"level":"error"},"region":"us","active":false}')],)
Expected Output: [['activeUs'], ['urgentUs', 'notDebug']]
Explanation: The first event is active in the US but has debug level, so only activeUs matches. The second event has error level in the US and is not debug, so urgentUs and notDebug match.
Input: ([('subscribe', 'large', 'amount > 100'), ('subscribe', 'negative', 'amount < 0'), ('subscribe', 'stringAmount', 'amount == "125"'), ('subscribe', 'notHundred', 'amount != 100'), ('route', '{"amount":"125"}'), ('route', '{"amount":-5}'), ('route', '{"amount":125}')],)
Expected Output: [['stringAmount', 'notHundred'], ['negative', 'notHundred'], ['large', 'notHundred']]
Explanation: Ordering comparisons only apply to numeric JSON values. The string amount matches only the string equality and notHundred. The negative amount matches negative and notHundred. The numeric 125 matches large and notHundred.
Hints
- Parse each filter expression once at subscription time into an expression tree. A recursive descent parser works well for handling NOT, AND, OR precedence and parentheses.
- During routing, resolve each dot path against the parsed JSON object. If any path component is missing, return null for that field, then perform type-aware comparison.