Tanay Pratap Singh/ live

01 · Live from Wikimedia · server sent events

Every Wikipedia edit, live, with each estimate checked against an exact count

This page reads every change to Wikipedia and its sister sites the moment it is published. It counts them twice, once with compact estimators that fit in a few kilobytes (sketches) and once exactly, so you can watch how far each estimate drifts and whether it stays inside its promised error.

Source stream.wikimedia.org/v2/stream/recentchange · Transport: server sent events, resumed with Last-Event-ID · License: the stream states none; linked pages carry their wiki's license (CC BY-SA 4.0 for Wikipedia text, CC0 for Wikidata)

Every edit to Wikipedia and its sister sites, as it happens

Each dot is one edit, sliding left as it ages. Bigger dots changed more text; rings are new pages.

Largest change in the last minute
waiting
Waiting for the first edit
How the river is drawn

Each dot is one change of type edit or new from the scope chosen below; category changes and log actions are counted in the cards. Rows are the 6 wikis with the most edits since the counters started, plus one row for the rest, and they slide into place as the ranking settles. Horizontal position is the edit's age on this computer's clock, so it includes the clock offset in the delay tile; the span grows from 4 to 60 seconds over the first minute. Position inside a row comes from a hash of the event id, so dots do not stack. The river keeps the latest 2,000 edits.

dot area ∝ 1 + 1.5 log10(1 + |bytes changed|)
waiting for the first event
Changes per second
0 / 5 s
opening the stream
Different editors
waiting
estimated in 4 KB
Made by people
waiting
the rest by bot accounts
New pages
waiting
pages created
Pages edited
waiting
counted exactly
Wikis with activity
waiting
counted exactly
Edit to screen delay
waiting
median / 95th percentile

How busy is it right now?

Changes per second over the last 5 minutes, people stacked under bots. Triangles mark bursts.

Waiting for the first complete second.

How this is measured

A burst is a second far above the recent norm. The norm is an exponentially weighted mean μ and standard deviation σ of earlier seconds, with a 60 second half life. A flagged second still updates the norm, and nothing is flagged in the first 30 seconds.

flag second t if x_t > μ + 4σ and x_t ≥ μ + 10

Seconds are binned by event time (meta.dt) and close 2 s after the newest event time passes them, so this computer's clock plays no part. Delivery arrives in clumps, and arrival time bins would read those clumps as bursts; the comparison below counts how often.

How many different people are editing?

Error of a 4 KB estimate (HyperLogLog) against an exact count, each second. Lines mark the typical error; the band is twice that.

Waiting for the first editor.

How this is measured

HyperLogLog with p = 12 keeps 4,096 one byte registers (4 KB). The top 12 bits of the MurmurHash3 of a user name pick a register, which keeps the largest rank seen: one plus the leading zeros in the other 20 bits.

E = α_m m² / Σ_j 2^(−M[j]), m = 4,096 if E ≤ 2.5 m and V > 0: E = m ln(m / V) typical error σ = 1.04 / √m = 1.625%

Below 2.5 m = 10,240 the linear counting branch (V = registers still zero) is in use, and its error there is a little smaller, close to 1 / √(2m) ≈ 1.1%. Successive points come from one sketch, so they are not independent trials.

Which pages are busiest?

The 15 most edited pages, from 200 counters (Space-Saving). Solid bar: guaranteed minimum. Gray: possible overcount. Tick: exact count.

Waiting for the first edit in this scope

Waiting for edits.

How this is measured

Space-Saving (Metwally, Agrawal and El Abbadi, 2005) keeps k = 200 counters for edits and page creations. A page it has not seen takes over the smallest counter and inherits that count as possible error.

count − error ≤ exact ≤ count smallest count ≤ N / k, so exact > N / k means tracked

Both guarantees are checked every second against an exact map of every page. For pages near N / k most of a counter is inherited error, so the order of the lower rows is unreliable.

Which wikis are busiest?

Changes per wiki from a fixed table of 4 by 1,024 counters (Count-Min), next to exact counts.

Waiting for the first event in this scope

Waiting for events.

How this is measured

