accesspatterns.dev
← All models

geo

Store Locator

Finding what is nearby, using a geohash as a sort key.

Two dimensions do not fit in one sort key, so a geohash flattens them into one: nearby places share a leading prefix. A proximity search becomes a prefix read, which DynamoDB is very good at, with none of the machinery a spatial index would need.

The model

Place

A store, with its position encoded as a geohash.

pk
PLACE#<placeId>

Attributes: name (S), geohash (S), openUntil (S), GSI1PK (S), GSI1SK (S)

Access patterns

  • Query · GSI1Places in a cell

    Everything inside one geohash cell, which is everything roughly nearby.

  • GetItemRead one place

    A single store by id.

Design notes

A geohash turns two dimensions into onewhy

Latitude and longitude cannot both be a sort key. A geohash interleaves them into a single string where a shared prefix means physical proximity, so the ordering DynamoDB already gives you becomes a spatial ordering. Nothing here is a spatial index; it is a string index used carefully.

Prefix length is the radiuswhy

Each character narrows the cell, alternating between the two axes. At this latitude four characters is about 23 km by 20 km, six is roughly 700 m by 600 m, and eight is around 23 m by 19 m - street level, not pinpoint. Shortening the prefix widens the search, so the radius is chosen by how much of the hash you key on. The two cells in the table are central Leeds and central York, about 30 km apart, and they share only 'gc': two characters, a cell some 740 km across, which is most of western Europe.

The edge case is the whole difficultytrade-off

A place fifty metres away but across a cell boundary is not in your cell, and no amount of prefixing will find it. Real implementations query the surrounding cells too - eight neighbours plus the centre - and filter by true distance afterwards. That is the honest cost of this technique: cheap reads, and an application that has to know about cell geometry.

Cells are not evenly populatedtrade-off

A cell over a city centre holds thousands of places and a cell over moorland holds none, so keying the index by cell means the partitions are as uneven as the world is. Somewhere busy enough becomes a hot partition on read, and the fix is the same as anywhere else: a finer prefix, which is to say more partitions and a smaller radius.

Taught in the course

store-locator
Try an example

Everything inside one geohash cell, which is everything roughly nearby.

PK(pk)
GSI1PK
GSI1SK
geohash
name
openUntil
PLACE#p-101
GEO#gcwfS
gcwfhct3#p-101S
gcwfhct3S
BriggateS
18:00S
PLACE#p-102
GEO#gcwfS
gcwfhcqu#p-102S
gcwfhcquS
Kirkgate MarketS
17:30S
PLACE#p-103
GEO#gcwfS
gcwfhccw#p-103S
gcwfhccwS
The HeadrowS
20:00S
PLACE#p-104
GEO#gcwfS
gcwfh5xr#p-104S
gcwfh5xrS
Hyde ParkS
22:00S
PLACE#p-201
GEO#gcx4S
gcx4znwm#p-201S
gcx4znwmS
MicklegateS
19:00S
PLACE#p-202
GEO#gcx4S
gcx4zrhg#p-202S
gcx4zrhgS
ShamblesS
17:00S

Run an operation to see the raw engine response.

table store-locatorkeys PKitems 6

The in-browser engine is a preview build. Transactions, vector search, streams, tags and TTL are among the operations it doesn't implement yet.