Lesson 21 of 53
Ride Dispatch: Spatial Indexing, Batch Matching, and Deep Dives
This lesson continues Chapter 9 and covers sections 4 to 6. It follows Ride Dispatch: Framing, Scale Math, and Architecture and continues in Ride Dispatch: Interview Calibration, Opinions, and Runbooks.
4. Spatial Indexing Engine, Uber H3 Hexagonal Grid & Production Schemas
The choice of spatial indexing determines the performance, accuracy, and operational complexity of the entire dispatch platform:
Figure 9.2: Spatial Indexing: Uber H3 Hexagons vs. Geohash vs. Quadtree
Why Hexagons Beat Squares & Geohash: The Adjacency Proof
In spatial geometry, there are only three regular polygons that can tessellate a flat two-dimensional plane: triangles, squares, and hexagons.
| GEOMETRY | NEIGHBOR COUNT | DISTANCE TO NEIGHBORS | DIAGONAL DISTORTION |
|---|---|---|---|
| 1. Triangles | 3 Edge, 9 Vertex | 3 Different Distances | Massive Distortion |
| 2. Squares | 4 Edge, 4 Corner | 1.0 (Edge) vs 1.414 (Corner) | 41.4% Inconsistency |
| 3. Hexagons | 6 Identical Edges | 1.0 to ALL 6 Centroids | 0.0% Distortion! |
THE SQUARE GRID DEFECT
In a square grid (such as Geohash or Google S2), a cell has two distinct types of neighbors: 4 orthogonal edge neighbors and 4 diagonal corner neighbors.
The distance from the center of a square to its edge neighbor is 1.0. The distance to its diagonal corner neighbor is sqrt(1² + 1²) = sqrt(2) ≈ 1.414.
This means proximity searches on square grids do not form circles; they form distorted rhombuses. Finding all drivers within a 1 km radius requires searching irregular bounding boxes that over-index corners and miss nearby drivers along edges.
Furthermore, Geohash has boundary discontinuities: two coordinates separated by 10 meters across the Prime Meridian or equator have completely different string prefixes (e.g., s0000 vs kpbpb), breaking prefix searches.
THE UBER H3 HEXAGONAL SOLUTION
In a hexagonal grid, every neighbor is an edge neighbor.
The distance from the centroid of a hexagon to the centroids of all 6 adjacent neighbors is 100% identical.
Expanding outward across k concentric rings (k-ring) perfectly approximates a true Euclidean circle on the Earth's surface!
k-ring Expansion Formula:
k=0: 1 cell (the target cell itself).
k=1: 1 + 6 = 7 cells.
k=2: 1 + 6 + 12 = 19 cells.
k=3: 1 + 6 + 12 + 18 = 37 cells.Finding all drivers within ~1 km of a rider requires querying exactly 19 contiguous cells (k=2), executed via 19 in-memory set lookups in Redis in under 1.2 milliseconds!
Production Relational Schemas & DDL (PostgreSQL)
While live geospatial positions live in Redis, all commercial contracts, driver profiles, trip state transitions, and billing events require strict ACID relational guarantees in PostgreSQL.
-- 1. Driver Fleet & Vehicle Master Table
CREATE TABLE drivers (
driver_id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
first_name VARCHAR(64) NOT NULL,
last_name VARCHAR(64) NOT NULL,
phone_e164 VARCHAR(20) NOT NULL UNIQUE,
current_status VARCHAR(32) NOT NULL DEFAULT 'OFFLINE',
-- 'OFFLINE', 'AVAILABLE', 'EN_ROUTE', 'ON_TRIP'
rating_score NUMERIC(3, 2) NOT NULL DEFAULT 5.00,
acceptance_rate NUMERIC(5, 2) NOT NULL DEFAULT 100.00,
cancellation_rate NUMERIC(5, 2) NOT NULL DEFAULT 0.00,
current_h3_res9 VARCHAR(16), -- Cached last known H3 cell
vehicle_tier VARCHAR(32) NOT NULL DEFAULT 'STANDARD',
-- 'STANDARD', 'COMFORT', 'XL', 'BLACK'
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
-- 2. Trips Master Table (Strict State Machine Ledger)
CREATE TABLE trips (
trip_id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
rider_id UUID NOT NULL,
driver_id UUID, -- Nullable until accepted
status VARCHAR(32) NOT NULL DEFAULT 'REQUESTED',
-- State transitions: REQUESTED -> MATCHING -> OFFERED -> ACCEPTED -> ARRIVED -> IN_PROGRESS -> COMPLETED
pickup_latitude DOUBLE PRECISION NOT NULL,
pickup_longitude DOUBLE PRECISION NOT NULL,
pickup_h3_res9 VARCHAR(16) NOT NULL,
dropoff_latitude DOUBLE PRECISION NOT NULL,
dropoff_longitude DOUBLE PRECISION NOT NULL,
dropoff_h3_res9 VARCHAR(16) NOT NULL,
base_fare_usd NUMERIC(8, 2) NOT NULL,
surge_multiplier NUMERIC(4, 2) NOT NULL DEFAULT 1.00,
final_fare_usd NUMERIC(8, 2),
estimated_pickup_eta_seconds INTEGER NOT NULL,
actual_pickup_timestamp TIMESTAMP WITH TIME ZONE,
dropoff_timestamp TIMESTAMP WITH TIME ZONE,
cancellation_reason VARCHAR(64),
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
-- 3. Surge Pricing Hexagonal Zone State (H3 Resolution 8)
CREATE TABLE surge_zones (
h3_res8_id VARCHAR(16) PRIMARY KEY,
metro_area_id VARCHAR(64) NOT NULL,
active_demand_count INTEGER NOT NULL DEFAULT 0,
active_supply_count INTEGER NOT NULL DEFAULT 0,
raw_surge_ratio NUMERIC(4, 2) NOT NULL DEFAULT 1.00,
smoothed_surge_multiplier NUMERIC(4, 2) NOT NULL DEFAULT 1.00,
last_updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
-- Production Partial Indexes for Ultra-Fast Lookups
CREATE INDEX idx_trips_active_rider ON trips (rider_id)
WHERE status IN ('REQUESTED', 'MATCHING', 'OFFED', 'ACCEPTED', 'ARRIVED', 'IN_PROGRESS');
CREATE INDEX idx_drivers_available_h3 ON drivers (current_h3_res9, vehicle_tier)
WHERE current_status = 'AVAILABLE';5. The Batch Dispatch Engine & Global Bipartite Matching Protocol
The core differentiator of an L6 Staff design is rejecting greedy matching in favor of Global Batch Bipartite Matching:
Figure 9.3: Global Batch Bipartite Matching (Hungarian Algorithm) vs. Greedy Dispatch
The Failure of Greedy Nearest-Driver Assignment
Consider two riders requesting rides 500ms apart in downtown Chicago:
- Rider 1 requests at Location A. Nearest is Driver 1 (ETA = 2 minutes). Driver 2 is 4 minutes away.
- A greedy system assigns Driver 1 to Rider 1 immediately.
- Rider 2 requests at Location B 500ms later. Location B is 100 meters away from where Driver 1 was! But Driver 1 was already taken.
- The only remaining driver for Rider 2 is Driver 3, located 16 minutes away!
- Total Fleet Wait Time: 2 mins + 16 mins = 18 minutes. Rider 2 cancels in frustration.
The Kuhn-Munkres (Hungarian) Optimization Protocol
By holding incoming requests in a 2-second aggregation buffer, the system transforms individual queries into a global weighted bipartite matching graph:
THE 2-SECOND BATCH DISPATCH PROTOCOL
1. Accumulation Phase (T = 0.0s to 2.0s):
• Collect all incoming ride requests in City Cluster: R = { r₁, r₂, ..., rₙ }
• Query Redis for available drivers in active & k-ring H3 cells:
D = { d₁, d₂, ..., dₘ }
2. Cost Matrix Construction:
• For every pair (rᵢ, dⱼ), evaluate the Global Cost Function C[i][j]:
C[i][j] = (w₁ * Driving_ETA) + (w₂ * (5.0 - Driver_Rating))
+ (w₃ * Cancellation_Risk) - (w₄ * Driver_Idle_Time)
3. Kuhn-Munkres (Hungarian) Algorithm Execution:
• Finds the matching M* that minimizes the global sum: Σ C[i][j]
• For Rider 1 & Rider 2:
Pairing (Rider 1 -> Driver 2 [4m]) + (Rider 2 -> Driver 1 [1m])
TOTAL SYSTEM WAIT TIME = 5 MINUTES (vs. 18 minutes under greedy!)
• Wait time slashed by 72%! Zero rider cancellations!
4. Atomic Lease Acquisition:
• Winner pairs acquire 15-second driver offer leases via Redis Redlock.
• Push notification dispatched to driver smartphone with 15s countdown.6. Deep Dives
Deep Dive 1: High-Frequency GPS Ingestion Pipeline (Kalman Filter & Road Snapping)
Raw smartphone GPS sensors are notoriously noisy. In urban canyons (e.g., Manhattan or downtown San Francisco), GPS signals bounce off high-rise glass buildings (multipath interference), causing reported positions to jump 50 meters across buildings onto adjacent parallel streets.
THE THREE-STAGE NORMALIZATION PIPELINE
- Edge Kalman Filtering: The driver mobile application runs a lightweight Extended Kalman Filter (EKF). It combines GPS coordinates with the smartphone's internal accelerometer and gyroscope sensors to filter out anomalous teleportation spikes and produce smooth velocity vectors.
- H3 Cell Resolution Indexing: As pings hit the API Gateway, workers compute the H3 Resolution 9 index. If the driver is stationary (speed < 1 km/h), updates are throttled to save cellular data and Redis IOPS.
- Map Road Snapping (Hidden Markov Model): Raw GPS coordinates rarely lie exactly on road centerlines. An asynchronous worker runs a Hidden Markov Model (HMM) against OpenStreetMap road geometry. The HMM determines the most probable sequence of actual road segments traversed by the vehicle based on heading, speed, and one-way road directionality, ensuring the vehicle icon animates realistically along physical roads rather than hovering through buildings.
Deep Dive 2: Dynamic Surge Pricing Engine (Supply/Demand & Spatial Laplacian Smoothing)
Surge pricing is fundamentally an economic balancing mechanism, not a revenue extraction tool. When a sudden rainstorm hits, demand surges 400% while supply drops (drivers pull over). Surge pricing accomplishes two goals:
- It rations scarce driver capacity to riders with the highest willingness to pay.
- It acts as an economic beacon, recruiting off-duty drivers to log in and incentivizing drivers in adjacent dry neighborhoods to drive into the high-demand zone.
THE MATH OF SURGE PRICING
For each H3 Resolution 8 cell c (~0.74 km²):
Demand(c) = Active Ride Requests + (0.3 * App Price Searches within last 5 mins)
Supply(c) = Available Drivers + (0.7 * Drivers dropping off within 3 mins)Raw Multiplier:
Raw_Surge(c) = 1.0 + alpha * max(0, (Demand(c) / Supply(c)) - 1.0)THE "CLIFF EDGE" PROBLEM & SPATIAL LAPLACIAN SMOOTHING
If Cell A has a 2.5x surge and adjacent Cell B has a 1.0x surge, riders walk 50 meters across the street to avoid the surge, and drivers refuse trips in Cell B to wait in Cell A. To eliminate artificial pricing cliffs, the system applies a Discrete Laplacian Smoothing Operator across all 6 hexagonal neighbors:
Smoothed_Surge(c) = (1 - lambda) * Raw_Surge(c) + (lambda / 6) * SUM(Raw_Surge(neighbor_k))With λ = 0.4, surge contours transition smoothly from 2.5x -> 2.0x -> 1.5x -> 1.0x across neighborhood boundaries.
The 5-Minute Quote Lock: When a rider views a surge price, the system generates a signed HMAC token freezing that price for 5 minutes. Even if surge spikes to 3.0x while the rider enters their payment details, their quote is honored, preventing checkout abandonment.
Deep Dive 3: Multi-Stop Vehicle Routing Problem (VRP) & Order Bundling for Food Delivery
In food delivery (DoorDash / Uber Eats), a courier can service multiple orders concurrently. However, naive order batching is dangerous: if Courier A picks up Food for Customer 1, then drives across town to pick up Food for Customer 2, Customer 1's hot pizza sits in the car for 25 minutes and arrives ice-cold.
THE BUNDLING FEASIBILITY CONSTRAINTS:
An order Order 2 can be bundled with an existing order Order 1 on Courier Courier C if and only if:
- Kitchen Proximity: Restaurant 1 and Restaurant 2 are located within 500 meters of each other (or are the exact same kitchen).
- Route Collinearity: The angle between Customer 1's dropoff and Customer 2's dropoff from the restaurants is less than 30 degrees (both customers live in the same general direction).
- Dropoff Detour SLA: The total delivery ETA for Customer 1 must not increase by more than 6 minutes compared to direct, unbundled delivery.
- Thermal Window: Total elapsed time from Restaurant 1 pickup to Customer 1 dropoff must not exceed 22 minutes.
By enforcing these constraints, platforms achieve a 1.45 order/trip bundling ratio, reducing fleet operating costs by 28% without degrading customer satisfaction scores.
Deep Dive 4: ETA Prediction ML Pipeline (Route ETA + Kitchen Prep Model)
In logistics, an ETA is a core contract of user trust. An ETA that is 10 minutes late loses a customer; an ETA that is 10 minutes early causes food to arrive before the customer returns home.
END-TO-END ETA PREDICTION
Total ETA = Driver_Travel_Time(To Pickup) + Pickup_Friction
+ Food_Prep_Delay (Food Only) + Travel_Time(To Dropoff)
+ Dropoff_FrictionTHE COMPONENTS:
Base Driving Travel Time: Evaluated using OSRM Contraction Hierarchies. Graph nodes represent road intersections; edges represent street segments weighted by speed limits and historical traffic profiles.
The Kitchen Preparation Model (The Biggest Failure Source): While road travel time is predictable to within ±2 minutes, restaurant kitchen prep time has a variance of ±15 minutes. We train a Gradient Boosted Tree (XGBoost) model on historical kitchen completions with features:
restaurant_id,item_count,item_complexity(e.g., sushi vs. pizza),current_active_orders_in_kitchen,day_of_week, andtime_of_day.Dynamic Dispatch Timing: If a pizza requires 25 minutes of prep, the dispatch engine delays dispatching a driver for 15 minutes, ensuring the courier arrives exactly as the pizza is boxed, eliminating idle driver wait times.
Pickup and Dropoff Friction Models: High-density urban addresses (e.g., 40-story office towers or complex apartment complexes) require 4 to 8 minutes of parking, elevator transit, and security check-in. The ML model learns location-specific friction offsets mapped to H3 Resolution 9 cells.
Deep Dive 5: Atomic Driver Dispatch Lock & Concurrency Control
In a high-throughput dispatch cluster, two matching threads running concurrently for adjacent city zones might simultaneously select the same Driver 42 as the optimal match for two different riders.
THE RACE CONDITION THREAT:
If both threads dispatch offers to Driver 42, Driver 42's phone rings twice, and whoever clicks first causes the second rider's trip to crash or orphan.
THE STAFF SOLUTION: REDIS REDLOCK WITH OPTIMISTIC LEASE HANDOFF
ATOMIC DRIVER RESERVATION LEASE
Thread 1 selects Driver 42 for Rider 101.
1. Acquire Distributed Redis Lock:
SET lock:driver:42 "rider_101" NX PX 15000
• NX: Only set if key does NOT exist.
• PX 15000: Auto-expire after 15,000 milliseconds (15s driver timeout).
2. If Lock Fails (Acquired by another thread):
• Driver 42 is already reserved. Thread 1 drops Driver 42 and falls back
to the second-best candidate in its bipartite cost matrix.
3. If Lock Succeeds:
• Update Driver Status in Redis: HSET driver:42 status "OFFERED"
• Remove Driver 42 from H3 availability sets: SREM geo:h3:<cell> 42
• Push Offer to Driver 42 via WebSocket.
4. Resolution Handlers:
• Driver Accepts: DB executes: UPDATE trips SET status='ACCEPTED' ...
Redis lock converted to persistent trip session.
• Driver Rejects / 15s Timeout: Driver 42 status restored to "AVAILABLE",
lock deleted, Rider 101 re-queued for next 2-second batch window.Deep Dive 6: Driver Rejection Cascades, Penalty Timers & Auto-Offline Circuit Breakers
A major failure mode in ride-sharing is the Rejection Cascade: A rider requests a pickup in an undesirable location (e.g., far from the city center). Driver 1 rejects the offer (15s). Driver 2 rejects (15s). Driver 3 rejects (15s). By the time Driver 4 receives the offer, 60 seconds have elapsed, the rider has cancelled, and 4 drivers wasted productive time viewing dead offers.
THE STAFF MITIGATION STRATEGY:
- Dynamic Offer Timers: Instead of a flat 15 seconds, scale offer timers based on candidate rank: Candidate 1 gets 10 seconds; Candidate 2 gets 7 seconds; Candidate 3 gets 5 seconds.
- Acceptance Rate Penalty Weighting: In the Hungarian cost matrix, drivers with low acceptance rates receive an artificial cost penalty (w₂ * (100 - Acceptance_Rate)), ensuring responsive drivers receive prime dispatch opportunities first.
- The Auto-Offline Circuit Breaker: If a driver consecutively ignores or rejects 3 consecutive dispatched offers, the system automatically transitions their status to
SUSPENDED_OFFLINEfor 2 minutes. This prevents inactive drivers (e.g., phones left on in cup holders) from poisoning the active dispatch candidate pool.
Deep Dive 7: Geospatial Sharding & Distributed City Partitioning
Can a global ride-sharing platform run on a single monolithic matching cluster? Never. Ride-sharing has a unique and beautiful distributed systems property: Geographic Locality.
THE SPATIAL INVARIANT:
A rider in London will never, under any circumstance, be matched to a driver in New York City or Paris. Transportation supply and demand are strictly bounded by metropolitan physical geography.
We partition the entire system into independent, self-contained Metro Cluster Shards (e.g., metro_nyc, metro_london, metro_tokyo). Each metro shard runs its own isolated Redis spatial cluster, Kafka ingestion topics, and 2-second batch dispatch engines.
The Inter-City Boundary Defense: For contiguous geographic corridors (e.g., Washington D.C. to Baltimore), clusters overlap by 1 concentric H3 Resolution 7 cell (~5 km buffer). Cross-cluster coordination uses two-phase locking only for drivers straddling the border.
Failure Isolation: A complete database crash or network partition in the London cluster has zero blast radius on operations in New York City.
Deep Dive 8: Supply Positioning & Idle Driver Heatmap Projections
The most efficient trip dispatch is one where the driver is already waiting at the rider's curb. Rather than waiting for demand to appear reactively, Staff-level platforms implement Predictive Supply Positioning:
- Demand Forecasting Model: A deep learning model (Spatial-Temporal Graph Convolutional Network - ST-GCN) forecasts ride demand per H3 Resolution 8 cell 30 minutes into the future based on historical patterns, flight arrival schedules, concert dismissals, and Doppler radar weather forecasts.
- Driver Guidance Heatmaps: Idle drivers looking for trips see dynamic visual heatmaps on their mobile apps indicating zones with high forecasted demand.
- Relocation Bounties: If a massive concert at Madison Square Garden is scheduled to dismiss in 20 minutes, the platform injects small financial bonuses ($5 to $10) for idle drivers who reposition into adjacent vacant cells before the surge occurs, preventing post-event ride shortages before the first rider even taps their screen.
Deep Dive 9: Dynamic Driver Dispatch Handoff & En-Route Re-Matching (Forward Dispatch)
The standard matching model assumes drivers are idle before they can be considered for a new ride. However, in dense metropolitan areas, the best driver for an incoming request is often already on a trip.
THE MECHANICS OF FORWARD DISPATCH:
Consider Driver A who is 2 minutes away from dropping off Passenger 1 at 5th Avenue and 42nd Street. Passenger 2 requests a ride at 5th Avenue and 44th Street (2 blocks away). If the system considers only idle drivers, Driver B (who is currently empty 8 minutes away) is assigned. Driver A completes Passenger 1's trip 2 minutes later and sits idle, while Passenger 2 waits 8 minutes for Driver B!
THE STAFF OPTIMIZATION PROTOCOL:
Virtual Supply Inclusion: Drivers whose active trip is within 3 minutes of dropoff are classified as
DROPPING_OFFand included in the candidate bipartite graph.Marginal ETA Calculation:
Text Marginal_ETA = Remaining_Dropoff_ETA_1 + Dwell_Buffer (60s) + Travel_ETA(Dropoff_1 -> Pickup_2)If Marginal_ETA < Best_Idle_Driver_ETA, Driver A is selected.
The Chained Trip Queue: The new trip is queued on Driver A's app as a "Next Trip".
Driver Deadhead Elimination: This forward-dispatching pipeline reduces driver deadhead idle miles by 42% and increases driver billable hours from 58% to 76% of their total shift time!
