Skip to main content

Who's On First — data model and gotchas

Who's On FirstWOF (Who's On First). An open-source gazetteer of places maintained by Mapzen/whosonfirst. Mailwoman builds a custom SQLite database from WOF GeoJSON repos, extended with postcode data, importance scores, and coincident-role relations. (WOFWOF (Who's On First). An open-source gazetteer of places maintained by Mapzen/whosonfirst. Mailwoman builds a custom SQLite database from WOF GeoJSON repos, extended with postcode data, importance scores, and coincident-role relations.) is the best open gazetteergazetteerA geographical index that maps place names and postcodes to real-world coordinates. Mailwoman uses a custom-built Who's On First (WOF) SQLite database as its gazetteer — the 'atlas' half of the grammar/atlas architecture. available. It's also one of the strangest datasets you'll encounter as a developer. This article documents the gotchas — the structural quirks that trip up new consumers — and the tooling Mailwoman built to work around them.

If you just want to understand how Mailwoman's resolverresolverThe component that converts parsed address components (locality, region, postcode) into coordinates by looking them up in the gazetteer. The resolver ranks candidates by name match, population, and proximity, and returns the best-matching place with its centroid or polygon. queries WOFWOF (Who's On First). An open-source gazetteer of places maintained by Mapzen/whosonfirst. Mailwoman builds a custom SQLite database from WOF GeoJSON repos, extended with postcode data, importance scores, and coincident-role relations. at runtime, see Resolver and Who's On First. For the build-time ingest pipelinestaged pipelineMailwoman's runtime architecture: a sequence of pure-function stages (normalize → query-shape → locale-gate → kind-classifier → phrase-grouper → classifier → decoder) connected by typed handoffs. Each stage is published as its own npm package., see WOF data pipeline. This article is about the data modelneural classifierThe machine learning model at the core of Mailwoman's parser — a transformer encoder (~30M parameters) trained from scratch to do BIO token classification over addresses. It learns the 'grammar' of address formats; the gazetteer supplies the 'atlas.' itself.

What WOF is

WOFWOF (Who's On First). An open-source gazetteer of places maintained by Mapzen/whosonfirst. Mailwoman builds a custom SQLite database from WOF GeoJSON repos, extended with postcode data, importance scores, and coincident-role relations. is a gazetteergazetteerA geographical index that maps place names and postcodes to real-world coordinates. Mailwoman uses a custom-built Who's On First (WOF) SQLite database as its gazetteer — the 'atlas' half of the grammar/atlas architecture. — a structured database of places. Not addresses, not roads, not buildings. Places: countries, regionsregionThe first-level administrative subdivision of a country — a US state, a French region, a province. The component between country and locality., counties, cities, neighbourhoods, venuesvenueA named, non-address place — a business, building, park, or stadium. Mailwoman's free-text point-of-interest component, added as a Tier 2 fine label.. Each record gets:

  • A stable numeric ID
  • A parent-child hierarchy
  • Multilingual name variants
  • A polygon geometry (bounding box)

It was created by Mapzen (2018) as the successor to GeoPlanet (Yahoo's gazetteergazetteerA geographical index that maps place names and postcodes to real-world coordinates. Mailwoman uses a custom-built Who's On First (WOF) SQLite database as its gazetteer — the 'atlas' half of the grammar/atlas architecture.). The data lives on GitHub as approximately 100 repositories under the whosonfirst-data org — several million individual GeoJSON files. Geocode Earth maintains the canonical SQLite distributions.

The key thing WOFWOF (Who's On First). An open-source gazetteer of places maintained by Mapzen/whosonfirst. Mailwoman builds a custom SQLite database from WOF GeoJSON repos, extended with postcode data, importance scores, and coincident-role relations. gives you that no other open dataset provides: a consistent hierarchy with stable IDs. You can take a localitylocalityThe city / town / settlement component of an address: a populated place sitting between region and neighbourhood in the hierarchy. (Houston, id 85922029), follow its parent_id to a regionregionThe first-level administrative subdivision of a country — a US state, a French region, a province. The component between country and locality. (Texas, id 85688753), follow that to a countrycountryThe top-level address component (an ISO country). Closed-vocabulary, so it is best handled by a deterministic matcher feeding a proposal rather than a retrained model head. (United States, id 85633793), and know the chain is consistent. OpenStreetMapOpenStreetMap (OSM). A community-curated global map database (ODbL-licensed) with addr:* tagged features and place hierarchies. A secondary corpus source and a source of street names. doesn't give you this. GeoNamesGeoNamesA free global gazetteer combining administrative, postal, and POI data across 200+ countries. Supplements Who's On First for postcode centroids and places where WOF has gaps. gives you a partial version. WOFWOF (Who's On First). An open-source gazetteer of places maintained by Mapzen/whosonfirst. Mailwoman builds a custom SQLite database from WOF GeoJSON repos, extended with postcode data, importance scores, and coincident-role relations. gives you the whole thing, with an opinion on how the world's administrative boundaries nest.

The gotchas

One file per place

WOFWOF (Who's On First). An open-source gazetteer of places maintained by Mapzen/whosonfirst. Mailwoman builds a custom SQLite database from WOF GeoJSON repos, extended with postcode data, importance scores, and coincident-role relations.'s canonical storage is one .geojson file per place, organized in a directory tree. A US admin subset has roughly 120,000 individual files. The French equivalent has about 80,000. Opening, parsingaddress parsingThe process of decomposing a free-text postal address string into structured components — house number, street name, locality, region, postcode, and country — so a geocoder can resolve them to coordinates., and indexing 200,000 JSON files is a meaningful engineering problem before you've asked a single query.

This layout made sense for WOFWOF (Who's On First). An open-source gazetteer of places maintained by Mapzen/whosonfirst. Mailwoman builds a custom SQLite database from WOF GeoJSON repos, extended with postcode data, importance scores, and coincident-role relations.'s original use case — git-trackable changes to individual places. But for a geocoder that needs to query "all localities named Houston" across 120K files, it's the wrong access pattern. The SQLite distributions from Geocode Earth exist precisely to solve this.

The property namespace explosion

A WOF GeoJSONWOF GeoJSONThe raw one-feature-per-file GeoJSON distributed by Who's On First repositories — the input that Mailwoman's WOF SQLite build consumes. featurefeatureAn input signal a model conditions on. Beyond the raw tokens, Mailwoman feeds soft features — gazetteer-membership channels and the postcode anchor — that inform predictions without overriding them.'s properties object uses namespaced keys:

{
"wof:id": 85830005,
"wof:name": "Lawrence Corner",
"wof:placetype": "neighbourhood",
"wof:parent_id": 1729442683,
"wof:country": "US",
"wof:hierarchy": [
{
"continent_id": 102191575,
"country_id": 85633793,
"county_id": 102085493,
"localadmin_id": 404477193,
"locality_id": 1729442683,
"neighbourhood_id": 85830005,
"region_id": 85688689
}
],
"name:eng_x_preferred": ["Lawrence Corner"],
"name:eng_x_variant": ["Lawrence Cor"],
"src:geom": "quattroshapes",
"edtf:inception": "uuuu",
"edtf:cessation": "uuuu",
"geom:area": 0.000047,
"geom:bbox": "-74.73,40.08,-74.72,40.09",
"mz:hierarchy_label": 1
}

Key observations:

  • Namespaced keys everywhere. wof:, name:, src:, edtf:, geom:, mz: — each prefix is a different source or concern. The schema is flat (one object, no nesting) with meaning encoded in the key name.
  • Name variants are language-coded. name:eng_x_preferred is the preferred English name. name:fra_x_preferred is French. name:zho_x_preferred is Chinese. The _x_ separator splits the language code from the name kind.
  • Name kinds vary. preferred, variant, colloquial, abbr, short. A single place can have entries for several of these per language. A major citylocalityThe city / town / settlement component of an address: a populated place sitting between region and neighbourhood in the hierarchy. like Paris has name: entries in 50+ languages; a rural US neighbourhood might have only one.
  • The hierarchy is pre-computed. Instead of walking parent_id up the tree at query time, WOFWOF (Who's On First). An open-source gazetteer of places maintained by Mapzen/whosonfirst. Mailwoman builds a custom SQLite database from WOF GeoJSON repos, extended with postcode data, importance scores, and coincident-role relations. bakes the full ancestry chain into each record. Convenient for display; redundant for storage; occasionally stale when a parent is reclassified.

Brooklyn Integers

WOFWOF (Who's On First). An open-source gazetteer of places maintained by Mapzen/whosonfirst. Mailwoman builds a custom SQLite database from WOF GeoJSON repos, extended with postcode data, importance scores, and coincident-role relations. IDs are issued by a service called Brooklyn Integers — a distributed ID generator that guarantees uniqueness across the dataset. The IDs are not sequential, not geographically meaningful, and not sortable. They're just unique numbers. This is fine for lookup but means you can't reason about "nearby" places by ID proximity or infer anything from the numeric value.

Supersession chains

Places get deprecated: a neighbourhood is absorbed by a neighbouring one, a county boundary changes, a localitylocalityThe city / town / settlement component of an address: a populated place sitting between region and neighbourhood in the hierarchy. is merged. WOFWOF (Who's On First). An open-source gazetteer of places maintained by Mapzen/whosonfirst. Mailwoman builds a custom SQLite database from WOF GeoJSON repos, extended with postcode data, importance scores, and coincident-role relations. tracks this via wof:superseded_by arrays. A query that doesn't check supersession may return a place that hasn't existed since 2015. Every consumer needs to follow the supersession chain to the current record.

Parent ID holes

  • parent_id: -1 — "we don't know the parent." The first French postalcode dataset was ingested with parent_id: -1 for every record, making hierarchy traversal useless until someone manually assigned parents. Some records still have -1.
  • parent_id: 0 — "no parent (this is a continent or Earth itself)."
  • parent_id: 1 — Earth (the root of all hierarchy).

A query that assumes every record has a valid parent chainparent chainThe sequence of administrative parents above a place — Springfield → Sangamon County → Illinois → United States. Used to check the geographic coherence of a parse. will fail silently on these cases.

Name normalisation is critical

WOFWOF (Who's On First). An open-source gazetteer of places maintained by Mapzen/whosonfirst. Mailwoman builds a custom SQLite database from WOF GeoJSON repos, extended with postcode data, importance scores, and coincident-role relations. stores "São Paulo" with the accent. User input might arrive as "Sao Paulo" or "SAO PAULO". Case folding and accent stripping are not optional — they are required for matching. The resolverresolverThe component that converts parsed address components (locality, region, postcode) into coordinates by looking them up in the gazetteer. The resolver ranks candidates by name match, population, and proximity, and returns the best-matching place with its centroid or polygon.'s placename index normalises all names to a canonical form (NFC, lowercase, accent-stripped) before insertion.

How Mailwoman uses WOF

Mailwoman needs WOFWOF (Who's On First). An open-source gazetteer of places maintained by Mapzen/whosonfirst. Mailwoman builds a custom SQLite database from WOF GeoJSON repos, extended with postcode data, importance scores, and coincident-role relations. for two distinct access patterns:

1. Rule classifiers — "is this token a known place name?"

The whos_on_first rule classifier answers "is this string a localitylocalityThe city / town / settlement component of an address: a populated place sitting between region and neighbourhood in the hierarchy./regionregionThe first-level administrative subdivision of a country — a US state, a French region, a province. The component between country and locality./countrycountryThe top-level address component (an ISO country). Closed-vocabulary, so it is best handled by a deterministic matcher feeding a proposal rather than a retrained model head. name in any language?" It doesn't need coordinates, hierarchy, or geometry — just the normalised string and which languages it's valid in.

WOFPlacenameCache builds this index by streaming GeoJSON files, extracting name:* properties, normalising them, and inserting into an in-memory Map<string, Set<language>> keyed by the normalised form.

2. Reconcile concordance — "do these components form a valid parent chain?"

StagestageOne of the dataflow stages in the runtime pipeline (normalize, locale gate, kind classify, phrase group, token classify, sequence correct, reconcile, resolve). Distinct from tier (model vocabulary) and phase (plan milestone). 5 joint decodingjoint decodingA decode strategy where the neural model's proposals and rule-based solver's output are reconciled into a single parse tree. Formerly the default (Route A Phase II), now retired in favor of argmax after it was found to break the street+house_number geocode precondition. scores parseaddress parsingThe process of decomposing a free-text postal address string into structured components — house number, street name, locality, region, postcode, and country — so a geocoder can resolve them to coordinates. candidates against the gazetteergazetteerA geographical index that maps place names and postcodes to real-world coordinates. Mailwoman uses a custom-built Who's On First (WOF) SQLite database as its gazetteer — the 'atlas' half of the grammar/atlas architecture.'s hierarchy. The reconciler needs richer queries: "give me all localities named Houston with their parent_id chains" and "walk this localitylocalityThe city / town / settlement component of an address: a populated place sitting between region and neighbourhood in the hierarchy.'s parent_id up to regionregionThe first-level administrative subdivision of a country — a US state, a French region, a province. The component between country and locality. — does it reach Texas?"

PlacetypeDataSource is a SQLite database per (placetypeplacetypeThe Who's On First hierarchical classification of places: planet → continent → country → region → county → locality → neighbourhood. The resolver uses placetype to rank candidates — an exact locality match outranks a county-level match., language) pair:

CREATE TABLE records (
id INTEGER NOT NULL,
src TEXT NOT NULL,
name TEXT NOT NULL,
preferred TEXT,
variant TEXT,
colloquial TEXT,
abbr TEXT,
short TEXT,
parent_id INTEGER,
PRIMARY KEY (id, src, name)
);

One row per name variant. "Saint Petersburg", "St. Petersburg", and "St Petersburg" are three rows for the same id in different name/variant/short columns. The reconciler can match any variant form and get the same parent_id chain.

Ingest tooling

Processing 120K GeoJSON files is an embarrassingly-parallel problem. Mailwoman's WOFWOF (Who's On First). An open-source gazetteer of places maintained by Mapzen/whosonfirst. Mailwoman builds a custom SQLite database from WOF GeoJSON repos, extended with postcode data, importance scores, and coincident-role relations. ingest pipelinestaged pipelineMailwoman's runtime architecture: a sequence of pure-function stages (normalize → query-shape → locale-gate → kind-classifier → phrase-grouper → classifier → decoder) connected by typed handoffs. Each stage is published as its own npm package. uses Piscina (a Node.js worker-threadthreadA parallel workstream within a release. Threads compose; they are not sequential milestones like phases. pool) to dispatch files across all available CPU cores. Each worker reads a GeoJSON file, calls pluckPlacetypeSpec to extract structured fields and name variants, and upserts into the appropriate PlacetypeDataSource.

When the data arrives as a single bulk NDJSON dump rather than individual files, AsyncSpliterator.asMany(source, delimiter, concurrency) splits the file into N byte-range chunksunknown tokenA placeholder for input not in the tokenizer's vocabulary. Byte fallback largely removes the need for one by encoding unseen characters as raw bytes instead., snaps to delimiter boundaries, and returns N independent async iterators for parallel processing. It's built but not yet exercised at scale.

For full details on the ingest pipelinestaged pipelineMailwoman's runtime architecture: a sequence of pure-function stages (normalize → query-shape → locale-gate → kind-classifier → phrase-grouper → classifier → decoder) connected by typed handoffs. Each stage is published as its own npm package., see WOF data pipeline.

So why put up with WOF?

Every geocoder needs a gazetteergazetteerA geographical index that maps place names and postcodes to real-world coordinates. Mailwoman uses a custom-built Who's On First (WOF) SQLite database as its gazetteer — the 'atlas' half of the grammar/atlas architecture.. The options are:

  • Pay for one — Google, HERE, Mapbox
  • Use an open oneWOFWOF (Who's On First). An open-source gazetteer of places maintained by Mapzen/whosonfirst. Mailwoman builds a custom SQLite database from WOF GeoJSON repos, extended with postcode data, importance scores, and coincident-role relations., GeoNamesGeoNamesA free global gazetteer combining administrative, postal, and POI data across 200+ countries. Supplements Who's On First for postcode centroids and places where WOF has gaps., OSMOpenStreetMap (OSM). A community-curated global map database (ODbL-licensed) with addr:* tagged features and place hierarchies. A secondary corpus source and a source of street names. Nominatim
  • Build your ownBANBAN (Base Adresse Nationale). France's authoritative open national address register — the highest-quality training source for French addresses, with full component structure. (France), NADNAD (National Address Database). A US Department of Transportation dataset of structured address points, added to the training corpus as a major source of real US addresses. (US), TIGERTIGERThe US Census Topologically Integrated Geographic Encoding and Referencing database. Used as a corpus source for street-segment data. (US)

WOFWOF (Who's On First). An open-source gazetteer of places maintained by Mapzen/whosonfirst. Mailwoman builds a custom SQLite database from WOF GeoJSON repos, extended with postcode data, importance scores, and coincident-role relations. is the best open option for hierarchy and multilingual names. But it's hard to use raw. The per-file layout, flat namespace, supersession chains, and parent_id: -1 holes are each a trap for a naive consumer. The tooling Mailwoman built — WOFPlacenameCache, PlacetypeDataSource, the Piscina pipelinestaged pipelineMailwoman's runtime architecture: a sequence of pure-function stages (normalize → query-shape → locale-gate → kind-classifier → phrase-grouper → classifier → decoder) connected by typed handoffs. Each stage is published as its own npm package., AsyncSpliterator.asMany — closes the gap between "WOFWOF (Who's On First). An open-source gazetteer of places maintained by Mapzen/whosonfirst. Mailwoman builds a custom SQLite database from WOF GeoJSON repos, extended with postcode data, importance scores, and coincident-role relations. exists" and "WOFWOF (Who's On First). An open-source gazetteer of places maintained by Mapzen/whosonfirst. Mailwoman builds a custom SQLite database from WOF GeoJSON repos, extended with postcode data, importance scores, and coincident-role relations. is usable as a geocoder component."

See also

  • Who's On First on GitHub — the source repos
  • Geocode Earth WOF distributions — pre-built SQLite files
  • Spelunker — the official WOFWOF (Who's On First). An open-source gazetteer of places maintained by Mapzen/whosonfirst. Mailwoman builds a custom SQLite database from WOF GeoJSON repos, extended with postcode data, importance scores, and coincident-role relations. browser
  • Resolver and Who's On First — how the runtime resolverresolverThe component that converts parsed address components (locality, region, postcode) into coordinates by looking them up in the gazetteer. The resolver ranks candidates by name match, population, and proximity, and returns the best-matching place with its centroid or polygon. queries WOFWOF (Who's On First). An open-source gazetteer of places maintained by Mapzen/whosonfirst. Mailwoman builds a custom SQLite database from WOF GeoJSON repos, extended with postcode data, importance scores, and coincident-role relations.
  • WOF data pipeline — build-time ingest architecture
  • Taming Who's On First — the narrative version of this article