]> git.openstreetmap.org Git - nominatim.git/blob - docs/customize/Tokenizers.md
add documentation for housenumber analyzer
[nominatim.git] / docs / customize / Tokenizers.md
1 # Tokenizers
2
3 The tokenizer module in Nominatim is responsible for analysing the names given
4 to OSM objects and the terms of an incoming query in order to make sure, they
5 can be matched appropriately.
6
7 Nominatim offers different tokenizer modules, which behave differently and have
8 different configuration options. This sections describes the tokenizers and how
9 they can be configured.
10
11 !!! important
12     The use of a tokenizer is tied to a database installation. You need to choose
13     and configure the tokenizer before starting the initial import. Once the import
14     is done, you cannot switch to another tokenizer anymore. Reconfiguring the
15     chosen tokenizer is very limited as well. See the comments in each tokenizer
16     section.
17
18 ## Legacy tokenizer
19
20 The legacy tokenizer implements the analysis algorithms of older Nominatim
21 versions. It uses a special Postgresql module to normalize names and queries.
22 This tokenizer is currently the default.
23
24 To enable the tokenizer add the following line to your project configuration:
25
26 ```
27 NOMINATIM_TOKENIZER=legacy
28 ```
29
30 The Postgresql module for the tokenizer is available in the `module` directory
31 and also installed with the remainder of the software under
32 `lib/nominatim/module/nominatim.so`. You can specify a custom location for
33 the module with
34
35 ```
36 NOMINATIM_DATABASE_MODULE_PATH=<path to directory where nominatim.so resides>
37 ```
38
39 This is in particular useful when the database runs on a different server.
40 See [Advanced installations](../admin/Advanced-Installations.md#importing-nominatim-to-an-external-postgresql-database) for details.
41
42 There are no other configuration options for the legacy tokenizer. All
43 normalization functions are hard-coded.
44
45 ## ICU tokenizer
46
47 The ICU tokenizer uses the [ICU library](http://site.icu-project.org/) to
48 normalize names and queries. It also offers configurable decomposition and
49 abbreviation handling.
50
51 To enable the tokenizer add the following line to your project configuration:
52
53 ```
54 NOMINATIM_TOKENIZER=icu
55 ```
56
57 ### How it works
58
59 On import the tokenizer processes names in the following three stages:
60
61 1. During the **Sanitizer step** incoming names are cleaned up and converted to
62    **full names**. This step can be used to regularize spelling, split multi-name
63    tags into their parts and tag names with additional attributes. See the
64    [Sanitizers section](#sanitizers) below for available cleaning routines.
65 2. The **Normalization** part removes all information from the full names
66    that are not relevant for search.
67 3. The **Token analysis** step takes the normalized full names and creates
68    all transliterated variants under which the name should be searchable.
69    See the [Token analysis](#token-analysis) section below for more
70    information.
71
72 During query time, only normalization and transliteration are relevant.
73 An incoming query is first split into name chunks (this usually means splitting
74 the string at the commas) and the each part is normalised and transliterated.
75 The result is used to look up places in the search index.
76
77 ### Configuration
78
79 The ICU tokenizer is configured using a YAML file which can be configured using
80 `NOMINATIM_TOKENIZER_CONFIG`. The configuration is read on import and then
81 saved as part of the internal database status. Later changes to the variable
82 have no effect.
83
84 Here is an example configuration file:
85
86 ``` yaml
87 normalization:
88     - ":: lower ()"
89     - "ß > 'ss'" # German szet is unimbigiously equal to double ss
90 transliteration:
91     - !include /etc/nominatim/icu-rules/extended-unicode-to-asccii.yaml
92     - ":: Ascii ()"
93 sanitizers:
94     - step: split-name-list
95 token-analysis:
96     - analyzer: generic
97       variants:
98           - !include icu-rules/variants-ca.yaml
99           - words:
100               - road -> rd
101               - bridge -> bdge,br,brdg,bri,brg
102       mutations:
103           - pattern: 'ä'
104             replacements: ['ä', 'ae']
105 ```
106
107 The configuration file contains four sections:
108 `normalization`, `transliteration`, `sanitizers` and `token-analysis`.
109
110 #### Normalization and Transliteration
111
112 The normalization and transliteration sections each define a set of
113 ICU rules that are applied to the names.
114
115 The **normalisation** rules are applied after sanitation. They should remove
116 any information that is not relevant for search at all. Usual rules to be
117 applied here are: lower-casing, removing of special characters, cleanup of
118 spaces.
119
120 The **transliteration** rules are applied at the end of the tokenization
121 process to transfer the name into an ASCII representation. Transliteration can
122 be useful to allow for further fuzzy matching, especially between different
123 scripts.
124
125 Each section must contain a list of
126 [ICU transformation rules](https://unicode-org.github.io/icu/userguide/transforms/general/rules.html).
127 The rules are applied in the order in which they appear in the file.
128 You can also include additional rules from external yaml file using the
129 `!include` tag. The included file must contain a valid YAML list of ICU rules
130 and may again include other files.
131
132 !!! warning
133     The ICU rule syntax contains special characters that conflict with the
134     YAML syntax. You should therefore always enclose the ICU rules in
135     double-quotes.
136
137 #### Sanitizers
138
139 The sanitizers section defines an ordered list of functions that are applied
140 to the name and address tags before they are further processed by the tokenizer.
141 They allows to clean up the tagging and bring it to a standardized form more
142 suitable for building the search index.
143
144 !!! hint
145     Sanitizers only have an effect on how the search index is built. They
146     do not change the information about each place that is saved in the
147     database. In particular, they have no influence on how the results are
148     displayed. The returned results always show the original information as
149     stored in the OpenStreetMap database.
150
151 Each entry contains information of a sanitizer to be applied. It has a
152 mandatory parameter `step` which gives the name of the sanitizer. Depending
153 on the type, it may have additional parameters to configure its operation.
154
155 The order of the list matters. The sanitizers are applied exactly in the order
156 that is configured. Each sanitizer works on the results of the previous one.
157
158 The following is a list of sanitizers that are shipped with Nominatim.
159
160 ##### split-name-list
161
162 ::: nominatim.tokenizer.sanitizers.split_name_list
163     selection:
164         members: False
165     rendering:
166         heading_level: 6
167
168 ##### strip-brace-terms
169
170 ::: nominatim.tokenizer.sanitizers.strip_brace_terms
171     selection:
172         members: False
173     rendering:
174         heading_level: 6
175
176 ##### tag-analyzer-by-language
177
178 ::: nominatim.tokenizer.sanitizers.tag_analyzer_by_language
179     selection:
180         members: False
181     rendering:
182         heading_level: 6
183
184 ##### clean-housenumbers
185
186 ::: nominatim.tokenizer.sanitizers.clean_housenumbers
187     selection:
188         members: False
189     rendering:
190         heading_level: 6
191
192
193 #### Token Analysis
194
195 Token analyzers take a full name and transform it into one or more normalized
196 form that are then saved in the search index. In its simplest form, the
197 analyzer only applies the transliteration rules. More complex analyzers
198 create additional spelling variants of a name. This is useful to handle
199 decomposition and abbreviation.
200
201 The ICU tokenizer may use different analyzers for different names. To select
202 the analyzer to be used, the name must be tagged with the `analyzer` attribute
203 by a sanitizer (see for example the
204 [tag-analyzer-by-language sanitizer](#tag-analyzer-by-language)).
205
206 The token-analysis section contains the list of configured analyzers. Each
207 analyzer must have an `id` parameter that uniquely identifies the analyzer.
208 The only exception is the default analyzer that is used when no special
209 analyzer was selected. There is one special id '@housenumber'. If an analyzer
210 with that name is present, it is used for normalization of house numbers.
211
212 Different analyzer implementations may exist. To select the implementation,
213 the `analyzer` parameter must be set. The different implementations are
214 described in the following.
215
216 ##### Generic token analyzer
217
218 The generic analyzer `generic` is able to create variants from a list of given
219 abbreviation and decomposition replacements and introduce spelling variations.
220
221 ###### Variants
222
223 The optional 'variants' section defines lists of replacements which create alternative
224 spellings of a name. To create the variants, a name is scanned from left to
225 right and the longest matching replacement is applied until the end of the
226 string is reached.
227
228 The variants section must contain a list of replacement groups. Each group
229 defines a set of properties that describes where the replacements are
230 applicable. In addition, the word section defines the list of replacements
231 to be made. The basic replacement description is of the form:
232
233 ```
234 <source>[,<source>[...]] => <target>[,<target>[...]]
235 ```
236
237 The left side contains one or more `source` terms to be replaced. The right side
238 lists one or more replacements. Each source is replaced with each replacement
239 term.
240
241 !!! tip
242     The source and target terms are internally normalized using the
243     normalization rules given in the configuration. This ensures that the
244     strings match as expected. In fact, it is better to use unnormalized
245     words in the configuration because then it is possible to change the
246     rules for normalization later without having to adapt the variant rules.
247
248 ###### Decomposition
249
250 In its standard form, only full words match against the source. There
251 is a special notation to match the prefix and suffix of a word:
252
253 ``` yaml
254 - ~strasse => str  # matches "strasse" as full word and in suffix position
255 - hinter~ => hntr  # matches "hinter" as full word and in prefix position
256 ```
257
258 There is no facility to match a string in the middle of the word. The suffix
259 and prefix notation automatically trigger the decomposition mode: two variants
260 are created for each replacement, one with the replacement attached to the word
261 and one separate. So in above example, the tokenization of "hauptstrasse" will
262 create the variants "hauptstr" and "haupt str". Similarly, the name "rote strasse"
263 triggers the variants "rote str" and "rotestr". By having decomposition work
264 both ways, it is sufficient to create the variants at index time. The variant
265 rules are not applied at query time.
266
267 To avoid automatic decomposition, use the '|' notation:
268
269 ``` yaml
270 - ~strasse |=> str
271 ```
272
273 simply changes "hauptstrasse" to "hauptstr" and "rote strasse" to "rote str".
274
275 ###### Initial and final terms
276
277 It is also possible to restrict replacements to the beginning and end of a
278 name:
279
280 ``` yaml
281 - ^south => s  # matches only at the beginning of the name
282 - road$ => rd  # matches only at the end of the name
283 ```
284
285 So the first example would trigger a replacement for "south 45th street" but
286 not for "the south beach restaurant".
287
288 ###### Replacements vs. variants
289
290 The replacement syntax `source => target` works as a pure replacement. It changes
291 the name instead of creating a variant. To create an additional version, you'd
292 have to write `source => source,target`. As this is a frequent case, there is
293 a shortcut notation for it:
294
295 ```
296 <source>[,<source>[...]] -> <target>[,<target>[...]]
297 ```
298
299 The simple arrow causes an additional variant to be added. Note that
300 decomposition has an effect here on the source as well. So a rule
301
302 ``` yaml
303 - "~strasse -> str"
304 ```
305
306 means that for a word like `hauptstrasse` four variants are created:
307 `hauptstrasse`, `haupt strasse`, `hauptstr` and `haupt str`.
308
309 ###### Mutations
310
311 The 'mutation' section in the configuration describes an additional set of
312 replacements to be applied after the variants have been computed.
313
314 Each mutation is described by two parameters: `pattern` and `replacements`.
315 The pattern must contain a single regular expression to search for in the
316 variant name. The regular expressions need to follow the syntax for
317 [Python regular expressions](file:///usr/share/doc/python3-doc/html/library/re.html#regular-expression-syntax).
318 Capturing groups are not permitted.
319 `replacements` must contain a list of strings that the pattern
320 should be replaced with. Each occurrence of the pattern is replaced with
321 all given replacements. Be mindful of combinatorial explosion of variants.
322
323 ###### Modes
324
325 The generic analyser supports a special mode `variant-only`. When configured
326 then it consumes the input token and emits only variants (if any exist). Enable
327 the mode by adding:
328
329 ```
330   mode: variant-only
331 ```
332
333 to the analyser configuration.
334
335 ##### Housenumber token analyzer
336
337 The analyzer `housenumbers` is purpose-made to analyze house numbers. It
338 creates variants with optional spaces between numbers and letters. Thus,
339 house numbers of the form '3 a', '3A', '3-A' etc. are all considered equivalent.
340
341 The analyzer cannot be customized.
342
343 ### Reconfiguration
344
345 Changing the configuration after the import is currently not possible, although
346 this feature may be added at a later time.