When building logistics and telemetry platforms, processing thousands of GPS pings per second is just a regular Tuesday. The core challenge isn't just receiving the data; it's figuring out exactly where that data is in relation to your business logic. Is the truck inside the warehouse? Did it cross a restricted zone?
If you are building a geofencing architecture, you will inevitably face the dilemma: Should you use exact Custom Polygons (PostGIS) or spatial indexing grids like Uber's H3?
Spoiler alert: For a truly scalable and user-friendly system, you need both. Here is how we handle this hybrid architecture using Go and PostGIS.
The Reality: Users Don't Think in Hexagons
From a purely mathematical standpoint, Uber’s H3 is a masterpiece. But from a UX perspective, telling a warehouse manager to draw their loading dock using only rigid hexagons is a terrible idea. Real-world facilities (like a CEDIS or a distribution center) are irregular.
Users need to draw custom polygons on a map. In our Go backend, we typically store these directly in PostgreSQL using PostGIS.
The Standard Approach: PostGIS ST_Contains
When a GPS ping hits our Go server, the most straightforward approach is to ask PostGIS if the point is inside any stored polygon.
// A simplified example of checking a GPS ping against PostGIS polygons
package main
import (
"database/sql"
"fmt"
"log"
_ "github.com/lib/pq"
)
func checkGeofence(db *sql.DB, lat, lng float64) (string, error) {
query := `
SELECT fence_id, name
FROM geofences
WHERE ST_Contains(geom, ST_SetSRID(ST_MakePoint($1, $2), 4326));
`
var fenceID, name string
err := db.QueryRow(query, lng, lat).Scan(&fenceID, &name)
if err != nil {
if err == sql.ErrNoRows {
return "", nil // Not in any geofence
}
return "", err
}
return name, nil
}
The Catch: ST_Contains uses spatial math (like ray casting) to determine if a point is inside a polygon. Even with GiST indexes, running complex spatial intersections for 10,000 pings per second will melt your database CPU and spike your cloud bill.
The Scaling Secret: Enter Uber's H3
When we need to eliminate database latency and scale massively, we bring H3 into the backend.
H3 divides the world into a grid of hexagons. Instead of doing complex math, H3 converts a (latitude, longitude) pair into a simple string or integer (e.g., 8928308280fffff).
Why is this a game-changer? Because checking if a truck is in a zone goes from an expensive spatial calculation to an $O(1)$ Hash Map lookup.
The Hybrid Architecture: "Polyfill"
We don't force users to draw hexagons. We let them draw their precise custom polygons. Then, in the Go backend, we run an asynchronous worker that takes that polygon and "fills" it with H3 hexagons (a process called Polyfill).
We store these hexagon IDs in a fast key-value store (like Redis) or a simple indexed database table.
package main
import (
"fmt"
"github.com/uber/h3-go/v4"
)
func indexGeofenceWithH3(polygon []h3.LatLng, resolution int) []h3.Cell {
// Create a GeoLoop from the user's custom polygon
geoLoop := h3.NewGeoLoop(polygon)
geoPolygon := h3.NewGeoPolygon(geoLoop, nil)
// Fill the polygon with H3 hexagons at the desired resolution
hexagons := h3.PolygonToCells(geoPolygon, resolution)
return hexagons
}
func handleIncomingPing(lat, lng float64) {
// 1. Convert incoming ping to H3 index instantly
latLng := h3.NewLatLng(lat, lng)
resolution := 9 // Roughly city-block size
cell := h3.LatLngToCell(latLng, resolution)
// 2. O(1) Lookup: Check if this cell ID exists in our Redis cache
// cache.Exists(cell.String())
fmt.Printf("Ping mapped to Hexagon: %s\n", cell.String())
}
The Best of Both Worlds
By using Go, PostGIS, and H3 together, you build a logistics engine that is both precise and brutally fast:
- UX / Precision: Users draw exact custom polygons.
- Storage: PostGIS acts as the source of truth for the exact geometries.
- Real-Time Processing: Go converts incoming pings to H3 indexes and checks them against a cached set of Polyfilled hexagons in microseconds.
There is no silver bullet in software engineering, but for real-time logistics telemetry, combining PostGIS precision with H3 speed is as close as it gets.
Top comments (0)