learn-streaming-data-with-phoebe / Session 4 of 6
Learn Streaming Data with Phoebe · Session 4 of 6

Windows: asking a stream an hourly question

A stream never ends, so "total revenue" is not a question it can answer. "Revenue between 1pm and 2pm" is. Windows are how an infinite stream gets cut into finite questions - and tonight, switching them on the RIGHT way will make the dashboard's accuracy visibly worse before session 5 makes it better. That dip is the most honest number in this course.

🟠 Advanced You have the stream deduplicated from session 3 45 min
0-3 · Welcome 3-18 · Window shapes, and the two clocks 18-40 · Build-along: windows on, watch the dip 40-45 · Q&A
Part 0

Where the artifact stands

The order stream is live and deduplicated: 89.1% accurate, fresh to the second. The remaining error is all about TIME - late orders are being counted in the hour they arrived, not the hour they happened. Tonight fixes the bucketing. It does not yet fix the lateness.

🎫 Clear all three quiz questions to stamp your passport Live = presented in the 45 minutes Self-study = the full depth, after class

★ What you walk out with: the three window shapes and when each is the right question, the event-time versus processing-time distinction that decides whether your hourly chart tells the truth, and first-hand experience of the strict-window trap - the reason watermarks exist.

Part 1 · covers window shapes

Three ways to cut an endless stream 7 min live

The Flink documentation names the standard shapes, and every serious streaming system offers the same three. The shape you pick IS the question you are asking.

Tumbling fixed size, no overlap 1pm-2pm Hopping fixed size, slides, overlaps a 1h window, restarted every 15 min Session closes after a quiet gap gap gap Pick the shape by the question: hourly report, moving trend, or one customer visit.
🔍 Click to zoom - the three standard window shapes over the same stream of events.
Live The shape is the question 5 min ▶

The definitions, straight from the Flink docs. Tumbling windows have a fixed size and do not overlap - each event belongs to exactly one. That is "revenue per hour", tonight's dashboard question. Hopping windows (Flink calls them sliding) have a fixed size plus a slide interval, so they overlap - a one-hour window recomputed every 15 minutes is a smooth trend line, and each event lands in several windows. Session windows have no fixed size at all: one closes when no elements arrive for a set gap. That is "one customer's visit to the shop".

  • Hourly revenue report - tumbling 1h. One answer per hour, no double counting.
  • "Are sales accelerating right now?" - hopping 1h/15min. Smooth, overlapping, deliberately redundant.
  • "How long does a lunchtime customer browse?" - session with a 30 min gap.
Real world

Uptime pages compute error rates over hopping windows so an incident shows as a rising curve rather than a cliff at the hour boundary. Finance closes are tumbling by construction: a transaction belongs to exactly one month.

Self-study The fourth shape, and why it is a trap for beginners 3 min ▶

Flink also offers a global window: every event with the same key lands in one single window that never closes on its own. The docs are blunt that it is only useful with a custom trigger, because a window that never closes never emits an answer. It exists for building exotic logic by hand, not for reporting.

If you catch yourself reaching for a global window to compute "total revenue ever", the stream is telling you that question belongs to the warehouse, not the stream. Totals-over-all-time are batch questions wearing a streaming costume.

Part 2 · covers the two clocks

Event time versus processing time 8 min live

Windows need a clock, and there are two candidates. The Flink docs define them precisely: processing time is the system time of the machine executing the operation. Event time is the time each event occurred on its producing device. Everything session 5 fixes starts here.

One order, placed 12:55, arrives 14:10 (tablet was offline) Processing-time buckets 12:00 - 13:00 13:00 - 14:00 14:00 - 15:00 ✕ counted when it ARRIVED Event-time buckets 12:00 - 13:00 ✓ 13:00 - 14:00 14:00 - 15:00 counted when it HAPPENED Processing time is simple and non-deterministic: replay the stream tomorrow and the buckets move. Event time is deterministic: the same events always produce the same answer. The lunch rush belongs to the lunch hour, whichever hour the tablet reconnected.
🔍 Click to zoom - the same late order, two clocks, two different hourly charts.
Live Why anyone still uses processing time 4 min ▶

Because it is free. No timestamps to extract, no out-of-order events to reason about, no waiting: the machine's own clock decides everything, and results are emitted the instant a window's wall-clock boundary passes. The Flink docs name the price with unusual candor - processing time offers no determinism, because it depends on the speed at which records happen to arrive.

