Skip to main content

Making Valhalla Understand Monday Morning

· 6 min read
Evgen Bodunov
Evgen Bodunov
CEO @ Globus Software

At 08:12 on a Monday, a delivery driver leaves the depot on a route built on Sunday afternoon. The routing engine that built it does not know that the arterial out of the warehouse jams between 08:00 and 08:30. The driver knows, and so does anyone who lives nearby.

Most people assume predicted traffic already works in their routing engine. Valhalla supports it, but only if someone feeds it good data. Over the last several months at Globus, we have been doing that work.

This post covers what we shipped, what we threw away, and why a deliberately small layer turned out to matter more than a more ambitious one.

What we shipped​

Globus predicted traffic for Valhalla ships in two layers.

Layer 1 — Scalar coverage. A per-road day speed and night speed for the entire drivable graph — 41,231,017 directed edges — exported as Valhalla's free_flow / constrained_flow CSV.

Layer 2 — Time-of-week canary. A weekly speed profile encoded in Valhalla's 200-coefficient DCT format. Selective: 86,466 corridors across Germany, the Netherlands, Switzerland, Ukraine, and the US — only the ones where the GPS evidence is strong enough to carry a weekly curve.

The split is deliberate: coverage everywhere, and temporal detail only where the data supports it.

Why not weekly profiles on every road?​

Because the data cannot support them.

Our source is matched GPS: over a billion observations in total, but the median road sees only a handful. Valhalla's DCT grid is 7 days × 24 hours × 12 five-minute buckets = 2,016 slots per week. Learning 2,016 numbers from five samples produces a curve that looks detailed and behaves like noise, and the dispatcher gets reroutes around congestion that does not exist.

Confusing detail with accuracy is the most common failure in predicted traffic. So the first layer we shipped was deliberately plain: day and night speed per road, with shrinkage toward priors where local data is thin, and two reliability features (count-decayed dispersion and a count-decayed coverage cap) that let well-observed roads trust their own data and sparse roads lean on cohort behavior.

It covers the whole graph and does not invent precision it does not have.

What we tried and threw away​

With Layer 1 stable, the next step was temporal shape: discover rush-hour windows from the data, fit per-road interval models, and ship a richer product.

We tried three approaches.

A fixed ladder of 1-hour and 3-hour intervals was robust and interpretable, but real congestion does not always start on the hour. An adaptive tree that searched for data-driven splits looked great on in-sample MAE, then collapsed under date-holdout validation: the trees were memorizing, not predicting. A contrast interval model designed for fast-slow-fast patterns won on its own selected roads under production scoring, then lost on held-out reconstruction.

All three were plausible, and all three failed the test that matters: predicting next Monday, not last month. We shelved them.

The work still paid off. It left us with an evaluation harness built to distrust its own results: date-holdout splits, selected-subset reconstruction, shuffled-timestamp negative controls, and abstain-or-predict scoring. Every later candidate had to pass it before it went near a tile.

What worked: cohort templates, anchored per road​

The model we shipped is simpler than the ones we discarded.

Instead of teaching every road its own weekly shape, we grouped similar roads into cohorts — country + road class + density zone — and learned a shared normalized weekly template per cohort. Each road anchors that template to its own scalar baseline, scaled by a strength term that grows with local data:

profile = scalar baseline × cohort weekly shape × strength
strength = support / (support + 20)

The cohort provides the rhythm and the road provides the level. Sparse roads abstain and fall back to the scalar layer automatically.

We evaluated after Valhalla's lossy 200-coefficient DCT compression, not before, because only the compressed profile reaches the router.

The numbers that mattered:

  • 63.4% selected win rate vs the scalar layer on chosen roads
  • +15.0 percentage points above a shuffled-timestamp control, so the signal is not noise
  • 88.9% of high-support roads beat scalar even after DCT compression, so the format is sufficient

The mean per-road improvement is small in absolute terms, as expected. The scalar layer already captures the average day and night; DCT adds the weekly shape on top, and only where it helps.

The real test: routes, not metrics​

A model that wins offline can still make routing worse. Before publishing the tiles, we ran 132 routes across DCT-heavy and risk-focused groups — motorway corridors, service roads, full-week-ready edges, known high-error edges — at five times of week: Monday 08:00, Monday 12:00, Monday 17:00, Friday 17:00, Sunday 03:00.

  • 132 / 132 routes succeeded
  • 0 catastrophic ETA jumps
  • 0 trafficview profile artifacts
  • 94 / 100 Monday-08:00 routes through DCT corridors arrived slower with DCT than without

The last number is the one we were looking for. The scalar layer already knew the average daytime speed; DCT added the morning peak. Off-peak deltas stayed near zero, which is also what we wanted: a time-of-week layer should stay quiet when the time of week does not matter.

What this means if you ship routes​

ETAs improve on the roads where they matter most, without the operational risks that usually come with traffic layers:

  • Every drivable edge still has a predicted speed, so coverage does not regress.
  • The DCT tier is a canary, not an irreversible global rollout. Rollback is one tile-set switch.
  • Behavior moves in the expected direction. Rush-hour routes through covered corridors get slower; quiet Sunday routes barely change.

For fleet routing, the Monday 08:00 difference appears where you would expect it: motorway approaches into dense cities, urban arterials during local peaks, Friday afternoons in Western Europe. At 03:00 on Sunday almost nothing changes, which is correct.

No integration work is needed. The layer ships inside our regular map and navigation data updates: Globus SDK customers get it with the next data refresh, with no API change and no new tiles to wire in. Pricing is unchanged: online routing is paid, and offline navigation is free once the data is downloaded.

What's next​

We have been working through the same sequence for a while:

  1. default_speeds.json — per-country, per-road-class priors baked into the tiles, refined over the years from our own GPS data.
  2. Scalar predicted traffic — free_flow and constrained_flow per road. The current foundation.
  3. Selective DCT profiles — what landed this release, on 86,466 corridors.
  4. Wider DCT coverage — as the GPS evidence grows on more cohorts and countries.
  5. Live traffic — a real-time overlay on top of all of the above, as a later step.

Each step has to prove itself before the next one ships. The DCT canary is narrow on purpose, and we will widen it as the data allows.

To try the routing stack, create an API key. To evaluate predicted-traffic tiles or discuss a Valhalla deployment, write to [email protected].