]> git.openstreetmap.org Git - nominatim.git/blob - settings/flex-base.lua
update osm2pgsql (flex not building index)
[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 function Place:set_address(key, value)
106     self.address[key] = value
107 end
108
109 function Place:grab_name(data)
110     local count = 0
111
112     if data.match ~= nil then
113         for k, v in pairs(self.object.tags) do
114             if data.match(k, v) then
115                 self.object.tags[k] = nil
116                 self.names[k] = v
117                 if data.include_on_name ~= false then
118                     self.has_name = true
119                 end
120                 count = count + 1
121             end
122         end
123     end
124
125     return count
126 end
127
128 function Place:grab_tag(key)
129     return self.object:grab_tag(key)
130 end
131
132 function Place:tags()
133     return self.object.tags
134 end
135
136 function Place:write_place(k, v, mtype, save_extra_mains)
137     if mtype == nil then
138         return 0
139     end
140
141     v = v or self.object.tags[k]
142     if v == nil then
143         return 0
144     end
145
146     if type(mtype) == 'table' then
147         mtype = mtype[v] or mtype[1]
148     end
149
150     if mtype == 'always' or (self.has_name and mtype == 'named') then
151         return self:write_row(k, v, save_extra_mains)
152     end
153
154     if mtype == 'named_with_key' then
155         local names = {}
156         local prefix = k .. ':name'
157         for namek, namev in pairs(self.object.tags) do
158             if namek:sub(1, #prefix) == prefix
159                and (#namek == #prefix
160                     or namek:sub(#prefix + 1, #prefix + 1) == ':') then
161                 names[namek:sub(#k + 2)] = namev
162             end
163         end
164
165         if next(names) ~= nil then
166             local saved_names = self.names
167             self.names = names
168
169             local results = self:write_row(k, v, save_extra_mains)
170
171             self.names = saved_names
172
173             return results
174         end
175     end
176
177     return 0
178 end
179
180 function Place:write_row(k, v, save_extra_mains)
181     if self.geometry == nil then
182         self.geometry = self.geom_func(self.object)
183     end
184     if self.geometry:is_null() then
185         return 0
186     end
187
188     if save_extra_mains then
189         for extra_k, extra_v in pairs(self.object.tags) do
190             if extra_k ~= k then
191                 self.extratags[extra_k] = extra_v
192             end
193         end
194     end
195
196     place_table:insert{
197         class = k,
198         type = v,
199         admin_level = self.admin_level,
200         name = next(self.names) and self.names,
201         address = next(self.address) and self.address,
202         extratags = next(self.extratags) and self.extratags,
203         geometry = self.geometry
204     }
205
206     if save_extra_mains then
207         for k, v in pairs(self.object.tags) do
208             self.extratags[k] = nil
209         end
210     end
211
212     self.num_entries = self.num_entries + 1
213
214     return 1
215 end
216
217
218 function tag_match(data)
219     if data == nil or next(data) == nil then
220         return nil
221     end
222
223     local fullmatches = {}
224     local key_prefixes = {}
225     local key_suffixes = {}
226
227     if data.keys ~= nil then
228         for _, key in pairs(data.keys) do
229             if key:sub(1, 1) == '*' then
230                 if #key > 1 then
231                     if key_suffixes[#key - 1] == nil then
232                         key_suffixes[#key - 1] = {}
233                     end
234                     key_suffixes[#key - 1][key:sub(2)] = true
235                 end
236             elseif key:sub(#key, #key) == '*' then
237                 if key_prefixes[#key - 1] == nil then
238                     key_prefixes[#key - 1] = {}
239                 end
240                 key_prefixes[#key - 1][key:sub(1, #key - 1)] = true
241             else
242                 fullmatches[key] = true
243             end
244         end
245     end
246
247     if data.tags ~= nil then
248         for k, vlist in pairs(data.tags) do
249             if fullmatches[k] == nil then
250                 fullmatches[k] = {}
251                 for _, v in pairs(vlist) do
252                     fullmatches[k][v] = true
253                 end
254             end
255         end
256     end
257
258     return function (k, v)
259         if fullmatches[k] ~= nil and (fullmatches[k] == true or fullmatches[k][v] ~= nil) then
260             return true
261         end
262
263         for slen, slist in pairs(key_suffixes) do
264             if #k >= slen and slist[k:sub(-slen)] ~= nil then
265                 return true
266             end
267         end
268
269         for slen, slist in pairs(key_prefixes) do
270             if #k >= slen and slist[k:sub(1, slen)] ~= nil then
271                 return true
272             end
273         end
274
275         return false
276     end
277 end
278
279
280 -- Process functions for all data types
281 function osm2pgsql.process_node(object)
282
283     local function geom_func(o)
284         return o:as_point()
285     end
286
287     process_tags(Place.new(object, geom_func))
288 end
289
290 function osm2pgsql.process_way(object)
291
292     local function geom_func(o)
293         local geom = o:as_polygon()
294
295         if geom:is_null() then
296             geom = o:as_linestring()
297         end
298
299         return geom
300     end
301
302     process_tags(Place.new(object, geom_func))
303 end
304
305 function relation_as_multipolygon(o)
306     return o:as_multipolygon()
307 end
308
309 function relation_as_multiline(o)
310     return o:as_multilinestring():line_merge()
311 end
312
313 function osm2pgsql.process_relation(object)
314     local geom_func = RELATION_TYPES[object.tags.type]
315
316     if geom_func ~= nil then
317         process_tags(Place.new(object, geom_func))
318     end
319 end
320
321 function process_tags(o)
322     local fallback
323
324     o:delete{match = PRE_DELETE}
325     o:grab_extratags{match = PRE_EXTRAS}
326
327     -- Exception for boundary/place double tagging
328     if o.object.tags.boundary == 'administrative' then
329         o:grab_extratags{match = function (k, v)
330             return k == 'place' and v:sub(1,3) ~= 'isl'
331         end}
332     end
333
334     -- address keys
335     o:grab_address{match=COUNTRY_TAGS, out_key='country'}
336     if o.address.country ~= nil and #o.address.country ~= 2 then
337         o.address['country'] = nil
338     end
339     if o:grab_name{match=HOUSENAME_TAGS} > 0 then
340         fallback = {'place', 'house'}
341     end
342     if o:grab_address{match=HOUSENUMBER_TAGS, include_on_name = true} > 0 and fallback == nil then
343         fallback = {'place', 'house'}
344     end
345     if o:grab_address{match=POSTCODES, out_key='postcode'} > 0 and fallback == nil then
346         fallback = {'place', 'postcode'}
347     end
348
349     local is_interpolation = o:grab_address{match=INTERPOLATION_TAGS} > 0
350
351     o:grab_address{match=ADDRESS_TAGS}
352
353     if is_interpolation then
354         o:write_place('place', 'houses', 'always', SAVE_EXTRA_MAINS)
355         return
356     end
357
358     -- name keys
359     o:grab_name{match = NAMES}
360     o:grab_name{match = REFS, include_on_name = false}
361
362     o:delete{match = POST_DELETE}
363     o:grab_extratags{match = POST_EXTRAS}
364
365     -- collect main keys
366     local num_mains = 0
367     for k, v in pairs(o:tags()) do
368         num_mains = num_mains + o:write_place(k, v, MAIN_KEYS[k], SAVE_EXTRA_MAINS)
369     end
370
371     if num_mains == 0 then
372         for tag, mtype in pairs(MAIN_FALLBACK_KEYS) do
373             if o:write_place(tag, nil, mtype, SAVE_EXTRA_MAINS) > 0 then
374                 return
375             end
376         end
377
378         if fallback ~= nil then
379             o:write_place(fallback[1], fallback[2], 'always', SAVE_EXTRA_MAINS)
380         end
381     end
382 end
383
384