How I Rebuilt OpenStreetMap’s Category Model During GSoC
Description and use
The new category model in Nominatim stores multiple tags in a single row, improves hierarchical filtering, and simplifies ranking. Migration of existing databases completed in 47 minutes.
Problem
Nominatim’s original model allowed only one class/type pair per place, causing awkward handling of multi‑tag objects and lack of hierarchical filtering.
Outcome
The new category model allows a single database row to represent multiple tags, improves hierarchical filtering, and simplifies ranking logic. Migration of existing planet databases completed in under 47 minutes with minimal downtime.
Workflow
- Added categories ltree[] column to place and placex tables
- Modified Lua import to generate categories and write one row per place
- Updated SQL ranking and trigger functions to use category paths
- Replaced class/type filtering with ltree queries
- Implemented lazy backfilling for existing rows during migration
- Optimized migration by disabling triggers and creating indexes after bulk update
Evidence
Nominatim only allowed one class/type pair per place.
The migration initially used lazy backfilling. When an existing row was touched, its category could be derived from the old class and type values.
Disabling the update trigger during the backfill and creating the indexes afterwards reduced that to about 47 minutes.
- Record date: 2026-09-22T06:30:36.939Z