]> git.openstreetmap.org Git - nominatim.git/blob - settings/flex-base.lua
flex: simplify address configuration
[nominatim.git] / settings / flex-base.lua
1 -- Core functions for Nominatim import flex style.
2 --
3
4
5 -- The single place table.
6 place_table = osm2pgsql.define_table{
7     name = "place",
8     ids = { type = 'any', id_column = 'osm_id', type_column = 'osm_type' },
9     columns = {
10         { column = 'class', type = 'text', not_null = true },
11         { column = 'type', type = 'text', not_null = true },
12         { column = 'admin_level', type = 'smallint' },
13         { column = 'name', type = 'hstore' },
14         { column = 'address', type = 'hstore' },
15         { column = 'extratags', type = 'hstore' },
16         { column = 'geometry', type = 'geometry', projection = 'WGS84', not_null = true },
17     },
18     indexes = {}
19 }
20
21 ------------- Place class ------------------------------------------
22
23 local Place = {}
24 Place.__index = Place
25
26 function Place.new(object, geom_func)
27     local self = setmetatable({}, Place)
28     self.object = object
29     self.geom_func = geom_func
30
31     self.admin_level = tonumber(self.object:grab_tag('admin_level'))
32     if self.admin_level == nil
33        or self.admin_level <= 0 or self.admin_level > 15
34        or math.floor(self.admin_level) ~= self.admin_level then
35         self.admin_level = 15
36     end
37
38     self.num_entries = 0
39     self.has_name = false
40     self.names = {}
41     self.address = {}
42     self.extratags = {}
43
44     return self
45 end
46
47 function Place:delete(data)
48     if data.match ~= nil then
49         for k, v in pairs(self.object.tags) do
50             if data.match(k, v) then
51                 self.object.tags[k] = nil
52             end
53         end
54     end
55 end
56
57 function Place:grab_extratags(data)
58     local count = 0
59
60     if data.match ~= nil then
61         for k, v in pairs(self.object.tags) do
62             if data.match(k, v) then
63                 self.object.tags[k] = nil
64                 self.extratags[k] = v
65                 count = count + 1
66             end
67         end
68     end
69
70     return count
71 end
72
73 function Place:grab_address(data)
74     local count = 0
75
76     if data.match ~= nil then
77         for k, v in pairs(self.object.tags) do
78             if data.match(k, v) then
79                 self.object.tags[k] = nil
80
81                 if data.include_on_name == true then
82                     self.has_name = true
83                 end
84
85                 if data.out_key ~= nil then
86                     self.address[data.out_key] = v
87                     return 1
88                 end
89
90                 if k:sub(1, 5) == 'addr:' then
91                     self.address[k:sub(6)] = v
92                 elseif k:sub(1, 6) == 'is_in:' then
93                     self.address[k:sub(7)] = v
94                 else
95                     self.address[k] = v
96                 end
97                 count = count + 1
98             end
99         end
100     end
101
102     return count
103 end
104
105 local function strip_address_prefix(k)
106     if k:sub(1, 5) == 'addr:' then
107         return k:sub(6)
108     end
109
110     if k:sub(1, 6) == 'is_in:' then
111         return k:sub(7)
112     end
113
114     return k
115 end
116
117
118 function Place:grab_address_parts(data)
119     local count = 0
120
121     if data.groups ~= nil then
122         for k, v in pairs(self.object.tags) do
123             local atype = data.groups(k, v)
124
125             if atype == 'main' then
126                 self.has_name = true
127                 self.address[strip_address_prefix(k)] = v
128                 count = count + 1
129             elseif atype == 'extra' then
130                 self.address[strip_address_prefix(k)] = v
131             elseif atype ~= nil then
132                 self.address[atype] = v
133             end
134         end
135     end
136
137     return count
138 end
139
140 function Place:grab_name(data)
141     local count = 0
142
143     if data.match ~= nil then
144         for k, v in pairs(self.object.tags) do
145             if data.match(k, v) then
146                 self.object.tags[k] = nil
147                 self.names[k] = v
148                 if data.include_on_name ~= false then
149                     self.has_name = true
150                 end
151                 count = count + 1
152             end
153         end
154     end
155
156     return count
157 end
158
159 function Place:grab_tag(key)
160     return self.object:grab_tag(key)
161 end
162
163 function Place:write_place(k, v, mtype, save_extra_mains)
164     if mtype == nil then
165         return 0
166     end
167
168     v = v or self.object.tags[k]
169     if v == nil then
170         return 0
171     end
172
173     if type(mtype) == 'table' then
174         mtype = mtype[v] or mtype[1]
175     end
176
177     if mtype == 'always' or (self.has_name and mtype == 'named') then
178         return self:write_row(k, v, save_extra_mains)
179     end
180
181     if mtype == 'named_with_key' then
182         local names = {}
183         local prefix = k .. ':name'
184         for namek, namev in pairs(self.object.tags) do
185             if namek:sub(1, #prefix) == prefix
186                and (#namek == #prefix
187                     or namek:sub(#prefix + 1, #prefix + 1) == ':') then
188                 names[namek:sub(#k + 2)] = namev
189             end
190         end
191
192         if next(names) ~= nil then
193             local saved_names = self.names
194             self.names = names
195
196             local results = self:write_row(k, v, save_extra_mains)
197
198             self.names = saved_names
199
200             return results
201         end
202     end
203
204     return 0
205 end
206
207 function Place:write_row(k, v, save_extra_mains)
208     if self.geometry == nil then
209         self.geometry = self.geom_func(self.object)
210     end
211     if self.geometry:is_null() then
212         return 0
213     end
214
215     if save_extra_mains then
216         for extra_k, extra_v in pairs(self.object.tags) do
217             if extra_k ~= k then
218                 self.extratags[extra_k] = extra_v
219             end
220         end
221     end
222
223     place_table:insert{
224         class = k,
225         type = v,
226         admin_level = self.admin_level,
227         name = next(self.names) and self.names,
228         address = next(self.address) and self.address,
229         extratags = next(self.extratags) and self.extratags,
230         geometry = self.geometry
231     }
232
233     if save_extra_mains then
234         for k, v in pairs(self.object.tags) do
235             self.extratags[k] = nil
236         end
237     end
238
239     self.num_entries = self.num_entries + 1
240
241     return 1
242 end
243
244
245 function tag_match(data)
246     if data == nil or next(data) == nil then
247         return nil
248     end
249
250     local fullmatches = {}
251     local key_prefixes = {}
252     local key_suffixes = {}
253
254     if data.keys ~= nil then
255         for _, key in pairs(data.keys) do
256             if key:sub(1, 1) == '*' then
257                 if #key > 1 then
258                     if key_suffixes[#key - 1] == nil then
259                         key_suffixes[#key - 1] = {}
260                     end
261                     key_suffixes[#key - 1][key:sub(2)] = true
262                 end
263             elseif key:sub(#key, #key) == '*' then
264                 if key_prefixes[#key - 1] == nil then
265                     key_prefixes[#key - 1] = {}
266                 end
267                 key_prefixes[#key - 1][key:sub(1, #key - 1)] = true
268             else
269                 fullmatches[key] = true
270             end
271         end
272     end
273
274     if data.tags ~= nil then
275         for k, vlist in pairs(data.tags) do
276             if fullmatches[k] == nil then
277                 fullmatches[k] = {}
278                 for _, v in pairs(vlist) do
279                     fullmatches[k][v] = true
280                 end
281             end
282         end
283     end
284
285     return function (k, v)
286         if fullmatches[k] ~= nil and (fullmatches[k] == true or fullmatches[k][v] ~= nil) then
287             return true
288         end
289
290         for slen, slist in pairs(key_suffixes) do
291             if #k >= slen and slist[k:sub(-slen)] ~= nil then
292                 return true
293             end
294         end
295
296         for slen, slist in pairs(key_prefixes) do
297             if #k >= slen and slist[k:sub(1, slen)] ~= nil then
298                 return true
299             end
300         end
301
302         return false
303     end
304 end
305
306
307 function key_group(data)
308     if data == nil or next(data) == nil then
309         return nil
310     end
311
312     local fullmatches = {}
313     local key_prefixes = {}
314     local key_suffixes = {}
315
316     for group, tags in pairs(data) do
317         for _, key in pairs(tags) do
318             if key:sub(1, 1) == '*' then
319                 if #key > 1 then
320                     if key_suffixes[#key - 1] == nil then
321                         key_suffixes[#key - 1] = {}
322                     end
323                     key_suffixes[#key - 1][key:sub(2)] = group
324                 end
325             elseif key:sub(#key, #key) == '*' then
326                 if key_prefixes[#key - 1] == nil then
327                     key_prefixes[#key - 1] = {}
328                 end
329                 key_prefixes[#key - 1][key:sub(1, #key - 1)] = group
330             else
331                 fullmatches[key] = group
332             end
333         end
334     end
335
336     return function (k, v)
337         local val = fullmatches[k]
338         if val ~= nil then
339             return val
340         end
341
342         for slen, slist in pairs(key_suffixes) do
343             if #k >= slen then
344                 val = slist[k:sub(-slen)]
345                 if val ~= nil then
346                     return val
347                 end
348             end
349         end
350
351         for slen, slist in pairs(key_prefixes) do
352             if #k >= slen then
353                 val = slist[k:sub(1, slen)]
354                 if val ~= nil then
355                     return val
356                 end
357             end
358         end
359     end
360 end
361
362 -- Process functions for all data types
363 function osm2pgsql.process_node(object)
364
365     local function geom_func(o)
366         return o:as_point()
367     end
368
369     process_tags(Place.new(object, geom_func))
370 end
371
372 function osm2pgsql.process_way(object)
373
374     local function geom_func(o)
375         local geom = o:as_polygon()
376
377         if geom:is_null() then
378             geom = o:as_linestring()
379         end
380
381         return geom
382     end
383
384     process_tags(Place.new(object, geom_func))
385 end
386
387 function relation_as_multipolygon(o)
388     return o:as_multipolygon()
389 end
390
391 function relation_as_multiline(o)
392     return o:as_multilinestring():line_merge()
393 end
394
395 function osm2pgsql.process_relation(object)
396     local geom_func = RELATION_TYPES[object.tags.type]
397
398     if geom_func ~= nil then
399         process_tags(Place.new(object, geom_func))
400     end
401 end
402
403 function process_tags(o)
404     local fallback
405
406     o:delete{match = PRE_DELETE}
407     o:grab_extratags{match = PRE_EXTRAS}
408
409     -- Exception for boundary/place double tagging
410     if o.object.tags.boundary == 'administrative' then
411         o:grab_extratags{match = function (k, v)
412             return k == 'place' and v:sub(1,3) ~= 'isl'
413         end}
414     end
415
416     -- address keys
417     if o:grab_name{match=HOUSENAME_TAGS} > 0 then
418         fallback = {'place', 'house', 'always'}
419     end
420     if o:grab_address_parts{groups=ADDRESS_TAGS} > 0 and fallback == nil then
421         fallback = {'place', 'house', 'always'}
422     end
423     if o.address.country ~= nil and #o.address.country ~= 2 then
424         o.address['country'] = nil
425     end
426     if fallback == nil and o.address.postcode ~= nil then
427         fallback = {'place', 'postcode', 'always'}
428     end
429
430     if o.address.interpolation ~= nil then
431         o:write_place('place', 'houses', 'always', SAVE_EXTRA_MAINS)
432         return
433     end
434
435     -- name keys
436     o:grab_name{match = NAMES}
437     o:grab_name{match = REFS, include_on_name = false}
438
439     o:delete{match = POST_DELETE}
440     o:grab_extratags{match = POST_EXTRAS}
441
442     -- collect main keys
443     for k, v in pairs(o.object.tags) do
444         local ktype = MAIN_KEYS[k]
445         if ktype == 'fallback' then
446             if o.has_name then
447                 fallback = {k, v, 'named'}
448             end
449         elseif ktype ~= nil then
450             o:write_place(k, v, MAIN_KEYS[k], SAVE_EXTRA_MAINS)
451         end
452     end
453
454     if fallback ~= nil and o.num_entries == 0 then
455         o:write_place(fallback[1], fallback[2], fallback[3], SAVE_EXTRA_MAINS)
456     end
457 end
458
459