skip to content

In a ride-hailing dispatch flow, how should candidate drivers found by a geo index be ranked using a separate ETA service?

level: middleimportance: should knowfreq 45%

answer

  1. cheap filter, expensive ranker
  2. rivers and one-way streets
  3. bounded candidate count K
  4. one batched call, tight timeout
  5. degrade to a distance estimate

basics

~20 s

Use the geo index only to shortlist a bounded set of nearby available drivers, then ask the ETA service for their road travel times in one batched call and rank by ETA, falling back to a distance estimate if it is slow.

solid answer

~40 s

Dispatch runs in two stages. First, the **geo index** returns a bounded shortlist, say the 20-50 nearest available drivers by straight-line distance, filtered by status and vehicle type. Straight-line distance is cheap but misleading: a river, a highway or a one-way street can make a close driver far away by road. Second, the dispatcher sends the shortlist to the **ETA service** in one batched request and ranks candidates by predicted pickup time. The ETA service is an external dependency, so the call gets a **tight timeout**, and on failure the dispatcher falls back to a distance-based estimate instead of stopping. Short-lived caching of ETAs for nearby origin-destination pairs cuts the load further. Bounding the shortlist keeps cost predictable: 1,000 requests per second x 30 candidates is already 30,000 ETA computations per second.

go deeper

for a junior

Recall that the nearest driver on a map is not always the quickest to arrive, because roads and traffic decide travel time.

for a middle

Explain the two-stage flow: a bounded geo shortlist, then a batched ETA call, and state how K drives ETA load.

for a senior

Show how you protect dispatch from a slow dependency with timeouts, circuit breaking, caching and a distance-based fallback, and how you tag degraded matches.

for a principal

Discuss where pure ETA ranking stops being enough, and how you would measure whether extra scoring terms improve pickup time and completion.

## Two stages: shortlist, then rank In a **ride-hailing dispatch flow**, finding the "best" driver is split into two stages with very different costs: 1. **Candidate generation** - the in-memory **geo index** returns drivers near the pickup point. This is fast because it compares coordinates only. 2. **Ranking** - a separate **ETA service** predicts how long each candidate needs to drive to the pickup. This is slower because it reasons about the road network and traffic. How the ETA service computes its answers (routing algorithms, traffic models) is out of scope here. What matters is how dispatch **uses it as a dependency**. ## Why straight-line distance is not enough **Straight-line distance** (the great-circle distance between two coordinates) ignores everything between them: - **Barriers** - a driver 400 m away across a river may need a 6 km detour to the nearest bridge, while a driver 1.5 km away on the same bank arrives sooner. - **Road direction** - on a divided highway or a one-way street, a driver who just passed the pickup must loop around. - **Heading** - a driver moving away from the pickup is effectively farther than the distance suggests. - **Traffic** - two equal distances can differ by many minutes at rush hour. Riders feel **pickup time**, not distance, so ranking should use ETA. ## Building the shortlist The geo index query should return a **bounded** set: - nearest **K** available drivers (K around 20-50 is a common illustrative range), or all drivers within a radius capped at K; - filtered by **status** (available, not already holding an offer) and by **product** (vehicle size, accessibility); - widened in steps if too few drivers are found, rather than starting with a huge radius. The bound matters for cost. Assuming 1,000 ride requests per second and K = 30, the ETA service must produce 30,000 ETAs per second. Doubling K doubles that load, usually for a small gain, because the best driver by road is almost always among the nearest few dozen by distance. That is a practical observation, not a guarantee: a large barrier can push the true best driver outside the shortlist. ## Calling the ETA service well | Concern | Technique | |---|---| | Many candidates per request | One **batched** call: many origins, one destination | | Slow responses | A **timeout** well inside the dispatch latency budget | | Outages | A **circuit breaker** that stops calling a failing service for a while | | Repeated similar queries | A short-lived **cache** keyed by coarse origin cell, destination cell and time bucket | | Degraded mode | **Fallback** estimate: distance x a road factor / typical speed | The fallback is what keeps dispatch alive. A rough estimate from distance is worse than a real ETA but far better than refusing to match anyone. The ranking should record which mode was used so quality dashboards can separate degraded matches. ## Putting it together ```pseudocode function rankCandidates(pickup, productType): candidates = geoIndex.nearestAvailable(pickup, productType, limit = 30) if candidates is empty: return widenSearchOrQueue(pickup) etas = etaService.batch(origins = positions(candidates), destination = pickup, timeout = 150 ms) if etas failed or timed out: etas = [distance(c, pickup) * roadFactor / typicalSpeed for c in candidates] markDegraded() return candidates sorted by etas ascending ``` The timeout and road factor are illustrative. The output is an ordered list; the dispatcher then offers the ride to the top candidate and handles concurrency separately. ## Beyond pure ETA Ranking is often a **score**, not ETA alone: - the driver's recent acceptance behaviour (an offer likely to be declined wastes seconds); - how long the driver has been idle, for fairness; - the drop-off area, when it matters for balancing supply. ETA usually stays the dominant term because it is what the rider experiences. Adding terms should be measured against pickup time and completion rate, not assumed to help. ## Common mistakes - Calling the ETA service once per candidate instead of in one batch, multiplying round trips. - Letting the ETA call have no timeout, so a slow dependency becomes a dispatch outage. - Ranking by distance permanently because ETA felt expensive, and then wondering why pickups near rivers and highways are slow. - Growing K to fix rare misses, which raises ETA load on every request.

  • The shortlist is 30 nearest drivers by distance. Can the best driver by road still be missed?
    Yes. Behind a large barrier, such as a river with few bridges, every nearby driver may be slow while a farther one on the right side is fastest. Mitigations include widening the search when the best ETA found is much worse than the straight-line distance suggests, or shaping the search area around known barriers. A larger fixed K costs ETA capacity on every request to fix a rare case.
  • Why cache ETAs by coarse cell and time bucket instead of exact coordinates?
    Exact coordinates almost never repeat, so the cache would never hit. Rounding origins and destinations to small cells and time to a bucket of a minute or so makes nearby requests share an entry, and travel time between two small cells changes little within that window. The trade-off is a small accuracy loss, bounded by the cell size.

saying these in an interview costs you the question

  • The straight-line nearest driver always has the shortest pickup time.
  • Every driver in the city should be sent to the ETA service for each request.
  • If the ETA service is down, dispatch should stop until it recovers.
  • ETA calls should be made one candidate at a time for accuracy.
  • Taking the nearest few dozen drivers guarantees the best one is included.