Count-Min adds each change to one counter in each of 4 rows and reports the smallest of the 4. Wikis that share a counter inflate each other, so it can overcount and never undercounts. This is the standard update, so the textbook bound applies as stated.

exact ≤ estimate, P(estimate − exact > ε N) ≤ δ ε = e / 1,024 = 0.00265, δ = e^−4 = 0.0183

The proof assumes pairwise independent hashes, which seeded MurmurHash3 is not provably. With a few hundred wikis in 1,024 columns an overcount needs a collision in all 4 rows, so it is rare here.

How big are the edits?

Share of each group's edits by bytes added or removed, people and bots side by side.

Waiting for edits.

How this is measured

Byte change is new length minus old length, for edits only. Bins are orders of magnitude and each label is the edge nearest zero: +100 means +100 to +999 bytes. Shares are within each group, so each color sums to 100%.

What kind of change?

Changes by type since the counters started, people and bots side by side.

Waiting for events.

How this is measured

Types come from the stream. An edit changes a page's text and new creates a page. Categorize records a page entering or leaving a category, and log covers actions such as moves, deletions, uploads and new accounts.

The bot flag is the wiki's own: accounts with the bot right. Automated edits from accounts without it count as people.

Latest changes

The 25 newest changes, newest first. Editors are never shown.

Waiting for events

Waiting for events.

How this is measured

Each event's meta.id passes through a set of the 5,000 most recent ids, and repeats after a reconnect are dropped. Wikimedia's synthetic canary events are discarded. Times are event times (meta.dt) in this computer's time zone. Byte change is new length minus old length, blank when the event carries no length. User and User talk pages are named after an account, so their titles are hidden.

Method

This page keeps two sets of books on the same stream. One uses sketches, compact summaries that answer “how many” and “which are biggest” in a fixed few kilobytes at the price of a small, bounded error. The other keeps every count exactly, which works here only because the stream is small. Each card puts the two side by side, and the sections below give the details.

Transport and resume

The page opens one EventSource on Wikimedia's recentchange stream. Every message carries an SSE id: a JSON list of Kafka topic and partition positions (in the stream as observed, a millisecond timestamp for the active datacenter's topic). Wikimedia closes every connection after 15 minutes. The browser then reconnects on its own and sends the last id it saw as the Last-Event-ID header, so the stream resumes where it stopped. If the browser gives up (an HTTP error it will not retry), the page reconnects itself with since set 5 seconds before the newest event time, which can replay a few events.

Each event's meta.id passes through a set of the 5,000 most recent ids; repeats are dropped and counted in the tape footer. Wikimedia's synthetic canary events (meta.domain = canary) are discarded before anything is counted. Changing the scope resets every counter and sketch.

Edit river

The river draws events of type edit and new from the chosen scope; category changes and log actions appear in the cards. Rows are the 6 wikis with the most edits since the counters started, plus one row for the rest. A wiki takes a row, or passes the row above, only when its count exceeds that row's by 10% plus one, so rows settle without flapping, and they slide to new places. Horizontal position is age, this computer's clock minus meta.dt, so it includes the clock offset in the delay tile. The span grows from 4 to 60 seconds over the first minute. Vertical position inside a row comes from a hash of the event id, so dots do not stack. The river keeps the latest 2,000 edits.

dot area ∝ 1 + 1.5 log10(1 + |bytes changed|)

Hashing

All three sketches hash with MurmurHash3, x86 32 bit, over UTF-8 bytes. The implementation is checked in the test suite against the published test vectors and SMHasher's verification value. Count-Min uses a different seed for each row.

HyperLogLog

Distinct editors are counted by user name with p = 12, so m = 4,096 registers of one byte each. The top 12 bits of the hash choose a register, which keeps the largest rank it has seen; the rank is one plus the number of leading zeros in the remaining 20 bits.

j = h >>> (32 − p) register index: the top p bits ρ = clz(h << p) + 1 rank: at most 32 − p + 1 = 21 M[j] = max(M[j], ρ) E = α_m m² / Σ_j 2^(−M[j]), α_m = 0.7213 / (1 + 1.079 / m) if E ≤ 2.5 m and V > 0: E = m ln(m / V), V = registers still 0 if E > 2^32 / 30: E = −2^32 ln(1 − E / 2^32) relative standard error ≈ 1.04 / √m = 1.04 / 64 = 1.625%

