Problem
Aggregates such as counts per minute need a boundary, but streams never end and events arrive late or out of order. Using arrival time gives wrong answers when delays occur.
Also known as: windowed aggregation, tumbling and sliding windows
Group an unbounded event stream into finite windows so aggregations can be computed and emitted.
Aggregates such as counts per minute need a boundary, but streams never end and events arrive late or out of order. Using arrival time gives wrong answers when delays occur.
Windowing slices time into pieces that can be aggregated. The key discipline is using event time, the moment something happened, not the time it reached the processor.
A watermark is the engine belief that no more events older than a given time will arrive.
Pick the window type to match the question. Tumbling windows fit per-minute counts, sliding windows fit moving averages that update more often than the window length, and session windows fit user activity separated by quiet gaps. Each assigns events differently and carries different state costs, since sliding windows hold each event in several windows.
Each event is mapped to one or more windows by its timestamp. When the watermark passes a window end plus allowed lateness, the aggregate is emitted and state released.
window = floor(event.ts / 60s) * 60s # tumbling, 1 min
counts[(key, window)] += 1
when watermark >= window + 60s + lateness:
emit(key, window, counts.pop((key, window)))
Handling lateness is a product decision as much as a technical one. A longer allowed lateness improves accuracy but delays final results and holds more state. Many systems emit an early provisional result and then updates as late data arrives. Whatever you choose, count dropped late events as a metric so you know the real cost of your watermark setting.
High - stream processing cluster
High - state, checkpoints, lag
High - time semantics
Watermark stalls when one partition goes idle
Late events silently dropped
Window state grows unbounded with long sessions