DBRaven
Pattern · indexing

Geospatial Index

established

Summary

Index geographic coordinates using space-partitioning data structures (R-tree, GeoHash, S2, PostGIS GiST) to enable efficient nearest-neighbor and radius queries : finding all records within N kilometers of a point without scanning every record.

Problem

Distance-based queries on latitude/longitude columns without a spatial index degrade to full table scans. At scale (millions of records), this produces query latencies of seconds to minutes, making real-time location features (nearby drivers, restaurant search, store locator) operationally impossible.

Description

Geospatial queries: "find all drivers within 2km of this passenger" or "find all restaurants within 5km of this point": are inefficient without a spatial index. A naive approach scans every record and computes the Haversine distance, producing O(n) performance. At millions of records, this takes seconds.

Spatial indexes partition the geographic space into regions, allowing the query to skip large portions of the dataset:

R-tree (PostgreSQL PostGIS GiST index): stores bounding boxes in a tree structure. Each leaf node contains the bounding box of actual geometric objects. Queries prune branches whose bounding boxes don't intersect the search area. O(log n) average case for radius queries. Standard for PostGIS; used by MySQL spatial indexes.

GeoHash: encodes latitude/longitude as a string where longer prefixes denote finer geographic cells. Nearby points share a common prefix. Enables range scan on an indexed GeoHash column: WHERE geohash LIKE 'u4pru%'. Simple to implement in any database with string B-tree indexes but has cell boundary artifacts (nearby points on different cell boundaries don't share a prefix).

S2 cells (Google's S2 library, used by Uber, Google Maps): projects the sphere onto a cube, then recursively subdivides each face. Cells at each level form a covering for any region. Used in DynamoDB-based geospatial systems (partition by S2 cell at an appropriate level) and H3 (Uber's hexagonal hierarchical spatial index).

H3 (Uber): hexagonal grid system where each hexagon has a unique 64-bit index at 15 resolution levels. Efficient for radius queries, aggregation by geographic region, and neighborhood traversal. Available as a library for Python, JavaScript, Go.

For ride-sharing and delivery platforms (Uber, Lyft, DoorDash, Grab), driver location updates arrive thousands of times per second and must be queryable by radius in under 10ms. Redis with the GEOADD / GEOSEARCH commands provides in-memory spatial indexing backed by a sorted set of GeoHash-encoded scores.

PostgreSQL PostGIS: add and populate a geometry column, index it with GiST, then query with ST_DWithin:

SELECT AddGeometryColumn('locations', 'geom', 4326, 'POINT', 2);

UPDATE locations SET geom = ST_SetSRID(ST_MakePoint(longitude, latitude), 4326);

CREATE INDEX locations_geom_idx ON locations USING GIST(geom);

SELECT * FROM locations WHERE ST_DWithin(

geom::geography, ST_MakePoint(-122.4, 37.7)::geography, 1000);

Redis GEOSEARCH: GEOADD drivers:locations 37.7749 -122.4194 "driver:42", then GEOSEARCH drivers:locations FROMLONLAT -122.4194 37.7749 BYRADIUS 2 km ASC COUNT 10.

H3 for Uber-style location indexing computes a cell index and stores it as a shard key or Redis key prefix: h3.latlng_to_cell(lat, lng, resolution=9) yields roughly 174m hexagons at resolution 9.

Tradeoffs

Query complexity
+0.8

Radius and nearest-neighbor queries run in O(log n) to O(k) time, where k is the result set size

Real-time location features
+0.7

Enables real-time location features at scale (nearby drivers, restaurant discovery)

Geometry support
+0.4

PostGIS GiST indexes support complex polygon and geometry operations in addition to point queries

Index maintenance cost
-0.3

Spatial indexes are larger and slower to update than B-tree indexes on scalar columns

Boundary artifacts
-0.2

GeoHash boundary artifacts require querying adjacent cells to avoid missing nearby points on cell boundaries

Operational dependencies
-0.3

PostGIS and S2/H3 libraries add dependencies and operational expertise requirements

When to use

Application requires proximity queries (nearest N records, radius search)

Without a spatial index, proximity queries require scanning all records and computing distance

Location data is updated frequently and read at high frequency

Driver location tracking (Uber, DoorDash) requires both fast writes and fast reads

Geographic aggregation is needed (count records per region, heatmaps)

Spatial indexes enable efficient range-based aggregation by geographic region

When not to use

Geospatial queries are only needed for static reference data with small datasets (<10,000 records)

Full scan is fast enough at small scale; a spatial index adds complexity for no measurable benefit

Queries are bounding box lookups only, not radius queries

A simple composite B-tree index on (lat_rounded, lng_rounded) may suffice for grid-based lookups

Operational Requirements

recommended

Batch location index updates for moving entities

Update drivers and couriers in batches rather than one-by-one.

mandatory

Expire stale location data

A driver who disconnected 30 minutes ago should not appear in radius queries.

mandatory

Use TTL on Redis GEOSEARCH sorted set members

Auto-expires stale locations without a separate cleanup job.

mandatory

Always query neighboring GeoHash cells

Avoids missed results at cell boundaries.

Characteristics

Scales on
Implementation complexitymedium
Operational complexitymedium

Relationships

Complements

index tableconsistent hashingcache aside

Basis

PostGIS R-tree GiST indexes are documented in PostgreSQL documentation; Redis GEOSEARCH is documented in Redis commands; H3 and S2 are documented in Uber and Google open-source libraries; production patterns are discussed in Uber and Google engineering blogs

Related Architecture Knowledge

Outbound: this entity affects

ComplementsPattern
cache aside
Grounded

Geospatial radius query results for static reference points (store locations, service areas) can be cached since the underlying dataset changes infrequently relative to query frequency.

Full relationship →
ComplementsPattern
consistent hashing
Grounded

Geospatial indexes identify which records are near a point; consistent hashing on a geohash or S2 cell key routes those records to the correct shard, combining location-aware partitioning with efficient proximity lookup.

Full relationship →

Used In Architecture Scenarios