]> git.openstreetmap.org Git - nominatim.git/blob - sql/partition-functions.src.sql
lookup places for address tags for rank < 30
[nominatim.git] / sql / partition-functions.src.sql
1 DROP TYPE IF EXISTS nearfeaturecentr CASCADE;
2 CREATE TYPE nearfeaturecentr AS (
3   place_id BIGINT,
4   keywords int[],
5   rank_address smallint,
6   rank_search smallint,
7   distance float,
8   isguess boolean,
9   postcode TEXT,
10   centroid GEOMETRY
11 );
12
13 -- feature intersects geoemtry
14 -- for areas and linestrings they must touch at least along a line
15 CREATE OR REPLACE FUNCTION is_relevant_geometry(de9im TEXT, geom_type TEXT)
16 RETURNS BOOLEAN
17 AS $$
18 BEGIN
19   IF substring(de9im from 1 for 2) != 'FF' THEN
20     RETURN TRUE;
21   END IF;
22
23   IF geom_type = 'ST_Point' THEN
24     RETURN substring(de9im from 4 for 1) = '0';
25   END IF;
26
27   IF geom_type in ('ST_LineString', 'ST_MultiLineString') THEN
28     RETURN substring(de9im from 4 for 1) = '1';
29   END IF;
30
31   RETURN substring(de9im from 4 for 1) = '2';
32 END
33 $$ LANGUAGE plpgsql IMMUTABLE;
34
35 create or replace function getNearFeatures(in_partition INTEGER, feature GEOMETRY, maxrank INTEGER) RETURNS setof nearfeaturecentr AS $$
36 DECLARE
37   r nearfeaturecentr%rowtype;
38 BEGIN
39
40 -- start
41   IF in_partition = -partition- THEN
42     FOR r IN
43       SELECT place_id, keywords, rank_address, rank_search,
44              min(ST_Distance(feature, centroid)) as distance,
45              isguess, postcode, centroid
46       FROM location_area_large_-partition-
47       WHERE geometry && feature
48         AND is_relevant_geometry(ST_Relate(geometry, feature), ST_GeometryType(feature))
49         AND rank_address < maxrank
50       GROUP BY place_id, keywords, rank_address, rank_search, isguess, postcode, centroid
51     LOOP
52       RETURN NEXT r;
53     END LOOP;
54     RETURN;
55   END IF;
56 -- end
57
58   RAISE EXCEPTION 'Unknown partition %', in_partition;
59 END
60 $$
61 LANGUAGE plpgsql STABLE;
62
63 CREATE OR REPLACE FUNCTION get_places_for_addr_tags(in_partition SMALLINT,
64                                                     feature GEOMETRY,
65                                                     address HSTORE, country TEXT)
66   RETURNS SETOF nearfeaturecentr
67   AS $$
68 DECLARE
69   r nearfeaturecentr%rowtype;
70   item RECORD;
71 BEGIN
72   FOR item IN
73     SELECT (get_addr_tag_rank(key, country)).*, key, name FROM
74       (SELECT skeys(address) as key, svals(address) as name) x
75         WHERE key not in ('country', 'postcode', 'housenumber',
76                           'conscriptionnumber', 'streetnumber')
77   LOOP
78    IF item.from_rank is null THEN
79      CONTINUE;
80    END IF;
81
82 -- start
83     IF in_partition = -partition- THEN
84         SELECT place_id, keywords, rank_address, rank_search,
85                min(ST_Distance(feature, centroid)) as distance,
86                isguess, postcode, centroid INTO r
87         FROM location_area_large_-partition-
88         WHERE geometry && ST_Expand(feature, item.extent)
89           AND rank_address between item.from_rank and item.to_rank
90           AND word_ids_from_name(item.name) && keywords
91         GROUP BY place_id, keywords, rank_address, rank_search, isguess, postcode, centroid
92         ORDER BY ST_Intersects(ST_Collect(geometry), feature), distance LIMIT 1;
93       IF r.place_id is null THEN
94         -- If we cannot find a place for the term, just return the
95         -- search term for the given name. That ensures that the address
96         -- element can still be searched for, even though it will not be
97         -- displayed.
98         RETURN NEXT ROW(null, addr_ids_from_name(item.name), null, null,
99                         null, null, null, null)::nearfeaturecentr;
100       ELSE
101         RETURN NEXT r;
102       END IF;
103       CONTINUE;
104     END IF;
105 -- end
106
107     RAISE EXCEPTION 'Unknown partition %', in_partition;
108   END LOOP;
109 END;
110 $$
111 LANGUAGE plpgsql STABLE;
112
113 create or replace function deleteLocationArea(in_partition INTEGER, in_place_id BIGINT, in_rank_search INTEGER) RETURNS BOOLEAN AS $$
114 DECLARE
115 BEGIN
116
117   IF in_rank_search <= 4 THEN
118     DELETE from location_area_country WHERE place_id = in_place_id;
119     RETURN TRUE;
120   END IF;
121
122 -- start
123   IF in_partition = -partition- THEN
124     DELETE from location_area_large_-partition- WHERE place_id = in_place_id;
125     RETURN TRUE;
126   END IF;
127 -- end
128
129   RAISE EXCEPTION 'Unknown partition %', in_partition;
130
131   RETURN FALSE;
132 END
133 $$
134 LANGUAGE plpgsql;
135
136 create or replace function insertLocationAreaLarge(
137   in_partition INTEGER, in_place_id BIGINT, in_country_code VARCHAR(2), in_keywords INTEGER[],
138   in_rank_search INTEGER, in_rank_address INTEGER, in_estimate BOOLEAN, postcode TEXT,
139   in_centroid GEOMETRY, in_geometry GEOMETRY) RETURNS BOOLEAN AS $$
140 DECLARE
141 BEGIN
142   IF in_rank_address = 0 THEN
143     RETURN TRUE;
144   END IF;
145
146   IF in_rank_search <= 4 and not in_estimate THEN
147     INSERT INTO location_area_country (place_id, country_code, geometry)
148       values (in_place_id, in_country_code, in_geometry);
149     RETURN TRUE;
150   END IF;
151
152 -- start
153   IF in_partition = -partition- THEN
154     INSERT INTO location_area_large_-partition- (partition, place_id, country_code, keywords, rank_search, rank_address, isguess, postcode, centroid, geometry)
155       values (in_partition, in_place_id, in_country_code, in_keywords, in_rank_search, in_rank_address, in_estimate, postcode, in_centroid, in_geometry);
156     RETURN TRUE;
157   END IF;
158 -- end
159
160   RAISE EXCEPTION 'Unknown partition %', in_partition;
161   RETURN FALSE;
162 END
163 $$
164 LANGUAGE plpgsql;
165
166 CREATE OR REPLACE FUNCTION getNearestNamedRoadPlaceId(in_partition INTEGER,
167                                                       point GEOMETRY,
168                                                       isin_token INTEGER[])
169   RETURNS BIGINT
170   AS $$
171 DECLARE
172   parent BIGINT;
173 BEGIN
174
175 -- start
176   IF in_partition = -partition- THEN
177     SELECT place_id FROM search_name_-partition-
178       INTO parent
179       WHERE name_vector && isin_token
180             AND centroid && ST_Expand(point, 0.015)
181             AND search_rank between 26 and 27
182       ORDER BY ST_Distance(centroid, point) ASC limit 1;
183     RETURN parent;
184   END IF;
185 -- end
186
187   RAISE EXCEPTION 'Unknown partition %', in_partition;
188 END
189 $$
190 LANGUAGE plpgsql STABLE;
191
192 CREATE OR REPLACE FUNCTION getNearestNamedPlacePlaceId(in_partition INTEGER,
193                                                        point GEOMETRY,
194                                                        isin_token INTEGER[])
195   RETURNS BIGINT
196   AS $$
197 DECLARE
198   parent BIGINT;
199 BEGIN
200
201 -- start
202   IF in_partition = -partition- THEN
203     SELECT place_id
204       INTO parent
205       FROM search_name_-partition-
206       WHERE name_vector && isin_token
207             AND centroid && ST_Expand(point, 0.04)
208             AND address_rank between 16 and 25
209       ORDER BY ST_Distance(centroid, point) ASC limit 1;
210     RETURN parent;
211   END IF;
212 -- end
213
214   RAISE EXCEPTION 'Unknown partition %', in_partition;
215 END
216 $$
217 LANGUAGE plpgsql STABLE;
218
219 create or replace function insertSearchName(
220   in_partition INTEGER, in_place_id BIGINT, in_name_vector INTEGER[],
221   in_rank_search INTEGER, in_rank_address INTEGER, in_geometry GEOMETRY)
222 RETURNS BOOLEAN AS $$
223 DECLARE
224 BEGIN
225 -- start
226   IF in_partition = -partition- THEN
227     DELETE FROM search_name_-partition- values WHERE place_id = in_place_id;
228     IF in_rank_address > 0 THEN
229       INSERT INTO search_name_-partition- (place_id, search_rank, address_rank, name_vector, centroid)
230         values (in_place_id, in_rank_search, in_rank_address, in_name_vector, in_geometry);
231     END IF;
232     RETURN TRUE;
233   END IF;
234 -- end
235
236   RAISE EXCEPTION 'Unknown partition %', in_partition;
237   RETURN FALSE;
238 END
239 $$
240 LANGUAGE plpgsql;
241
242 create or replace function deleteSearchName(in_partition INTEGER, in_place_id BIGINT) RETURNS BOOLEAN AS $$
243 DECLARE
244 BEGIN
245 -- start
246   IF in_partition = -partition- THEN
247     DELETE from search_name_-partition- WHERE place_id = in_place_id;
248     RETURN TRUE;
249   END IF;
250 -- end
251
252   RAISE EXCEPTION 'Unknown partition %', in_partition;
253
254   RETURN FALSE;
255 END
256 $$
257 LANGUAGE plpgsql;
258
259 create or replace function insertLocationRoad(
260   in_partition INTEGER, in_place_id BIGINT, in_country_code VARCHAR(2), in_geometry GEOMETRY) RETURNS BOOLEAN AS $$
261 DECLARE
262 BEGIN
263
264 -- start
265   IF in_partition = -partition- THEN
266     DELETE FROM location_road_-partition- where place_id = in_place_id;
267     INSERT INTO location_road_-partition- (partition, place_id, country_code, geometry)
268       values (in_partition, in_place_id, in_country_code, in_geometry);
269     RETURN TRUE;
270   END IF;
271 -- end
272
273   RAISE EXCEPTION 'Unknown partition %', in_partition;
274   RETURN FALSE;
275 END
276 $$
277 LANGUAGE plpgsql;
278
279 create or replace function deleteRoad(in_partition INTEGER, in_place_id BIGINT) RETURNS BOOLEAN AS $$
280 DECLARE
281 BEGIN
282
283 -- start
284   IF in_partition = -partition- THEN
285     DELETE FROM location_road_-partition- where place_id = in_place_id;
286     RETURN TRUE;
287   END IF;
288 -- end
289
290   RAISE EXCEPTION 'Unknown partition %', in_partition;
291
292   RETURN FALSE;
293 END
294 $$
295 LANGUAGE plpgsql;
296
297 CREATE OR REPLACE FUNCTION getNearestRoadPlaceId(in_partition INTEGER, point GEOMETRY)
298   RETURNS BIGINT
299   AS $$
300 DECLARE
301   r RECORD;
302   search_diameter FLOAT;
303 BEGIN
304
305 -- start
306   IF in_partition = -partition- THEN
307     search_diameter := 0.00005;
308     WHILE search_diameter < 0.1 LOOP
309       FOR r IN
310         SELECT place_id FROM location_road_-partition-
311           WHERE ST_DWithin(geometry, point, search_diameter)
312           ORDER BY ST_Distance(geometry, point) ASC limit 1
313       LOOP
314         RETURN r.place_id;
315       END LOOP;
316       search_diameter := search_diameter * 2;
317     END LOOP;
318     RETURN NULL;
319   END IF;
320 -- end
321
322   RAISE EXCEPTION 'Unknown partition %', in_partition;
323 END
324 $$
325 LANGUAGE plpgsql STABLE;
326
327 CREATE OR REPLACE FUNCTION getNearestParallelRoadFeature(in_partition INTEGER,
328                                                          line GEOMETRY)
329   RETURNS BIGINT
330   AS $$
331 DECLARE
332   r RECORD;
333   search_diameter FLOAT;
334   p1 GEOMETRY;
335   p2 GEOMETRY;
336   p3 GEOMETRY;
337 BEGIN
338
339   IF ST_GeometryType(line) not in ('ST_LineString') THEN
340     RETURN NULL;
341   END IF;
342
343   p1 := ST_LineInterpolatePoint(line,0);
344   p2 := ST_LineInterpolatePoint(line,0.5);
345   p3 := ST_LineInterpolatePoint(line,1);
346
347 -- start
348   IF in_partition = -partition- THEN
349     search_diameter := 0.0005;
350     WHILE search_diameter < 0.01 LOOP
351       FOR r IN
352         SELECT place_id FROM location_road_-partition-
353           WHERE ST_DWithin(line, geometry, search_diameter)
354           ORDER BY (ST_distance(geometry, p1)+
355                     ST_distance(geometry, p2)+
356                     ST_distance(geometry, p3)) ASC limit 1
357       LOOP
358         RETURN r.place_id;
359       END LOOP;
360       search_diameter := search_diameter * 2;
361     END LOOP;
362     RETURN NULL;
363   END IF;
364 -- end
365
366   RAISE EXCEPTION 'Unknown partition %', in_partition;
367 END
368 $$
369 LANGUAGE plpgsql STABLE;