]> git.openstreetmap.org Git - nominatim.git/blob - settings/flex-base.lua
9663f96052aa69fa2aecbffe7c1867b1b8043f02
[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_name_parts(data)
160     local fallback = nil
161
162     if data.groups ~= nil then
163         for k, v in pairs(self.object.tags) do
164             local atype = data.groups(k, v)
165
166             if atype ~= nil then
167                 self.names[k] = v
168                 if atype == 'main' then
169                     self.has_name = true
170                 elseif atype == 'house' then
171                     self.has_name = true
172                     fallback = {'place', 'house', 'always'}
173                 end
174             end
175         end
176     end
177
178     return fallback
179 end
180
181 function Place:grab_tag(key)
182     return self.object:grab_tag(key)
183 end
184
185 function Place:write_place(k, v, mtype, save_extra_mains)
186     if mtype == nil then
187         return 0
188     end
189
190     v = v or self.object.tags[k]
191     if v == nil then
192         return 0
193     end
194
195     if type(mtype) == 'table' then
196         mtype = mtype[v] or mtype[1]
197     end
198
199     if mtype == 'always' or (self.has_name and mtype == 'named') then
200         return self:write_row(k, v, save_extra_mains)
201     end
202
203     if mtype == 'named_with_key' then
204         local names = {}
205         local prefix = k .. ':name'
206         for namek, namev in pairs(self.object.tags) do
207             if namek:sub(1, #prefix) == prefix
208                and (#namek == #prefix
209                     or namek:sub(#prefix + 1, #prefix + 1) == ':') then
210                 names[namek:sub(#k + 2)] = namev
211             end
212         end
213
214         if next(names) ~= nil then
215             local saved_names = self.names
216             self.names = names
217
218             local results = self:write_row(k, v, save_extra_mains)
219
220             self.names = saved_names
221
222             return results
223         end
224     end
225
226     return 0
227 end
228
229 function Place:write_row(k, v, save_extra_mains)
230     if self.geometry == nil then
231         self.geometry = self.geom_func(self.object)
232     end
233     if self.geometry:is_null() then
234         return 0
235     end
236
237     if save_extra_mains then
238         for extra_k, extra_v in pairs(self.object.tags) do
239             if extra_k ~= k then
240                 self.extratags[extra_k] = extra_v
241             end
242         end
243     end
244
245     place_table:insert{
246         class = k,
247         type = v,
248         admin_level = self.admin_level,
249         name = next(self.names) and self.names,
250         address = next(self.address) and self.address,
251         extratags = next(self.extratags) and self.extratags,
252         geometry = self.geometry
253     }
254
255     if save_extra_mains then
256         for k, v in pairs(self.object.tags) do
257             self.extratags[k] = nil
258         end
259     end
260
261     self.num_entries = self.num_entries + 1
262
263     return 1
264 end
265
266
267 function tag_match(data)
268     if data == nil or next(data) == nil then
269         return nil
270     end
271
272     local fullmatches = {}
273     local key_prefixes = {}
274     local key_suffixes = {}
275
276     if data.keys ~= nil then
277         for _, key in pairs(data.keys) do
278             if key:sub(1, 1) == '*' then
279                 if #key > 1 then
280                     if key_suffixes[#key - 1] == nil then
281                         key_suffixes[#key - 1] = {}
282                     end
283                     key_suffixes[#key - 1][key:sub(2)] = true
284                 end
285             elseif key:sub(#key, #key) == '*' then
286                 if key_prefixes[#key - 1] == nil then
287                     key_prefixes[#key - 1] = {}
288                 end
289                 key_prefixes[#key - 1][key:sub(1, #key - 1)] = true
290             else
291                 fullmatches[key] = true
292             end
293         end
294     end
295
296     if data.tags ~= nil then
297         for k, vlist in pairs(data.tags) do
298             if fullmatches[k] == nil then
299                 fullmatches[k] = {}
300                 for _, v in pairs(vlist) do
301                     fullmatches[k][v] = true
302                 end
303             end
304         end
305     end
306
307     return function (k, v)
308         if fullmatches[k] ~= nil and (fullmatches[k] == true or fullmatches[k][v] ~= nil) then
309             return true
310         end
311
312         for slen, slist in pairs(key_suffixes) do
313             if #k >= slen and slist[k:sub(-slen)] ~= nil then
314                 return true
315             end
316         end
317
318         for slen, slist in pairs(key_prefixes) do
319             if #k >= slen and slist[k:sub(1, slen)] ~= nil then
320                 return true
321             end
322         end
323
324         return false
325     end
326 end
327
328
329 function key_group(data)
330     if data == nil or next(data) == nil then
331         return nil
332     end
333
334     local fullmatches = {}
335     local key_prefixes = {}
336     local key_suffixes = {}
337
338     for group, tags in pairs(data) do
339         for _, key in pairs(tags) do
340             if key:sub(1, 1) == '*' then
341                 if #key > 1 then
342                     if key_suffixes[#key - 1] == nil then
343                         key_suffixes[#key - 1] = {}
344                     end
345                     key_suffixes[#key - 1][key:sub(2)] = group
346                 end
347             elseif key:sub(#key, #key) == '*' then
348                 if key_prefixes[#key - 1] == nil then
349                     key_prefixes[#key - 1] = {}
350                 end
351                 key_prefixes[#key - 1][key:sub(1, #key - 1)] = group
352             else
353                 fullmatches[key] = group
354             end
355         end
356     end
357
358     return function (k, v)
359         local val = fullmatches[k]
360         if val ~= nil then
361             return val
362         end
363
364         for slen, slist in pairs(key_suffixes) do
365             if #k >= slen then
366                 val = slist[k:sub(-slen)]
367                 if val ~= nil then
368                     return val
369                 end
370             end
371         end
372
373         for slen, slist in pairs(key_prefixes) do
374             if #k >= slen then
375                 val = slist[k:sub(1, slen)]
376                 if val ~= nil then
377                     return val
378                 end
379             end
380         end
381     end
382 end
383
384 -- Process functions for all data types
385 function osm2pgsql.process_node(object)
386
387     local function geom_func(o)
388         return o:as_point()
389     end
390
391     process_tags(Place.new(object, geom_func))
392 end
393
394 function osm2pgsql.process_way(object)
395
396     local function geom_func(o)
397         local geom = o:as_polygon()
398
399         if geom:is_null() then
400             geom = o:as_linestring()
401         end
402
403         return geom
404     end
405
406     process_tags(Place.new(object, geom_func))
407 end
408
409 function relation_as_multipolygon(o)
410     return o:as_multipolygon()
411 end
412
413 function relation_as_multiline(o)
414     return o:as_multilinestring():line_merge()
415 end
416
417 function osm2pgsql.process_relation(object)
418     local geom_func = RELATION_TYPES[object.tags.type]
419
420     if geom_func ~= nil then
421         process_tags(Place.new(object, geom_func))
422     end
423 end
424
425 function process_tags(o)
426     o:delete{match = PRE_DELETE}
427     o:grab_extratags{match = PRE_EXTRAS}
428
429     -- Exception for boundary/place double tagging
430     if o.object.tags.boundary == 'administrative' then
431         o:grab_extratags{match = function (k, v)
432             return k == 'place' and v:sub(1,3) ~= 'isl'
433         end}
434     end
435
436     -- name keys
437     local fallback = o:grab_name_parts{groups=NAMES}
438
439     -- address keys
440     if o:grab_address_parts{groups=ADDRESS_TAGS} > 0 and fallback == nil then
441         fallback = {'place', 'house', 'always'}
442     end
443     if o.address.country ~= nil and #o.address.country ~= 2 then
444         o.address['country'] = nil
445     end
446     if fallback == nil and o.address.postcode ~= nil then
447         fallback = {'place', 'postcode', 'always'}
448     end
449
450     if o.address.interpolation ~= nil then
451         o:write_place('place', 'houses', 'always', SAVE_EXTRA_MAINS)
452         return
453     end
454
455     o:delete{match = POST_DELETE}
456     o:grab_extratags{match = POST_EXTRAS}
457
458     -- collect main keys
459     for k, v in pairs(o.object.tags) do
460         local ktype = MAIN_KEYS[k]
461         if ktype == 'fallback' then
462             if o.has_name then
463                 fallback = {k, v, 'named'}
464             end
465         elseif ktype ~= nil then
466             o:write_place(k, v, MAIN_KEYS[k], SAVE_EXTRA_MAINS)
467         end
468     end
469
470     if fallback ~= nil and o.num_entries == 0 then
471         o:write_place(fallback[1], fallback[2], fallback[3], SAVE_EXTRA_MAINS)
472     end
473 end
474
475