Chapter 12 · Time Series and Geospatial Workloads

Geospatial GEOADD, GEOSEARCH, Distance, Radius/Box Queries, and Sorted-Set Foundations

Build an AtlasMart location index with correct longitude/latitude order, units, radius/box queries, sorted-set foundations, and explicit precision limits.

Intermediate170–210 minutesGeospatial indexing and queriesRedis Open Source 8.10.1Free/local-firstLast reviewed: September 6, 2026

Learning outcomes

AtlasMart must find couriers and pickup lockers near a customer without loading every coordinate into the application. Redis GEO provides a proximity index, but correctness depends on coordinate order, units, Earth-model limits, and understanding that the underlying key is a sorted set rather than a GIS database.

01

Store longitude/latitude/member triples with GEOADD and validate coordinate bounds.

02

Query radius and box neighborhoods with GEOSEARCH and make units explicit.

03

Use GEODIST/GEOPOS as evidence while understanding spherical-distance error bounds.

04

Explain the sorted-set foundation without treating internal scores as business distance.

05

Design tenant/business filters so proximity results cannot become a data-leak boundary.

Exact lab baseline

All Chapter 12 mandatory labs reuse the disposable Chapter 01 environment: Redis Open Source 8.10.1 from Docker Official Image redis:8.10.1, container atlasmart-redis-ch01, standalone topology, host publication 127.0.0.1:6379, TLS disabled only because traffic stays on loopback, default ACL user disabled, named users atlasmart-app and academy-admin, logical database 0, AOF with appendfsync everysec plus RDB snapshots, persistent /data, and no explicit maxmemory limit or eviction policy. Redis 8 integrates Time Series into Redis Open Source; geospatial commands are core Redis commands. Fixtures stay under atlasmart:ch12:*. Mandatory work is local and uses synthetic telemetry/coordinates only; no paid service, production endpoint, or real credential is required.

1. GEO mental model: current member location in a sorted-set-backed index

A Redis geospatial key maps each unique member name to one indexed coordinate. Adding the same member again updates its current location. This is ideal for “where is courier c42 now?” but it is not a trajectory history. Redis encodes position into a sorted-set score so it can search nearby score ranges efficiently.

Need Redis structure Why
Current courier position GEO sorted set One member can be updated in place and queried by proximity
Courier movement history Time Series or Stream History needs many timestamped events, not one current member coordinate
Warehouse metadata/search Hash/JSON + Search Address/category/status are not geographic distance alone
High-precision GIS geometry Dedicated GIS/spatial engine when required Redis GEO uses a spherical approximation and point locations

2. Coordinate order is longitude first, latitude second

GEOADD key longitude latitude member uses x,y order. This differs from the conversational “latitude, longitude” order many humans use. Valid longitudes are −180..180. Redis GEO latitude is limited to about ±85.05112878 degrees because of the underlying projection.

redis-cli · deterministic AtlasMart location fixtures
docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app GEOADD atlasmart:ch12:geo:atlasmart 49.8671 40.4093 hub-centraldocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app GEOADD atlasmart:ch12:geo:atlasmart 49.8495 40.3777 locker-westdocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app GEOADD atlasmart:ch12:geo:atlasmart 49.8920 40.4200 locker-eastdocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app GEOPOS atlasmart:ch12:geo:atlasmart hub-central locker-west locker-eastdocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app TYPE atlasmart:ch12:geo:atlasmartdocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app ZCARD atlasmart:ch12:geo:atlasmart

TYPE reports zset. GEOPOS returns longitude then latitude and may show small representation differences from the inserted decimals because Redis encodes coordinates for the geospatial index.

3. Wrong coordinate order can fail loudly—or succeed silently in the wrong place

redis-cli · two different coordinate failures
docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app GEOADD atlasmart:ch12:geo:atlasmart 49.8671 90 impossible-latitudedocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app GEOADD atlasmart:ch12:geo:atlasmart 40.4093 49.8671 wrong-orderdocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app GEOPOS atlasmart:ch12:geo:atlasmart wrong-orderdocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app GEOSEARCH atlasmart:ch12:geo:atlasmart FROMLONLAT 49.8671 40.4093 BYRADIUS 5 km WITHDIST ASCdocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app ZREM atlasmart:ch12:geo:atlasmart wrong-order

Latitude 90 is out of Redis GEO bounds and should error. The reversed Baku values are both individually valid, so Redis can accept them as a coordinate far from the intended site. The repair is application-side schema validation plus a known-center proximity test—not just numeric range validation.

4. Radius queries: center, shape, unit, evidence

GEOSEARCH separates how the center is chosen (FROMMEMBER or FROMLONLAT) from the search shape (BYRADIUS or BYBOX). The unit belongs in the query and is also the unit returned by WITHDIST.

redis-cli · radius search from an indexed member
docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app GEOSEARCH atlasmart:ch12:geo:atlasmart FROMMEMBER hub-central BYRADIUS 5 km WITHDIST WITHCOORD ASC COUNT 10docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app GEOSEARCH atlasmart:ch12:geo:atlasmart FROMLONLAT 49.8671 40.4093 BYRADIUS 3000 m WITHDIST ASC COUNT 10

Do not compare “5” from a kilometers query with “3000” from a meters query without converting units. COUNT bounds the number of returned candidates; it does not change the coordinate precision model.

5. Box queries answer a different neighborhood shape

redis-cli · rectangular pickup-service window
docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app GEOSEARCH atlasmart:ch12:geo:atlasmart FROMMEMBER hub-central BYBOX 10 6 km WITHDIST WITHCOORD ASC COUNT 20

A box can model operational service windows or map viewports more directly than a radius. Redis still returns point members; it does not evaluate polygon containment, roads, travel time, administrative boundaries, or obstacles.

