]> git.openstreetmap.org Git - nominatim.git/blob - sql/functions/normalization.sql
cf8e63bc83068559c4b1ad6fba9b96cce2dc2f52
[nominatim.git] / sql / functions / normalization.sql
1 -- Functions for term normalisation and access to the 'word' table.
2
3 CREATE OR REPLACE FUNCTION transliteration(text) RETURNS text
4   AS '{modulepath}/nominatim.so', 'transliteration'
5 LANGUAGE c IMMUTABLE STRICT;
6
7
8 CREATE OR REPLACE FUNCTION gettokenstring(text) RETURNS text
9   AS '{modulepath}/nominatim.so', 'gettokenstring'
10 LANGUAGE c IMMUTABLE STRICT;
11
12
13 CREATE OR REPLACE FUNCTION make_standard_name(name TEXT) RETURNS TEXT
14   AS $$
15 DECLARE
16   o TEXT;
17 BEGIN
18   o := public.gettokenstring(public.transliteration(name));
19   RETURN trim(substr(o,1,length(o)));
20 END;
21 $$
22 LANGUAGE plpgsql IMMUTABLE;
23
24 -- returns NULL if the word is too common
25 CREATE OR REPLACE FUNCTION getorcreate_word_id(lookup_word TEXT) 
26   RETURNS INTEGER
27   AS $$
28 DECLARE
29   lookup_token TEXT;
30   return_word_id INTEGER;
31   count INTEGER;
32 BEGIN
33   lookup_token := trim(lookup_word);
34   SELECT min(word_id), max(search_name_count) FROM word
35     WHERE word_token = lookup_token and class is null and type is null
36     INTO return_word_id, count;
37   IF return_word_id IS NULL THEN
38     return_word_id := nextval('seq_word');
39     INSERT INTO word VALUES (return_word_id, lookup_token, null, null, null, null, 0);
40   ELSE
41     IF count > get_maxwordfreq() THEN
42       return_word_id := NULL;
43     END IF;
44   END IF;
45   RETURN return_word_id;
46 END;
47 $$
48 LANGUAGE plpgsql;
49
50
51 CREATE OR REPLACE FUNCTION getorcreate_housenumber_id(lookup_word TEXT)
52   RETURNS INTEGER
53   AS $$
54 DECLARE
55   lookup_token TEXT;
56   return_word_id INTEGER;
57 BEGIN
58   lookup_token := ' ' || trim(lookup_word);
59   SELECT min(word_id) FROM word
60     WHERE word_token = lookup_token and class='place' and type='house'
61     INTO return_word_id;
62   IF return_word_id IS NULL THEN
63     return_word_id := nextval('seq_word');
64     INSERT INTO word VALUES (return_word_id, lookup_token, null,
65                              'place', 'house', null, 0);
66   END IF;
67   RETURN return_word_id;
68 END;
69 $$
70 LANGUAGE plpgsql;
71
72
73 CREATE OR REPLACE FUNCTION getorcreate_postcode_id(postcode TEXT)
74   RETURNS INTEGER
75   AS $$
76 DECLARE
77   lookup_token TEXT;
78   lookup_word TEXT;
79   return_word_id INTEGER;
80 BEGIN
81   lookup_word := upper(trim(postcode));
82   lookup_token := ' ' || make_standard_name(lookup_word);
83   SELECT min(word_id) FROM word
84     WHERE word_token = lookup_token and class='place' and type='postcode'
85     INTO return_word_id;
86   IF return_word_id IS NULL THEN
87     return_word_id := nextval('seq_word');
88     INSERT INTO word VALUES (return_word_id, lookup_token, lookup_word,
89                              'place', 'postcode', null, 0);
90   END IF;
91   RETURN return_word_id;
92 END;
93 $$
94 LANGUAGE plpgsql;
95
96
97 CREATE OR REPLACE FUNCTION getorcreate_country(lookup_word TEXT,
98                                                lookup_country_code varchar(2))
99   RETURNS INTEGER
100   AS $$
101 DECLARE
102   lookup_token TEXT;
103   return_word_id INTEGER;
104 BEGIN
105   lookup_token := ' '||trim(lookup_word);
106   SELECT min(word_id) FROM word
107     WHERE word_token = lookup_token and country_code=lookup_country_code
108     INTO return_word_id;
109   IF return_word_id IS NULL THEN
110     return_word_id := nextval('seq_word');
111     INSERT INTO word VALUES (return_word_id, lookup_token, null,
112                              null, null, lookup_country_code, 0);
113   END IF;
114   RETURN return_word_id;
115 END;
116 $$
117 LANGUAGE plpgsql;
118
119
120 CREATE OR REPLACE FUNCTION getorcreate_amenity(lookup_word TEXT, normalized_word TEXT,
121                                                lookup_class text, lookup_type text)
122   RETURNS INTEGER
123   AS $$
124 DECLARE
125   lookup_token TEXT;
126   return_word_id INTEGER;
127 BEGIN
128   lookup_token := ' '||trim(lookup_word);
129   SELECT min(word_id) FROM word
130   WHERE word_token = lookup_token and word = normalized_word
131         and class = lookup_class and type = lookup_type
132   INTO return_word_id;
133   IF return_word_id IS NULL THEN
134     return_word_id := nextval('seq_word');
135     INSERT INTO word VALUES (return_word_id, lookup_token, normalized_word,
136                              lookup_class, lookup_type, null, 0);
137   END IF;
138   RETURN return_word_id;
139 END;
140 $$
141 LANGUAGE plpgsql;
142
143
144 CREATE OR REPLACE FUNCTION getorcreate_amenityoperator(lookup_word TEXT,
145                                                        normalized_word TEXT,
146                                                        lookup_class text,
147                                                        lookup_type text,
148                                                        op text)
149   RETURNS INTEGER
150   AS $$
151 DECLARE
152   lookup_token TEXT;
153   return_word_id INTEGER;
154 BEGIN
155   lookup_token := ' '||trim(lookup_word);
156   SELECT min(word_id) FROM word
157   WHERE word_token = lookup_token and word = normalized_word
158         and class = lookup_class and type = lookup_type and operator = op
159   INTO return_word_id;
160   IF return_word_id IS NULL THEN
161     return_word_id := nextval('seq_word');
162     INSERT INTO word VALUES (return_word_id, lookup_token, normalized_word,
163                              lookup_class, lookup_type, null, 0, op);
164   END IF;
165   RETURN return_word_id;
166 END;
167 $$
168 LANGUAGE plpgsql;
169
170
171 CREATE OR REPLACE FUNCTION getorcreate_name_id(lookup_word TEXT, src_word TEXT)
172   RETURNS INTEGER
173   AS $$
174 DECLARE
175   lookup_token TEXT;
176   nospace_lookup_token TEXT;
177   return_word_id INTEGER;
178 BEGIN
179   lookup_token := ' '||trim(lookup_word);
180   SELECT min(word_id) FROM word
181   WHERE word_token = lookup_token and class is null and type is null
182   INTO return_word_id;
183   IF return_word_id IS NULL THEN
184     return_word_id := nextval('seq_word');
185     INSERT INTO word VALUES (return_word_id, lookup_token, src_word,
186                              null, null, null, 0);
187   END IF;
188   RETURN return_word_id;
189 END;
190 $$
191 LANGUAGE plpgsql;
192
193
194 CREATE OR REPLACE FUNCTION getorcreate_name_id(lookup_word TEXT)
195   RETURNS INTEGER
196   AS $$
197 DECLARE
198 BEGIN
199   RETURN getorcreate_name_id(lookup_word, '');
200 END;
201 $$
202 LANGUAGE plpgsql;
203
204
205 CREATE OR REPLACE FUNCTION get_word_id(lookup_word TEXT)
206   RETURNS INTEGER
207   AS $$
208 DECLARE
209   lookup_token TEXT;
210   return_word_id INTEGER;
211 BEGIN
212   lookup_token := trim(lookup_word);
213   SELECT min(word_id) FROM word
214     WHERE word_token = lookup_token and class is null and type is null
215     INTO return_word_id;
216   RETURN return_word_id;
217 END;
218 $$
219 LANGUAGE plpgsql STABLE;
220
221
222 CREATE OR REPLACE FUNCTION get_name_id(lookup_word TEXT)
223   RETURNS INTEGER
224   AS $$
225 DECLARE
226   lookup_token TEXT;
227   return_word_id INTEGER;
228 BEGIN
229   lookup_token := ' '||trim(lookup_word);
230   SELECT min(word_id) FROM word
231     WHERE word_token = lookup_token and class is null and type is null
232     INTO return_word_id;
233   RETURN return_word_id;
234 END;
235 $$
236 LANGUAGE plpgsql STABLE;
237
238
239 -- Normalize a string and look up its name ids.
240 CREATE OR REPLACE FUNCTION word_ids_from_name(lookup_word TEXT)
241   RETURNS INTEGER[]
242   AS $$
243 DECLARE
244   lookup_token TEXT;
245   return_word_ids INTEGER[];
246 BEGIN
247   lookup_token := ' '|| make_standard_name(lookup_word);
248   SELECT array_agg(word_id) FROM word
249     WHERE word_token = lookup_token and class is null and type is null
250     INTO return_word_ids;
251   RETURN return_word_ids;
252 END;
253 $$
254 LANGUAGE plpgsql STABLE STRICT;
255
256
257 CREATE OR REPLACE FUNCTION create_country(src HSTORE, country_code varchar(2))
258   RETURNS VOID
259   AS $$
260 DECLARE
261   s TEXT;
262   w INTEGER;
263   words TEXT[];
264   item RECORD;
265   j INTEGER;
266 BEGIN
267   FOR item IN SELECT (each(src)).* LOOP
268
269     s := make_standard_name(item.value);
270     w := getorcreate_country(s, country_code);
271
272     words := regexp_split_to_array(item.value, E'[,;()]');
273     IF array_upper(words, 1) != 1 THEN
274       FOR j IN 1..array_upper(words, 1) LOOP
275         s := make_standard_name(words[j]);
276         IF s != '' THEN
277           w := getorcreate_country(s, country_code);
278         END IF;
279       END LOOP;
280     END IF;
281   END LOOP;
282 END;
283 $$
284 LANGUAGE plpgsql;
285
286
287 CREATE OR REPLACE FUNCTION make_keywords(src HSTORE)
288   RETURNS INTEGER[]
289   AS $$
290 DECLARE
291   result INTEGER[];
292   s TEXT;
293   w INTEGER;
294   words TEXT[];
295   item RECORD;
296   j INTEGER;
297 BEGIN
298   result := '{}'::INTEGER[];
299
300   FOR item IN SELECT (each(src)).* LOOP
301
302     s := make_standard_name(item.value);
303     w := getorcreate_name_id(s, item.value);
304
305     IF not(ARRAY[w] <@ result) THEN
306       result := result || w;
307     END IF;
308
309     w := getorcreate_word_id(s);
310
311     IF w IS NOT NULL AND NOT (ARRAY[w] <@ result) THEN
312       result := result || w;
313     END IF;
314
315     words := string_to_array(s, ' ');
316     IF array_upper(words, 1) IS NOT NULL THEN
317       FOR j IN 1..array_upper(words, 1) LOOP
318         IF (words[j] != '') THEN
319           w = getorcreate_word_id(words[j]);
320           IF w IS NOT NULL AND NOT (ARRAY[w] <@ result) THEN
321             result := result || w;
322           END IF;
323         END IF;
324       END LOOP;
325     END IF;
326
327     words := regexp_split_to_array(item.value, E'[,;()]');
328     IF array_upper(words, 1) != 1 THEN
329       FOR j IN 1..array_upper(words, 1) LOOP
330         s := make_standard_name(words[j]);
331         IF s != '' THEN
332           w := getorcreate_word_id(s);
333           IF w IS NOT NULL AND NOT (ARRAY[w] <@ result) THEN
334             result := result || w;
335           END IF;
336         END IF;
337       END LOOP;
338     END IF;
339
340     s := regexp_replace(item.value, '市$', '');
341     IF s != item.value THEN
342       s := make_standard_name(s);
343       IF s != '' THEN
344         w := getorcreate_name_id(s, item.value);
345         IF NOT (ARRAY[w] <@ result) THEN
346           result := result || w;
347         END IF;
348       END IF;
349     END IF;
350
351   END LOOP;
352
353   RETURN result;
354 END;
355 $$
356 LANGUAGE plpgsql;
357
358
359 CREATE OR REPLACE FUNCTION make_keywords(src TEXT)
360   RETURNS INTEGER[]
361   AS $$
362 DECLARE
363   result INTEGER[];
364   s TEXT;
365   w INTEGER;
366   words TEXT[];
367   i INTEGER;
368   j INTEGER;
369 BEGIN
370   result := '{}'::INTEGER[];
371
372   s := make_standard_name(src);
373   w := getorcreate_name_id(s, src);
374
375   IF NOT (ARRAY[w] <@ result) THEN
376     result := result || w;
377   END IF;
378
379   w := getorcreate_word_id(s);
380
381   IF w IS NOT NULL AND NOT (ARRAY[w] <@ result) THEN
382     result := result || w;
383   END IF;
384
385   words := string_to_array(s, ' ');
386   IF array_upper(words, 1) IS NOT NULL THEN
387     FOR j IN 1..array_upper(words, 1) LOOP
388       IF (words[j] != '') THEN
389         w = getorcreate_word_id(words[j]);
390         IF w IS NOT NULL AND NOT (ARRAY[w] <@ result) THEN
391           result := result || w;
392         END IF;
393       END IF;
394     END LOOP;
395   END IF;
396
397   words := regexp_split_to_array(src, E'[,;()]');
398   IF array_upper(words, 1) != 1 THEN
399     FOR j IN 1..array_upper(words, 1) LOOP
400       s := make_standard_name(words[j]);
401       IF s != '' THEN
402         w := getorcreate_word_id(s);
403         IF w IS NOT NULL AND NOT (ARRAY[w] <@ result) THEN
404           result := result || w;
405         END IF;
406       END IF;
407     END LOOP;
408   END IF;
409
410   s := regexp_replace(src, '市$', '');
411   IF s != src THEN
412     s := make_standard_name(s);
413     IF s != '' THEN
414       w := getorcreate_name_id(s, src);
415       IF NOT (ARRAY[w] <@ result) THEN
416         result := result || w;
417       END IF;
418     END IF;
419   END IF;
420
421   RETURN result;
422 END;
423 $$
424 LANGUAGE plpgsql;