]> git.openstreetmap.org Git - nominatim.git/blob - sql/functions/normalization.sql
Merge pull request #1936 from lonvia/tweeking-of-ranks
[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 -- Normalize a string and lookup its word ids (partial words).
205 CREATE OR REPLACE FUNCTION addr_ids_from_name(lookup_word TEXT)
206   RETURNS INTEGER[]
207   AS $$
208 DECLARE
209   lookup_token TEXT;
210   id INTEGER;
211   return_word_id INTEGER[];
212 BEGIN
213   lookup_token := make_standard_name(lookup_word);
214   SELECT array_agg(word_id) FROM word
215     WHERE word_token = lookup_token and class is null and type is null
216     INTO return_word_id;
217   IF return_word_id IS NULL THEN
218     id := nextval('seq_word');
219     INSERT INTO word VALUES (id, lookup_token, null, null, null, null, 0);
220     return_word_id = ARRAY[id];
221   END IF;
222   RETURN return_word_id;
223 END;
224 $$
225 LANGUAGE plpgsql;
226
227
228 -- Normalize a string and look up its name ids (full words).
229 CREATE OR REPLACE FUNCTION word_ids_from_name(lookup_word TEXT)
230   RETURNS INTEGER[]
231   AS $$
232 DECLARE
233   lookup_token TEXT;
234   return_word_ids INTEGER[];
235 BEGIN
236   lookup_token := ' '|| make_standard_name(lookup_word);
237   SELECT array_agg(word_id) FROM word
238     WHERE word_token = lookup_token and class is null and type is null
239     INTO return_word_ids;
240   RETURN return_word_ids;
241 END;
242 $$
243 LANGUAGE plpgsql STABLE STRICT;
244
245
246 CREATE OR REPLACE FUNCTION create_country(src HSTORE, country_code varchar(2))
247   RETURNS VOID
248   AS $$
249 DECLARE
250   s TEXT;
251   w INTEGER;
252   words TEXT[];
253   item RECORD;
254   j INTEGER;
255 BEGIN
256   FOR item IN SELECT (each(src)).* LOOP
257
258     s := make_standard_name(item.value);
259     w := getorcreate_country(s, country_code);
260
261     words := regexp_split_to_array(item.value, E'[,;()]');
262     IF array_upper(words, 1) != 1 THEN
263       FOR j IN 1..array_upper(words, 1) LOOP
264         s := make_standard_name(words[j]);
265         IF s != '' THEN
266           w := getorcreate_country(s, country_code);
267         END IF;
268       END LOOP;
269     END IF;
270   END LOOP;
271 END;
272 $$
273 LANGUAGE plpgsql;
274
275
276 CREATE OR REPLACE FUNCTION make_keywords(src HSTORE)
277   RETURNS INTEGER[]
278   AS $$
279 DECLARE
280   result INTEGER[];
281   s TEXT;
282   w INTEGER;
283   words TEXT[];
284   item RECORD;
285   j INTEGER;
286 BEGIN
287   result := '{}'::INTEGER[];
288
289   FOR item IN SELECT (each(src)).* LOOP
290
291     s := make_standard_name(item.value);
292     w := getorcreate_name_id(s, item.value);
293
294     IF not(ARRAY[w] <@ result) THEN
295       result := result || w;
296     END IF;
297
298     w := getorcreate_word_id(s);
299
300     IF w IS NOT NULL AND NOT (ARRAY[w] <@ result) THEN
301       result := result || w;
302     END IF;
303
304     words := string_to_array(s, ' ');
305     IF array_upper(words, 1) IS NOT NULL THEN
306       FOR j IN 1..array_upper(words, 1) LOOP
307         IF (words[j] != '') THEN
308           w = getorcreate_word_id(words[j]);
309           IF w IS NOT NULL AND NOT (ARRAY[w] <@ result) THEN
310             result := result || w;
311           END IF;
312         END IF;
313       END LOOP;
314     END IF;
315
316     words := regexp_split_to_array(item.value, E'[,;()]');
317     IF array_upper(words, 1) != 1 THEN
318       FOR j IN 1..array_upper(words, 1) LOOP
319         s := make_standard_name(words[j]);
320         IF s != '' THEN
321           w := getorcreate_word_id(s);
322           IF w IS NOT NULL AND NOT (ARRAY[w] <@ result) THEN
323             result := result || w;
324           END IF;
325         END IF;
326       END LOOP;
327     END IF;
328
329     s := regexp_replace(item.value, '市$', '');
330     IF s != item.value THEN
331       s := make_standard_name(s);
332       IF s != '' THEN
333         w := getorcreate_name_id(s, item.value);
334         IF NOT (ARRAY[w] <@ result) THEN
335           result := result || w;
336         END IF;
337       END IF;
338     END IF;
339
340   END LOOP;
341
342   RETURN result;
343 END;
344 $$
345 LANGUAGE plpgsql;
346
347
348 CREATE OR REPLACE FUNCTION make_keywords(src TEXT)
349   RETURNS INTEGER[]
350   AS $$
351 DECLARE
352   result INTEGER[];
353   s TEXT;
354   w INTEGER;
355   words TEXT[];
356   i INTEGER;
357   j INTEGER;
358 BEGIN
359   result := '{}'::INTEGER[];
360
361   s := make_standard_name(src);
362   w := getorcreate_name_id(s, src);
363
364   IF NOT (ARRAY[w] <@ result) THEN
365     result := result || w;
366   END IF;
367
368   w := getorcreate_word_id(s);
369
370   IF w IS NOT NULL AND NOT (ARRAY[w] <@ result) THEN
371     result := result || w;
372   END IF;
373
374   words := string_to_array(s, ' ');
375   IF array_upper(words, 1) IS NOT NULL THEN
376     FOR j IN 1..array_upper(words, 1) LOOP
377       IF (words[j] != '') THEN
378         w = getorcreate_word_id(words[j]);
379         IF w IS NOT NULL AND NOT (ARRAY[w] <@ result) THEN
380           result := result || w;
381         END IF;
382       END IF;
383     END LOOP;
384   END IF;
385
386   words := regexp_split_to_array(src, E'[,;()]');
387   IF array_upper(words, 1) != 1 THEN
388     FOR j IN 1..array_upper(words, 1) LOOP
389       s := make_standard_name(words[j]);
390       IF s != '' THEN
391         w := getorcreate_word_id(s);
392         IF w IS NOT NULL AND NOT (ARRAY[w] <@ result) THEN
393           result := result || w;
394         END IF;
395       END IF;
396     END LOOP;
397   END IF;
398
399   s := regexp_replace(src, '市$', '');
400   IF s != src THEN
401     s := make_standard_name(s);
402     IF s != '' THEN
403       w := getorcreate_name_id(s, src);
404       IF NOT (ARRAY[w] <@ result) THEN
405         result := result || w;
406       END IF;
407     END IF;
408   END IF;
409
410   RETURN result;
411 END;
412 $$
413 LANGUAGE plpgsql;