Appearance
H3 Spatial Indexing
Overview
The H3 Spatial Indexing service is a Python-based geospatial utility microservice providing Uber's H3 hexagonal spatial indexing and polygon operations for the OR platform. Developed for an OR Alpha project, it serves as the spatial computation backend that enables grid-based spatial analysis, zone assignment, and multi-resolution aggregation for fire risk mapping and location intelligence.
The service converts between geographic coordinates, H3 hexagonal grid cells, and polygon boundaries — enabling the Fire Spread Modelling service to work with real-world terrain data indexed at hexagonal resolution levels.
Architecture
| Aspect | Detail |
|---|---|
| Language | Python 3.12 |
| Web Framework | FastAPI v0.116.1 |
| ASGI Server | Uvicorn v0.37.0 |
| Port | :8585 |
| Data Validation | Pydantic v2.10.6 |
| H3 Library | h3 v4.0.0 (Uber's hexagonal hierarchical spatial index) |
| Geospatial | GeoPandas v1.0.1, Shapely v2.0.6 |
| Caching | Redis v6.2.0 |
| Package Manager | Poetry |
| Deployment | AWS ECR via Azure DevOps CI/CD pipeline |
OR Platform Integration
The service follows the OR Python microservice boilerplate pattern:
- Data Abstraction Layer (DAL) — all endpoint functions are wrapped with
@dal_wrapperfor OR platform DAL conformance - Route registration — endpoints registered via
create_route()with typed request/response schemas andx_type/x_usecaseOpenAPI extensions - Standard envelope — uses generic
ORHttpRequest[TInput, TParams]/ORHttpResponse[TOutput]types for pipeline compatibility - Redis — initialised at startup for platform state management
- Health probes —
/liveand/readyendpoints for Kubernetes health checks - Swagger — auto-generated OpenAPI 3.1.0 schema at
/docs/schemawith interactive UI at/docs
Capabilities
Coordinate ↔ H3 Conversion
Convert between geographic coordinates and H3 hexagonal cell indices at any resolution level (0–15).
Lat/Lon to H3
Converts a geographic coordinate to its enclosing H3 hexagonal cell using h3.latlng_to_cell().
| Endpoint | Input | Parameters | Output |
|---|---|---|---|
POST /latlon_to_h3 | latitude, longitude | resolution (0–15, default: 9) | h3_index, resolution, input coordinates |
POST /latlon_to_h3_bulk | Array of CoordinatePair | resolution (0–15, default: 9) | Array of H3Result (h3_index, lat, lon), total_converted |
H3 to Lat/Lon
Converts an H3 cell index back to its hexagon centre-point coordinates using h3.cell_to_latlng().
| Endpoint | Input | Parameters | Output |
|---|---|---|---|
POST /h3_to_latlon | h3_index | validate_h3_index (default: true) | latitude, longitude, resolution |
POST /h3_to_latlon_bulk | Array of h3_indices | validate_h3_indices, skip_invalid | Array of CoordinateResult, total_converted |
H3 Hierarchy Navigation
Navigate between resolution levels in the H3 hexagonal hierarchy. Each parent cell contains ~7 children at the next finer resolution.
Parent to Children (Zoom In)
Expands a parent H3 cell to all child cells at a higher (finer) resolution using h3.cell_to_children().
| Endpoint | Input | Parameters | Output |
|---|---|---|---|
POST /h3_parent_to_children | parent_h3_index, child_resolution | validate_h3_index, include_parent_info (area, coordinates) | child_h3_indices, total_children, resolution_difference, optional parent_info |
POST /h3_parent_to_children_bulk | Array of parent_h3_indices, child_resolution | validate_h3_indices, skip_invalid, deduplicate_children | Per-parent results, all_child_h3_indices (deduplicated), duplicates_removed |
The bulk variant deduplicates overlapping children from adjacent parents — essential when expanding contiguous regions.
Child to Parent (Zoom Out)
Maps a child H3 cell to its parent at a lower (coarser) resolution using h3.cell_to_parent(). Each child has exactly one parent at any given resolution.
| Endpoint | Input | Parameters | Output |
|---|---|---|---|
POST /h3_child_to_parent | child_h3_index, parent_resolution | validate_h3_index, include_child_info | parent_h3_index, parent_latitude, parent_longitude, resolution_difference |
POST /h3_child_to_parent_bulk | Array of child_h3_indices, parent_resolution | validate_h3_indices, skip_invalid | Per-child results, unique_parents (deduplicated), total_unique_parents |
The bulk variant identifies unique parents — siblings that share the same parent are naturally deduplicated.
Polygon Operations
Polygon Intersection (Zone Assignment)
Determines which polygon from a GeoJSON FeatureCollection contains each point, using a three-tier matching strategy:
- Exact match — point is geometrically inside a polygon (Shapely
contains) - Buffer match — point is within a configurable buffer distance of a polygon boundary
- Nearest match — finds the closest polygon within a maximum search distance
Built on GeoPandas and Shapely with automatic geometry validation and repair (.buffer(0) technique), numpy type conversion for JSON serialisation, and WGS84 (EPSG:4326) CRS assumption.
| Endpoint | Input | Parameters |
|---|---|---|
POST /polygon_intersect | GeoJSON FeatureCollection (polygons with id), array of PointWithId (id, lat, lon) | buffer_distance_meters (default: 5000), find_nearest_if_no_match (default: true), max_distance_for_nearest (default: 50000m) |
Response per point: intersecting_polygon_id, polygon_properties, distance_to_polygon (0 if inside, metres if buffer/nearest), match_type (exact / buffer / nearest / none).
Polygon to H3 (Grid Coverage)
Converts polygon boundaries to H3 hexagonal grid coverage using h3.polygon_to_cells(). Supports Polygon, MultiPolygon, Feature, and FeatureCollection inputs.
For MultiPolygon and FeatureCollection inputs, each polygon is processed separately and the H3 cell sets are unioned. Invalid geometries are auto-repaired via .buffer(0). Falls back to h3.LatLngPoly format if the GeoJSON dict format fails.
| Endpoint | Input | Parameters | Output |
|---|---|---|---|
POST /polygon_to_h3 | GeoJSON Polygon, MultiPolygon, Feature, or FeatureCollection | resolution (0–15, default: 5), combine_all_features (default: true) | h3_indices, total_hexagons, area_info (hexagon area, total area, geometry type), features_processed |
H3 Resolution Reference
| Resolution | Hexagon Area | Typical Use |
|---|---|---|
| 0–3 | 4,250–100,000 km² | Continental / country scale |
| 4–6 | 7–1,000 km² | State / province scale |
| 7–9 | 0.1–5 km² | City / neighbourhood scale |
| 10–12 | 15 m²–45,000 m² | Street / building scale |
| 13–15 | 0.9–9 m² | Precise / indoor scale |
The Fire Spread Modelling service uses resolution 4 (~25 km² per hex) for national-scale terrain indexing in the TerrainRef PostgreSQL table.
API Endpoints
| Endpoint | Method | Category | Purpose |
|---|---|---|---|
/live | GET | Health | Liveness probe |
/ready | GET | Health | Readiness probe |
/latlon_to_h3 | POST | Geocoding | Single coordinate → H3 index |
/latlon_to_h3_bulk | POST | Geocoding | Batch coordinates → H3 indices |
/h3_to_latlon | POST | Geocoding | Single H3 index → centre lat/lon |
/h3_to_latlon_bulk | POST | Geocoding | Batch H3 indices → coordinates |
/h3_parent_to_children | POST | H3 Hierarchy | Single parent → all child cells |
/h3_parent_to_children_bulk | POST | H3 Hierarchy | Batch parents → children with dedup |
/h3_child_to_parent | POST | H3 Hierarchy | Single child → parent cell |
/h3_child_to_parent_bulk | POST | H3 Hierarchy | Batch children → parents with unique parent identification |
/polygon_intersect | POST | Geospatial | Point-in-polygon zone assignment |
/polygon_to_h3 | POST | Geospatial | Polygon boundary → H3 grid coverage |
Deployment
| Aspect | Detail |
|---|---|
| Repository | or-demo-alpha-firesolvepython |
| AWS Account | 514190630167 |
| Container | Python Docker image → AWS ECR |
| CI/CD | Azure DevOps (PythonBuild → PythonTest → EcrDeploy) |
| Local dev | make install → make run → http://localhost:8585 |
| Testing | make test (pytest) |
