photon is an open source geocoder built for OpenStreetMap data. It is based on elasticsearch - an efficient, powerful and highly scalable search platform.
photon was started by komoot and provides search-as-you-type and multilingual support. Find our public API and demo on photon.komoot.io. Until October 2020 the API was available under photon.komoot.de. Please update your apps accordingly.
All code contributions and bug reports are welcome!
For questions please send an email to our mailing list.
Feel free to test and participate!
photon software is open source and licensed under Apache License, Version 2.0
- high performance
- highly scalability
- search-as-you-type
- multilingual search
- location bias
- typo tolerance
- filter by osm tag and value
- filter by bounding box
- reverse geocode a coordinate to an address
- OSM data import (built upon Nominatim) inclusive continuous updates
photon requires Java, at least version 11.
Download the search index (72G GB compressed, 159GB uncompressed as of 2023-10-26, worldwide coverage, languages: English, German, French and local name). The search index is updated weekly and thankfully provided by GraphHopper with the support of lonvia. Now get the latest version of photon from the releases.
Make sure you have bzip2 or pbzip2 installed and execute one of these two commands in your shell. This will download, uncompress and extract the huge database in one step:
wget -O - https://download1.graphhopper.com/public/photon-db-latest.tar.bz2 | bzip2 -cd | tar x
# you can significantly speed up extracting using pbzip2 (recommended):
wget -O - https://download1.graphhopper.com/public/photon-db-latest.tar.bz2 | pbzip2 -cd | tar x
photon uses gradle for building. To build the package from source make sure you have a JDK installed. Then run:
./gradlew app:es_embedded:build
This will build and test photon. The final jar can be found in target
.
The repository also contains a version that runs against the latest version of OpenSearch. This version is still experimental. To build the OpenSearch version run:
./gradlew app:opensearch:build
The final jar can be found in target/photon-opensearch-<VERSION>.jar
.
Indexes produced by this version are not compatible with the ElasticSearch version. There are no prebuilt indexes available. You need to create your own export from a Nominatim database. See 'Customized Search Data' below.
Start photon with the following command:
java -jar photon-*.jar
Use the -data-dir
option to point to the parent directory of photon_data
if that directory is not in the default location ./photon_data
. Before you can send requests to photon, ElasticSearch needs to load some data into memory so be patient for a few seconds.
Check the URL http://localhost:2322/api?q=berlin
to see if photon is running without problems. You may want to use our leaflet plugin to see the results on a map.
To enable CORS (cross-site requests), use -cors-any
to allow any origin or -cors-origin
with a specific origin as the argument. By default, CORS support is disabled.
Discover more of photon's features with its usage java -jar photon-*.jar -h
. The available options are as follows:
-h Show help / usage
-cluster Name of elasticsearch cluster to put the server into (default is 'photon')
-transport-addresses The comma separated addresses of external elasticsearch nodes where the
client can connect to (default is an empty string which forces an internal node to start)
-nominatim-import Import nominatim database into photon (this will delete previous index)
-nominatim-update Fetch updates from nominatim database into photon and exit (this updates the index only
without offering an API)
-languages Languages nominatim importer should import and use at run-time, comma separated (default is 'en,fr,de,it')
-default-language Language to return results in when no explicit language is choosen by the user
-country-codes Country codes filter that nominatim importer should import, comma separated. If empty full planet is done
-extra-tags Comma-separated list of additional tags to save for each place
-synonym-file File with synonym and classification terms
-json Import nominatim database and dump it to a json like files in (useful for developing)
-host Postgres host (default 127.0.0.1)
-port Postgres port (default 5432)
-database Postgres host (default nominatim)
-user Postgres user (default nominatim)
-password Postgres password (default '')
-data-dir Data directory (default '.')
-listen-port Listen to port (default 2322)
-listen-ip Listen to address (default '0.0.0.0')
-cors-any Enable cross-site resource sharing for any origin (default CORS not supported)
-cors-origin Enable cross-site resource sharing for the specified origin (default CORS not supported)
-enable-update-api Enable the additional endpoint /nominatim-update, which allows to trigger updates
from a nominatim database
If you need search data in other languages or restricted to a country you will need to create your search data by your own. Once you have your Nominatim database ready, you can import the data to photon.
If you haven't already set a password for your Nominatim database user, do it now (change user name and password as you like, below):
su postgres
psql
ALTER USER nominatim WITH ENCRYPTED PASSWORD 'mysecretpassword';
Import the data to photon:
java -jar photon-*.jar -nominatim-import -host localhost -port 5432 -database nominatim -user nominatim -password mysecretpassword -languages es,fr
The import of worldwide data set will take some hours/days, SSD/NVME disks are recommended to accelerate Nominatim queries.
To update an existing Photon database from Nominatim, first prepare the Nominatim database with the appropriate triggers:
java -jar photon-*.jar -database nominatim -user nominatim -password ... -nominatim-update-init-for update_user
This script must be run with a user that has the right to create tables, functions and triggers.
'update-user' is the PostgreSQL user that will be used when updating the Photon database. The user needs read rights on the database. The necessary update rights will be granted during initialisation.
Now you can run updates on Nominatim using the usual methods as described in the documentation. To bring the Photon database up-to-date, stop the Nominatim updates and then run the Photon update process:
java -jar photon-*.jar -database nominatim -user nominatim -password ... -nominatim-update
You can also run the photon process with the update API enabled:
java -jar photon-*.jar -enable-update-api -database nominatim -user nominatim -password ...
Then you can trigger updates like this:
curl http://localhost:2322/nominatim-update
This will only start the updates. To check if the updates have finished, use the status API:
curl http://localhost:2322/nominatim-update/status
It returns a single JSON string "BUSY"
when updates are in progress or
"OK"
when another update round can be started.
For your convenience, this repository contains a script to continuously update
both Nominatim and Photon using Photon's update API. Make sure you have
Photon started with -enable-update-api
and then run:
export NOMINATIM_DIR=/srv/nominatim/...
./continuously_update_from_nominatim.sh
where NOMINATIM_DIR
is the project directory of your Nominatim installation.
http://localhost:2322/api?q=berlin
http://localhost:2322/api?q=berlin&lon=10&lat=52
There are two optional parameters to influence the location bias. 'zoom'
describes the radius around the center to focus on. This is a number that
should correspond roughly to the map zoom parameter of a corresponding map.
The default is zoom=16
.
The location_bias_scale
describes how much the prominence of a result should
still be taken into account. Sensible values go from 0.0 (ignore prominence
almost completely) to 1.0 (prominence has approximately the same influence).
The default is 0.2.
http://localhost:2322/api?q=berlin&lon=10&lat=52&zoom=12&location_bias_scale=0.1
http://localhost:2322/reverse?lon=10&lat=52
An optional radius parameter can be used to specify a value in kilometers to reverse geocode within. The value has to be greater than 0 and lower than 5000.
http://localhost:2322/reverse?lon=10&lat=52&radius=10
http://localhost:2322/api?q=berlin&limit=2
http://localhost:2322/api?q=berlin&lang=it
If omitted the 'accept-language' HTTP header
will be used (browsers set this by default). If neither is set the local name of the place is returned. In OpenStreetMap
data that's usually the value of the name
tag, for example the local name for Tokyo is 東京都.
Expected format is minLon,minLat,maxLon,maxLat.
http://localhost:2322/api?q=berlin&bbox=9.5,51.5,11.5,53.5
Filter results by tags and values
Note: the filter only works on principal OSM tags and not all OSM tag/value combinations can be searched. The actual list depends on the import style used for the Nominatim database (e.g. settings/import-full.style). All tag/value combinations with a property 'main' are included in the photon database.
If one or many query parameters named osm_tag
are present, photon will attempt to filter results by those tags. In general, here is the expected format (syntax) for the value of osm_tag request parameters.
- Include places with tag:
osm_tag=key:value
- Exclude places with tag:
osm_tag=!key:value
- Include places with tag key:
osm_tag=key
- Include places with tag value:
osm_tag=:value
- Exclude places with tag key:
osm_tag=!key
- Exclude places with tag value:
osm_tag=:!value
For example, to search for all places named berlin
with tag of tourism=museum
, one should construct url as follows:
http://localhost:2322/api?q=berlin&osm_tag=tourism:museum
Or, just by they key
http://localhost:2322/api?q=berlin&osm_tag=tourism
You can also use this feature for reverse geocoding. Want to see the 5 pharmacies closest to a location ?
http://localhost:2322/reverse?lon=10&lat=52&osm_tag=amenity:pharmacy&limit=5
List of available layers:
- house
- street
- locality
- district
- city
- county
- state
- country
- other (e.g. natural features)
http://localhost:2322/api?q=berlin&layer=city&layer=locality
Example above will return both cities and localities.
{
"features": [
{
"properties": {
"name": "Berlin",
"state": "Berlin",
"country": "Germany",
"countrycode": "DE",
"osm_key": "place",
"osm_value": "city",
"osm_type": "N",
"osm_id": 240109189
},
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [13.3888599, 52.5170365]
}
},
{
"properties": {
"name": "Berlin Olympic Stadium",
"street": "Olympischer Platz",
"housenumber": "3",
"postcode": "14053",
"state": "Berlin",
"country": "Germany",
"countrycode": "DE",
"osm_key": "leisure",
"osm_value": "stadium",
"osm_type": "W",
"osm_id": 38862723,
"extent": [13.23727, 52.5157151, 13.241757, 52.5135972]
},
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [13.239514674078611, 52.51467945]
}
}
]
}
The OpenSeach based version of photon has opt-in support for structured queries. See docs/structured.md for details. Please note that structured queries are disabled for photon.komoot.io.
- photon's search configuration was developed with a specific test framework. It is written in Python and hosted separately.
- R package to access photon's public API with R
- PHP Geocoder provider to access photon's public API with PHP using the GeoCoder Package