P8 Sessionize events · P9 Consecutive streaks
FreeLesson 61 of 78
P8Sessionize eventsDEDAHARD
Sounds like: "split clickstream into sessions", "a session ends after 30 minutes idle", "average session length"
Worked question: Group each user's events into sessions, where a gap of more than 30 minutes starts a new session.
Approach: 1. group by user 2. sort by time 3. new session when the gap exceeds 30 minutes
import json
from collections import defaultdict
from datetime import datetime, timedelta
GAP = timedelta(minutes=30)
by_user = defaultdict(list)
for line in open("events.jsonl"):
e = json.loads(line)
ts = datetime.fromisoformat(e["ts"])
by_user[e["user_id"]].append((ts, e["event"]))
for user, events in sorted(by_user.items()):
events.sort() # never trust input order
sessions, prev = [], None
for ts, ev in events:
if prev is None or ts - prev > GAP:
sessions.append([]) # start a new session
sessions[-1].append(ev)
prev = ts
print(user, sessions)Output
1 [['view', 'cart', 'checkout', 'purchase'], ['view']] 2 [['view', 'view'], ['cart']] 3 [['view', 'cart', 'checkout']] 4 [['view']]
P9Consecutive streaksDEDAMEDIUM
Sounds like: "longest login streak", "most consecutive days with sales", "longest consecutive sequence"
Worked question: Each user's longest run of consecutive login days.
Approach: 1. put dates in a set 2. only count from a day whose previous day is missing 3. walk forward while days exist
import csv
from collections import defaultdict
from datetime import date, timedelta
ONE = timedelta(days=1)
days = defaultdict(set)
for r in csv.DictReader(open("logins.csv")):
days[int(r["user_id"])].add(date.fromisoformat(r["login_date"]))
for user, ds in sorted(days.items()):
best = (0, None)
for d in ds:
if d - ONE not in ds: # d starts a streak
n = 1
while d + n * ONE in ds:
n += 1
best = max(best, (n, d))
print(user, "longest:", best[0], "days from", best[1])Output
1 longest: 3 days from 2025-04-01 2 longest: 2 days from 2025-04-01 3 longest: 4 days from 2025-04-03
Follow-ups interviewers ask
| They ask | You answer |
|---|---|
| "Average session length." | Keep first and last timestamp per session and average the differences. A one-event session has length 0: say whether to exclude it. |
| "Streaks with gaps of one day allowed." | Change the test: a day starts a streak only if neither of the two days before it exists. |
| "Events arrive out of order in a stream." | Sort within a time window before sessionizing, and accept late events up to a cut-off (a watermark in Spark). |
Practice before you move on
- Solve the two practice questions for P8 and P9 in Coding Practice, under Python.
- Change the session gap in P8 to 10 minutes and count the sessions again.
In Coding Practice
Solve this pattern on fresh data, under Python. Hidden tests grade it.