]> git.openstreetmap.org Git - nominatim.git/blob - docs/library/Getting-Started.md
Merge pull request #3554 from lonvia/postcode-bbox
[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. Here is the simple search
107 example, using the configuration from a pre-defined project directory in
108 `/srv/nominatim-project`:
109
110 !!! example
111     === "NominatimAPIAsync"
112         ``` python
113         import asyncio
114
115         import nominatim_api as napi
116
117         async def search(query):
118             async with napi.NominatimAPIAsync('/srv/nominatim-project') as api:
119                 return await api.search(query)
120
121         results = asyncio.run(search('Brugge'))
122         if not results:
123             print('Cannot find Brugge')
124         else:
125             print(f'Found a place at {results[0].centroid.x},{results[0].centroid.y}')
126         ```
127
128     === "NominatimAPI"
129         ``` python
130         import nominatim_api as napi
131
132         with napi.NominatimAPI('/srv/nominatim-project') as api:
133             results = api.search('Brugge')
134
135         if not results:
136             print('Cannot find Brugge')
137         else:
138             print(f'Found a place at {results[0].centroid.x},{results[0].centroid.y}')
139         ```
140
141
142 You may also configure Nominatim by setting environment variables.
143 Normally Nominatim will check the operating system environment. Lets
144 say you want to look up 'Brugge' in the special database named 'belgium' instead of the
145 standard 'nominatim' database. You can run the example script above like this:
146
147 ```
148 NOMINATIM_DATABASE_DSN=pgsql:dbname=belgium python3 example.py
149 ```
150
151 The third option to configure the library is to hand in the configuration
152 parameters into the 'Nominatim API class'. Changing the database would look
153 like this:
154
155 !!! example
156     === "NominatimAPIAsync"
157         ``` python
158         import asyncio
159         import nominatim_api as napi
160
161         config_params = {
162             'NOMINATIM_DATABASE_DSN': 'pgsql:dbname=belgium'
163         }
164
165         async def search(query):
166             async with napi.NominatimAPIAsync(environ=config_params) as api:
167                 return await api.search(query)
168
169         results = asyncio.run(search('Brugge'))
170         ```
171
172     === "NominatimAPI"
173         ``` python
174         import nominatim_api as napi
175
176         config_params = {
177             'NOMINATIM_DATABASE_DSN': 'pgsql:dbname=belgium'
178         }
179
180         with napi.NominatimAPI(environ=config_params) as api:
181             results = api.search('Brugge')
182         ```
183
184 When the `environ` parameter is given, then only configuration variables
185 from this dictionary will be used. The operating system's environment
186 variables will be ignored.
187
188 ## Presenting results to humans
189
190 All search functions return full result objects from the database. Such a
191 result object contains lots of details: names, address information, OSM tags etc.
192 This gives you lots of flexibility what to do with the results.
193
194 One of the most common things to get is some kind of human-readable label
195 that describes the result in a compact form. Usually this would be the name
196 of the object and some parts of the address to explain where in the world
197 it is. To create such a label, you need two things:
198
199 * the address details of the place
200 * all names for the label adapted to the language you wish to use for display
201
202 Again searching for 'Brugge', this time with a nicely formatted result:
203
204 !!! example
205     === "NominatimAPIAsync"
206         ``` python
207         import asyncio
208
209         import nominatim_api as napi
210
211         async def search(query):
212             async with napi.NominatimAPIAsync() as api:
213                 return await api.search(query, address_details=True)
214
215         results = asyncio.run(search('Brugge'))
216
217         locale = napi.Locales(['fr', 'en'])
218         for i, result in enumerate(results):
219             address_parts = result.address_rows.localize(locale)
220             print(f"{i + 1}. {', '.join(address_parts)}")
221         ```
222
223     === "NominatimAPI"
224         ``` python
225         import nominatim_api as napi
226
227         with napi.NominatimAPI() as api:
228             results = api.search('Brugge', address_details=True)
229
230         locale = napi.Locales(['fr', 'en'])
231         for i, result in enumerate(results):
232             address_parts = result.address_rows.localize(locale)
233             print(f"{i + 1}. {', '.join(address_parts)}")
234         ```
235
236 To request information about the address of a result, add the optional
237 parameter 'address_details' to your search:
238
239 ``` python
240 >>> results = api.search('Brugge', address_details=True)
241 ```
242
243 An additional field `address_rows` will set in results that are returned.
244 It contains a list of all places that make up the address of the place. For
245 simplicity, this includes name and house number of the place itself. With
246 the names in this list it is possible to create a human-readable description
247 of the result. To do that, you first need to decide in which language the
248 results should be presented. As with the names in the result itself, the
249 places in `address_rows` contain all possible name translation for each row.
250
251 The library has a helper class `Locale` which helps extracting a name of a
252 place in the preferred language. It takes a single parameter with a list
253 of language codes in the order of preference. So
254
255 ``` python
256 locale = napi.Locale(['fr', 'en'])
257 ```
258
259 creates a helper class that returns the name preferably in French. If that is
260 not possible, it tries English and eventually falls back to the default `name`
261 or `ref`.
262
263 The `Locale` object can be applied to a name dictionary to return the best-matching
264 name out of it:
265
266 ``` python
267 >>> print(locale.display_name(results[0].names))
268 'Brugges'
269 ```
270
271 The `address_row` field has a helper function to apply the function to all
272 its members and save the result in the `local_name` field. It also returns
273 all the localized names as a convenient simple list. This list can be used
274 to create a human-readable output:
275
276 ``` python
277 >>> address_parts = results[0].address_rows.localize(locale)
278 >>> print(', '.join(address_parts))
279 Bruges, Flandre-Occidentale, Flandre, Belgique
280 ```
281
282 This is a fairly simple way to create a human-readable description. The
283 place information in `address_rows` contains further information about each
284 place. For example, which OSM `admin_level` was used, what category the place
285 belongs to or what rank Nominatim has assigned. Use this to adapt the output
286 to local address formats.
287
288 For more information on address rows, see
289 [detailed address description](Result-Handling.md#detailed-address-description).