Below 2.5 m = 10,240 the linear counting branch is in use, and its error there is a little smaller than the raw bound (close to 1 / √(2m) ≈ 1.1% for small counts). The chart follows one sketch over time, so neighbouring points are strongly correlated; a coverage test would need many independent sketches.

The exact set beside it stores only a 53 bit hash of each user name (two seeded MurmurHash3 values). The chance of any collision among 100,000 editors is about n² / 2^54 ≈ 6 × 10^−7, so it is exact in practice.

Count-Min

Events per wiki go into a table of 4 rows by 1,024 counters. Each event adds one to a counter in every row and the estimate is the minimum over rows. The page uses the standard update, so the textbook bound applies as stated; the conservative update tightens estimates but falls outside that proof.

f(x) ≤ f̂(x) = min_i C[i, h_i(x)] P( f̂(x) − f(x) > ε N ) ≤ δ ε = e / w = 0.00265, δ = e^(−d) = 0.0183

The proof assumes pairwise independent hash functions, which seeded MurmurHash3 is not provably. With a few hundred wikis in 1,024 columns, a key is inflated only when it collides in all four rows, so most estimates come out exact and the bound is far from tight here. The card puts the share of inflated keys expected under uniform hashing next to the share observed.

Space-Saving

Pages (edits and creations) are tracked with k = 200 counters, after Metwally, Agrawal and El Abbadi (2005).

hit: count[x] ← count[x] + 1 miss: evict the counter y with the smallest count c_min count[x] ← c_min + 1, error[x] ← c_min count[x] − error[x] ≤ f(x) ≤ count[x] c_min ≤ N / k, so f(x) > N / k implies x is tracked

Every second the page checks both guarantees against an exact map of every page seen and counts any failure. The guarantees are deterministic, so that count should stay at zero; it is on the page so that a bug would show. The ranking is weaker: for pages near N / k, most of a counter's count is error inherited from the page it evicted, so the order of the lower rows is unreliable. The card counts how many of the 15 rows belong in the exact top 15.

Bursts

μ, σ = exponentially weighted mean and standard deviation of per second totals, half life 60 s flag second t if x_t > μ + 4σ and x_t ≥ μ + 10

μ and σ are taken before second t is added, and flagged seconds still update the baseline. Nothing is flagged during the first 30 seconds. Seconds are binned by event time (meta.dt) because delivery comes in clumps, and a clump of delivery is no burst of editing; the card counts what the same rule flags on arrival time bins for comparison. A second is closed, and judged, once the newest event time seen is 2 seconds past it, so the judgement does not depend on this computer's clock. Events that arrive later still fill the chart, miss the detector, and are counted. The rate tile uses the same closed seconds, smoothed with a 10 second half life.

Delay, bot flag and privacy

The delay is arrival time on this computer minus meta.dt from Wikimedia, over the last 2,000 events. It includes the offset between the two clocks, which can be a second or more and can even make the delay negative. The bot flag is the wiki's own: accounts with the bot right. Automated edits from accounts without it count as people.

User names and IP addresses are never displayed. A name is hashed on arrival, into the HyperLogLog registers and the 53 bit exact set, and the string is not kept. The tape and the river show pages and leave out editors. Pages in the User and User talk namespaces (2 and 3) are named after an account or an IP address, so their titles are counted by hash and shown only as “User page (name hidden)”, without a link. Titles in other namespaces can still mention an account, for example a noticeboard subpage; those are shown as the wiki published them.

What the comparison shows

The exact counters are only affordable because this stream is small, tens of events a second as the rate tile shows. The exact set and maps grow with every new editor and page (the page resets itself if the page map reaches 500,000 keys), while the sketches stay at 4 KB, 4 × 1,024 counters and 200 counters. At a scale where exact counting does not fit in memory, the sketch is all there is; running both here shows what the sketch gives up in exchange.

Data: Wikimedia EventStreams, recentchange stream, published by the Wikimedia Foundation. Page titles link back to the wiki they came from. Nothing is stored between visits and nothing passes through a server of mine. All dashboards · Back to the portfolio