Built a complete Rust-based geocoding system with Elasticsearch, inspired by Pelias architecture but implemented cleanly in Rust.
- Models - Place,
AdminLevel, AdminHierarchy, AdminEntry for document structure - Elasticsearch - Client wrapper, schema creation, bulk indexer with batching
- PIP Service - Point-in-Polygon admin lookup with R-tree spatial indexing
- Wikidata - SPARQL fetcher for multilingual label enrichment
CLI binary that:
- Parses OSM PBF files using
osmpbfreader - Extracts admin boundaries with multilingual names
- Builds R-tree spatial index for PIP lookups
- Processes places (nodes with names/POI tags)
- Assigns denormalized parent hierarchy via PIP
- Optionally enriches with Wikidata labels
- Bulk indexes into Elasticsearch
- Supports refresh mode (deletes stale documents)
Axum HTTP server with endpoints:
GET /v1/search- Forward geocoding with full-text searchGET /v1/autocomplete- Edge n-gram autocompleteGET /v1/reverse- Reverse geocoding by coordinatesGET /health- Health check Features:- Multi-match across
name.*fields (all languages) - Gaussian decay scoring for location bias
- Bounding box filtering
- Language preference for result ordering
- Returns all language variants in response
Custom analyzers:
peliasIndex- Tokenizer with ASCII foldingpeliasQuery- Adds synonym expansionpeliasAutocomplete- Edge n-grams for partial matching Dynamic templates for multilingualname.*andparent.*.name_*fields.
cargo build --release ✓ Finished in 1m 14s
| Path | Description |
|---|---|
src/models/ |
Place, AdminLevel, AdminHierarchy types |
src/elasticsearch/ |
Client, schema, bulk indexer |
src/pip/ |
Admin boundary extraction and PIP service |
src/wikidata/ |
SPARQL label fetcher |
src/ingest/ |
OSM import binary |
src/query/ |
HTTP query server |
schema/places_mapping.json |
ES index mapping |
scripts/import_switzerland.sh |
Import automation |
./scripts/import_switzerland.sh --fresh
Run Query Server
cargo run --release --bin query
Example Queries
# Search
curl "http://localhost:3000/v1/search?text=Zurich"
# Autocomplete
curl "http://localhost:3000/v1/autocomplete?text=zur"
# Reverse geocode
curl "http://localhost:3000/v1/reverse?point.lat=47.37&point.lon=8.54"
Multilingual Support
Extracts all name:* tags from OSM (de, fr, it, en, etc.)
Stores in ES as name.de, name.fr, etc.
Searchable across all languages via multi_match
Optional Wikidata enrichment with --wikidata flag
Response includes all available languages in names object