Event time buys back the truth: results are correct and consistent even when events arrive out of order. The cost is that the stream now has to ANSWER a question processing time never faces: how long do you wait for stragglers before declaring an hour finished? That question has a name - the watermark - and it is the whole of session 5.

Real world

Mobile analytics is the extreme case: a phone can go through a tunnel at 12:55 and sync at 6pm. Products that bucket by processing time report a phantom evening engagement spike that is really the lunchtime tunnel traffic arriving late, in a pile.

Self-study Determinism is what makes replay possible 3 min ▶

Event-time windows have a property that quietly powers session 5's replay lever and session 6's whole architecture: run the same log through them twice and you get byte-identical answers. Processing-time results can never be reproduced - the second run's arrival times are different by definition.

That means an event-time pipeline can be rebuilt from the log after a bug fix and converge on the truth, which is exactly Nathan Marz's recovery story for immutable data: fix the code, recompute from the master dataset. A processing-time pipeline cannot be recomputed, only apologized for.

Build-along

Switch the buckets, watch the dip ★ 22 min · everyone builds

Same simulator, one new lever. Tonight's window is tumbling 1h on event time, and it closes STRICTLY - the moment the hour ends, its answer is frozen. Watch what strictness costs.

Rebuild last session's state: Stream it ON, Idempotent consumer ON. Confirm the headline reads 89.1% - fresh, deduplicated, and still lying about WHEN money happened, because buckets follow arrival time.

Turn on Event-time windows and read both numbers honestly. The chart's shape snaps to the truth - solid bars now line up under the dashed outlines, the lunch rush is back in the lunch hour. And the headline accuracy went DOWN, 89.1% to 88.0%.

Find out why in the counters: 6 late events dropped. A strict window froze each hour at the top of the hour; stragglers that used to be counted somewhere (the wrong somewhere) are now counted nowhere. The dashboard shows $3,275 of a true $3,723.

Say the trade out loud, because it is real: arrival-time bucketing smears late money across wrong hours but keeps the total closer. Strict event-time bucketing makes every bar honest and silently discards the stragglers. Neither is acceptable - which is precisely the argument for a window that stays open a little longer. That lever is session 5.

The dip is the lesson. A metric that only ever goes up when you do the "right" thing is a metric you should not trust. Doing windows correctly EXPOSED a real loss that sloppy bucketing was hiding. The Flink docs state the default plainly: late elements are dropped once the watermark passes the end of the window. Session 5 is about choosing that boundary on purpose instead of accepting it by accident.

Homework

Before session 5 15 min

Check yourself

Three questions

1. You want a smooth "sales in the last hour" trend, refreshed every 15 minutes. Which window?

A one-hour window restarted every 15 minutes overlaps deliberately - each event counts in four windows, which is what makes the trend smooth. Tumbling 15 min would answer a different, choppier question.

2. Why did switching to event-time windows make the accuracy number worse?

Arrival-time bucketing at least counted stragglers, in the wrong hour. A window that closes at +0 drops them entirely: 6 events, $448 of real revenue, gone from the dashboard. That loss is why watermarks exist.

3. What does processing time cost you, per the Flink docs?

Processing time is the lowest-latency option precisely because it never waits. What it surrenders is determinism: results depend on arrival speed, so the same log replayed tomorrow lands in different buckets.

Answer all three to see your score.

Sources this session stands on

What was covered

✓Apache Flink docs · Windowstumbling, sliding/hopping, session and global window definitions; late elements dropped by default
✓Apache Flink docs · Timely Stream Processingprocessing time vs event time, determinism, out-of-order correctness
◐Kafka Streams 101 · Windowing + Time Conceptsthe same semantics in Kafka's own stream processor - API details not covered by design

Session 4 cheat sheet

TumblingFixed size, no overlap, one bucket per event. The hourly report.
HoppingFixed size plus a slide, overlapping on purpose. The smooth trend.
SessionNo fixed size - closes after a quiet gap. The customer visit.
Processing timeThe machine's clock. Free and fast, zero determinism - replays disagree.
Event timeThe event's own clock. Honest buckets, reproducible replays - but you must decide how long to wait.
The strict-window trapClose at +0 and every straggler is dropped: 89.1% fell to 88.0%. Watermarks (session 5) are the deliberate answer.