]> git.openstreetmap.org Git - nominatim.git/blob - docs/library/Getting-Started.md
docs: rework library getting started
[nominatim.git] / docs / library / Getting-Started.md
1 # Getting Started
2
3 The Nominatim search frontend is implemented as a Python library and can as
4 such directly be used in Python scripts and applications. You don't need to
5 set up a web frontend and access it through HTTP calls. The library gives
6 direct access to the Nominatim database through similar search functions as
7 offered by the web API. In addition, it will give you a more complete and
8 detailed view on the search objects stored in the database.
9
10 !!! warning
11
12     The Nominatim library is used for accessing a local Nominatim database.
13     It is not meant to be used against web services of Nominatim like the
14     one on https://nominatim.openstreetmap.org. If you need a Python library
15     to access these web services, have a look at
16     [GeoPy](https://geopy.readthedocs.io). Don't forget to consult the
17     usage policy of the service you want to use before accessing such
18     a web service.
19
20 ## Installation
21
22 To use the Nominatim library, you need access to a local Nominatim database.
23 Follow the [installation](../admin/Installation.md) and
24 [import](../admin/Import.md) instructions to set up your database.
25
26 The Nominatim frontend library is contained in the Python package `nominatim-api`.
27 You can install the latest released version directly from pip:
28
29     pip install nominatim-api
30
31 To install the package from the source tree directly, run:
32
33     pip install packaging/nominatim-api
34
35 Usually you would want to run this in a virtual environment.
36
37 ### A simple search example
38
39 To query the Nominatim database you need to first set up a connection. This
40 is done by creating an Nominatim API object. This object exposes all the
41 search functions of Nominatim that are also known from its web API.
42
43 This code snippet implements a simple search for the town of 'Brugge':
44
45 !!! example
46     === "NominatimAPIAsync"
47         ``` python
48         import asyncio
49
50         import nominatim_api as napi
51
52         async def search(query):
53             async with napi.NominatimAPIAsync() as api:
54                 return await api.search(query)
55
56         results = asyncio.run(search('Brugge'))
57         if not results:
58             print('Cannot find Brugge')
59         else:
60             print(f'Found a place at {results[0].centroid.x},{results[0].centroid.y}')
61         ```
62
63     === "NominatimAPI"
64         ``` python
65         import nominatim_api as napi
66
67         with napi.NominatimAPI() as api:
68             results = api.search('Brugge')
69
70         if not results:
71             print('Cannot find Brugge')
72         else:
73             print(f'Found a place at {results[0].centroid.x},{results[0].centroid.y}')
74         ```
75
76 The Nominatim library is designed around
77 [asyncio](https://docs.python.org/3/library/asyncio.html). `NominatimAPIAsync`
78 provides you with an interface of coroutines.
79 If you have many requests to make, coroutines can speed up your applications
80 significantly.
81
82 For smaller scripts there is also a synchronous wrapper around the API. By
83 using `NominatimAPI`, you get exactly the same interface using classic functions.
84
85 The examples in this chapter will always show-case both
86 implementations. The documentation itself will usually refer only to
87 'Nominatim API class' when both flavours are meant. If a functionality is
88 available only for the synchronous or asynchronous version, this will be
89 explicitly mentioned.
90
91 ### Defining which database to use
92
93 The [Configuration](../admin/Import.md#configuration-setup-in-env)
94 section explains how Nominatim is configured using the
95 [dotenv](https://github.com/theskumar/python-dotenv) library.
96 The same configuration mechanism is used with the
97 Nominatim API library. You should therefore be sure you are familiar with
98 the section.
99
100 There are three different ways, how configuration options can be set for
101 a 'Nominatim API class'. When you have set up your Nominatim database, you
102 have normally created a [project directory](../admin/Import.md#creating-the-project-directory)
103 which stores the various configuration and customization files that Nominatim
104 needs. You may pass the location of the project directory to your
105 'Nominatim API class' constructor and it will read the .env file in the
106 directory and set the configuration accordingly.
107
108 You may also configure Nominatim by setting environment variables.
109 Normally Nominatim will check the operating system environment. Lets
110 say you want to look up 'Brugge' in the special database named 'belgium' instead of the
111 standard 'nominatim' database. You can run the example script above like this:
112
113 ```
114 NOMINATIM_DATABASE_DSN=pgsql:dbname=belgium python3 example.py
115 ```
116
117 The third option to configure the library is to hand in the configuration
118 parameters into the 'Nominatim API class'. Changing the database would look
119 like this:
120
121 !!! example
122     === "NominatimAPIAsync"
123         ``` python
124         import asyncio
125         import nominatim_api as napi
126
127         config_params = {
128             'NOMINATIM_DATABASE_DSN': 'pgsql:dbname=belgium'
129         }
130
131         async def search(query):
132             async with napi.NominatimAPIAsync(environ=config_params) as api:
133                 return await api.search(query)
134
135         results = asyncio.run(search('Brugge'))
136         ```
137
138     === "NominatimAPI"
139         ``` python
140         import nominatim_api as napi
141
142         config_params = {
143             'NOMINATIM_DATABASE_DSN': 'pgsql:dbname=belgium'
144         }
145
146         with napi.NominatimAPI(environ=config_params) as api:
147             results = api.search('Brugge')
148         ```
149
150 When the `environ` parameter is given, then only configuration variables
151 from this dictionary will be used.
152
153 ### Presenting results to humans
154
155 All search functions return full result objects from the database. Such a
156 result object contains lots of details: names, address information, OSM tags etc.
157 This gives you lots of flexibility what to do with the results.
158
159 One of the most common things to get is some kind of human-readable label
160 that describes the result in a compact form. Usually this would be the name
161 of the object and some parts of the address to explain where in the world
162 it is. To create such a label, you need two things:
163
164 * the address details of the place
165 * all names for the label adapted to the language you wish to use for display
166
167 Again searching for 'Brugge', this time with a nicely formatted result:
168
169 !!! example
170     === "NominatimAPIAsync"
171         ``` python
172         import asyncio
173
174         import nominatim_api as napi
175
176         async def search(query):
177             async with napi.NominatimAPIAsync() as api:
178                 return await api.search(query, address_details=True)
179
180         results = asyncio.run(search('Brugge'))
181
182         locale = napi.Locales(['fr', 'en'])
183         for i, result in enumerate(results):
184             address_parts = result.address_rows.localize(locale)
185             print(f"{i + 1}. {', '.join(address_parts)}")
186         ```
187
188     === "NominatimAPI"
189         ``` python
190         import nominatim_api as napi
191
192         with napi.NominatimAPI() as api:
193             results = api.search('Brugge', address_details=True)
194
195         locale = napi.Locales(['fr', 'en'])
196         for i, result in enumerate(results):
197             address_parts = result.address_rows.localize(locale)
198             print(f"{i + 1}. {', '.join(address_parts)}")
199         ```
200
201 To request information about the address of a result, add the optional
202 parameter 'address_details' to your search:
203
204 ``` python
205 >>> results = api.search('Brugge', address_details=True)
206 ```
207
208 An additional field `address_rows` will set in results that are returned.
209 It contains a list of all places that make up the address of the place. For
210 simplicity, this includes name and house number of the place itself. With
211 the names in this list it is possible to create a human-readable description
212 of the result. To do that, you first need to decide in which language the
213 results should be presented. As with the names in the result itself, the
214 places in `address_rows` contain all possible name translation for each row.
215
216 The library has a helper class `Locale` which helps extracting a name of a
217 place in the preferred language. It takes a single parameter with a list
218 of language codes in the order of preference. So
219
220 ``` python
221 locale = napi.Locale(['fr', 'en'])
222 ```
223
224 creates a helper class that returns the name preferably in French. If that is
225 not possible, it tries English and eventually falls back to the default `name`
226 or `ref`.
227
228 The `Locale` object can be applied to a name dictionary to return the best-matching
229 name out of it:
230
231 ``` python
232 >>> print(locale.display_name(results[0].names))
233 'Brugges'
234 ```
235
236 The `address_row` field has a helper function to apply the function to all
237 its members and save the result in the `local_name` field. It also returns
238 all the localized names as a convenient simple list. This list can be used
239 to create a human-readable output:
240
241 ``` python
242 >>> address_parts = results[0].address_rows.localize(locale)
243 >>> print(', '.join(address_parts))
244 Bruges, Flandre-Occidentale, Flandre, Belgique
245 ```
246
247 This is a fairly simple way to create a human-readable description. The
248 place information in `address_rows` contains further information about each
249 place. For example, which OSM `admin_level` was used, what category the place
250 belongs to or what rank Nominatim has assigned. Use this to adapt the output
251 to local address formats.
252
253 For more information on address rows, see
254 [detailed address description](Result-Handling.md#detailed-address-description).