6. GEODIST is useful evidence, not survey-grade geometry

redis-cli · compare explicit units
docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app GEODIST atlasmart:ch12:geo:atlasmart hub-central locker-west mdocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app GEODIST atlasmart:ch12:geo:atlasmart hub-central locker-west kmdocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app GEODIST atlasmart:ch12:geo:atlasmart hub-central locker-west mi

Redis calculates distance using a spherical Earth approximation (Haversine-style model in the documentation); worst-case error can be around 0.5%. That is generally acceptable for nearby-app discovery, but not necessarily for cadastral, navigation, surveying, or safety-critical distance decisions.

7. The sorted-set foundation is observable but internal scores are not your domain API

redis-cli · inspect the backing zset safely
docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app ZRANGE atlasmart:ch12:geo:atlasmart 0 -1 WITHSCORESdocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app GEOHASH atlasmart:ch12:geo:atlasmart hub-central locker-westdocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app GEOPOS atlasmart:ch12:geo:atlasmart hub-central locker-westdocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app MEMORY USAGE atlasmart:ch12:geo:atlasmart

The sorted-set score is an encoded spatial value. It is not “meters from origin” and should not become an application contract. Use GEO commands for geographic semantics and ordinary sorted-set commands only for compatible operations such as ZREM deletion.

8. Member uniqueness means GEO is latest-state, not location history

redis-cli · update one courier location
docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app GEOADD atlasmart:ch12:geo:atlasmart 49.8700 40.4100 courier-42docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app GEOPOS atlasmart:ch12:geo:atlasmart courier-42docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app GEOADD atlasmart:ch12:geo:atlasmart CH 49.8750 40.4150 courier-42docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app GEOPOS atlasmart:ch12:geo:atlasmart courier-42docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app ZCARD atlasmart:ch12:geo:atlasmart

The second GEOADD changes courier-42’s current coordinate; it does not append a second historical point. If AtlasMart needs a route trace, emit timestamped location events to Time Series or Streams and maintain GEO as a projection of the current position.

9. Security boundary: filter before proximity results cross the trust boundary

Member names inside one GEO key cannot receive independent Redis ACL patterns; ACL key patterns protect the key as a whole. A shared global courier GEO key can therefore become a tenant-leak surface. Prefer tenant/security-domain-specific keys when hard isolation is required, or enforce authorization before candidates are exposed.

redis-cli · separate security domain example
docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app GEOADD atlasmart:ch12:geo:tenant-a 49.8671 40.4093 courier-a1docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app GEOADD atlasmart:ch12:geo:tenant-b 49.8672 40.4094 courier-b1docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app GEOSEARCH atlasmart:ch12:geo:tenant-a FROMLONLAT 49.8671 40.4093 BYRADIUS 2 km WITHDIST ASC

A label or member-name prefix is not a substitute for a key-level ACL boundary. Chapter 22 will harden ACL/TLS/network design in depth.

10. Capacity and latency evidence

redis-cli · cardinality, memory, and server latency evidence
docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app ZCARD atlasmart:ch12:geo:atlasmartdocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app MEMORY USAGE atlasmart:ch12:geo:atlasmartdocker exec -e REDISCLI_AUTH=AtlasMart-Admin-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user academy-admin INFO commandstatsdocker exec -e REDISCLI_AUTH=AtlasMart-Admin-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user academy-admin INFO latencystats

GEOADD is O(log N) per item. Search cost depends on candidate geometry/selectivity and result count. Measure p50/p95/p99 under representative update/query concurrency rather than extrapolating from a three-member fixture.

11. Reproducible cleanup

redis-cli · bounded Chapter 12 cleanup
docker exec -e REDISCLI_AUTH=AtlasMart-Admin-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user academy-admin UNLINK atlasmart:ch12:geo:atlasmart atlasmart:ch12:geo:tenant-a atlasmart:ch12:geo:tenant-b

UNLINK targets only the named Chapter 12 fixtures. Do not replace this with FLUSHDB, FLUSHALL, or broad pattern deletion on a shared Redis instance.

12. Production judgment

Redis GEO is a strong fit for low-latency proximity over point locations that already belong in Redis. It is not a routing engine, polygon GIS, precision surveying system, or historical trajectory store. Validate coordinate order, ranges, units, service-radius semantics, member update rates, cardinality, hot-key concentration, persistence/replication cost, Cluster placement, ACL boundaries, and client timeout/retry behavior. A single citywide key can become a hot key; partition only after measuring and preserving query correctness.

Check your understanding

  1. What order does GEOADD require?
  2. Why can a reversed pair sometimes be accepted?
  3. What does updating the same member do?
  4. Why is ZRANGE WITHSCORES not a distance API?
  5. When is Redis GEO not sufficient?
Review the answers

Longitude first, latitude second.

Both reversed numbers can still fall inside valid longitude/latitude ranges, creating a semantically wrong but syntactically valid location.

Replaces its current indexed coordinate; it does not append history.

The score encodes geospatial position for index mechanics; it is not a business distance.

When you need high-precision GIS, polygons, road routing/travel time, complex spatial predicates, or safety-critical distance accuracy.

13. Summary and next step

You can now build and validate a current-position proximity index with correct coordinate and unit semantics. Lesson 4 combines the time-series and GEO lessons into a bounded-cardinality telemetry/location model so key growth, label growth, retention, and member churn are intentional rather than accidental.

Authoritative references

Keep knowledge open

Help the academy stay free and grow.

If these tutorials save you time, a small donation supports new lessons, technical review, diagrams, examples, and long-term maintenance.

ETHEthereum / ERC-20 only
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0

Send only Ethereum or ERC-20 compatible assets to this address.