1 -- Get tokens used for searching the given place.
3 -- These are the tokens that will be saved in the search_name table.
4 CREATE OR REPLACE FUNCTION token_get_name_search_tokens(info JSONB)
7 SELECT (info->>'names')::INTEGER[]
8 $$ LANGUAGE SQL IMMUTABLE STRICT;
10 -- Get tokens for matching the place name against others.
12 -- This should usually be restricted to full name tokens.
13 CREATE OR REPLACE FUNCTION token_get_name_match_tokens(info JSONB)
16 SELECT (info->>'names')::INTEGER[]
17 $$ LANGUAGE SQL IMMUTABLE STRICT;
20 -- Return token info that should be saved permanently in the database.
21 CREATE OR REPLACE FUNCTION token_strip_info(info JSONB)
25 $$ LANGUAGE SQL IMMUTABLE STRICT;
27 --------------- private functions ----------------------------------------------
29 -- Functions for term normalisation and access to the 'word' table.
31 CREATE OR REPLACE FUNCTION transliteration(text) RETURNS text
32 AS '{{ modulepath }}/nominatim.so', 'transliteration'
33 LANGUAGE c IMMUTABLE STRICT;
36 CREATE OR REPLACE FUNCTION gettokenstring(text) RETURNS text
37 AS '{{ modulepath }}/nominatim.so', 'gettokenstring'
38 LANGUAGE c IMMUTABLE STRICT;
41 CREATE OR REPLACE FUNCTION make_standard_name(name TEXT) RETURNS TEXT
46 o := public.gettokenstring(public.transliteration(name));
47 RETURN trim(substr(o,1,length(o)));
50 LANGUAGE plpgsql IMMUTABLE;
52 -- returns NULL if the word is too common
53 CREATE OR REPLACE FUNCTION getorcreate_word_id(lookup_word TEXT)
58 return_word_id INTEGER;
61 lookup_token := trim(lookup_word);
62 SELECT min(word_id), max(search_name_count) FROM word
63 WHERE word_token = lookup_token and class is null and type is null
64 INTO return_word_id, count;
65 IF return_word_id IS NULL THEN
66 return_word_id := nextval('seq_word');
67 INSERT INTO word VALUES (return_word_id, lookup_token, null, null, null, null, 0);
69 IF count > {{ max_word_freq }} THEN
70 return_word_id := NULL;
73 RETURN return_word_id;
78 -- Create housenumber tokens from an OSM addr:housenumber.
79 -- The housnumber is split at comma and semicolon as necessary.
80 -- The function returns the normalized form of the housenumber suitable
82 CREATE OR REPLACE FUNCTION create_housenumber_id(housenumber TEXT)
88 SELECT array_to_string(array_agg(trans), ';')
90 FROM (SELECT lookup_word as trans, getorcreate_housenumber_id(lookup_word)
91 FROM (SELECT make_standard_name(h) as lookup_word
92 FROM regexp_split_to_table(housenumber, '[,;]') h) x) y;
96 $$ LANGUAGE plpgsql STABLE STRICT;
98 CREATE OR REPLACE FUNCTION getorcreate_housenumber_id(lookup_word TEXT)
103 return_word_id INTEGER;
105 lookup_token := ' ' || trim(lookup_word);
106 SELECT min(word_id) FROM word
107 WHERE word_token = lookup_token and class='place' and type='house'
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 'place', 'house', null, 0);
114 RETURN return_word_id;
120 CREATE OR REPLACE FUNCTION getorcreate_postcode_id(postcode TEXT)
126 return_word_id INTEGER;
128 lookup_word := upper(trim(postcode));
129 lookup_token := ' ' || make_standard_name(lookup_word);
130 SELECT min(word_id) FROM word
131 WHERE word_token = lookup_token and word = lookup_word
132 and class='place' and type='postcode'
134 IF return_word_id IS NULL THEN
135 return_word_id := nextval('seq_word');
136 INSERT INTO word VALUES (return_word_id, lookup_token, lookup_word,
137 'place', 'postcode', null, 0);
139 RETURN return_word_id;
145 CREATE OR REPLACE FUNCTION getorcreate_country(lookup_word TEXT,
146 lookup_country_code varchar(2))
151 return_word_id INTEGER;
153 lookup_token := ' '||trim(lookup_word);
154 SELECT min(word_id) FROM word
155 WHERE word_token = lookup_token and country_code=lookup_country_code
157 IF return_word_id IS NULL THEN
158 return_word_id := nextval('seq_word');
159 INSERT INTO word VALUES (return_word_id, lookup_token, null,
160 null, null, lookup_country_code, 0);
162 RETURN return_word_id;
168 CREATE OR REPLACE FUNCTION getorcreate_amenity(lookup_word TEXT, normalized_word TEXT,
169 lookup_class text, lookup_type text)
174 return_word_id INTEGER;
176 lookup_token := ' '||trim(lookup_word);
177 SELECT min(word_id) FROM word
178 WHERE word_token = lookup_token and word = normalized_word
179 and class = lookup_class and type = lookup_type
181 IF return_word_id IS NULL THEN
182 return_word_id := nextval('seq_word');
183 INSERT INTO word VALUES (return_word_id, lookup_token, normalized_word,
184 lookup_class, lookup_type, null, 0);
186 RETURN return_word_id;
192 CREATE OR REPLACE FUNCTION getorcreate_amenityoperator(lookup_word TEXT,
193 normalized_word TEXT,
201 return_word_id INTEGER;
203 lookup_token := ' '||trim(lookup_word);
204 SELECT min(word_id) FROM word
205 WHERE word_token = lookup_token and word = normalized_word
206 and class = lookup_class and type = lookup_type and operator = op
208 IF return_word_id IS NULL THEN
209 return_word_id := nextval('seq_word');
210 INSERT INTO word VALUES (return_word_id, lookup_token, normalized_word,
211 lookup_class, lookup_type, null, 0, op);
213 RETURN return_word_id;
219 CREATE OR REPLACE FUNCTION getorcreate_name_id(lookup_word TEXT, src_word TEXT)
224 nospace_lookup_token TEXT;
225 return_word_id INTEGER;
227 lookup_token := ' '||trim(lookup_word);
228 SELECT min(word_id) FROM word
229 WHERE word_token = lookup_token and class is null and type is null
231 IF return_word_id IS NULL THEN
232 return_word_id := nextval('seq_word');
233 INSERT INTO word VALUES (return_word_id, lookup_token, src_word,
234 null, null, null, 0);
236 RETURN return_word_id;
242 CREATE OR REPLACE FUNCTION getorcreate_name_id(lookup_word TEXT)
247 RETURN getorcreate_name_id(lookup_word, '');
252 -- Normalize a string and lookup its word ids (partial words).
253 CREATE OR REPLACE FUNCTION addr_ids_from_name(lookup_word TEXT)
259 return_word_id INTEGER[];
263 words := string_to_array(make_standard_name(lookup_word), ' ');
264 IF array_upper(words, 1) IS NOT NULL THEN
265 FOR j IN 1..array_upper(words, 1) LOOP
266 IF (words[j] != '') THEN
267 SELECT array_agg(word_id) INTO word_ids
269 WHERE word_token = words[j] and class is null and type is null;
271 IF word_ids IS NULL THEN
272 id := nextval('seq_word');
273 INSERT INTO word VALUES (id, words[j], null, null, null, null, 0);
274 return_word_id := return_word_id || id;
276 return_word_id := array_merge(return_word_id, word_ids);
282 RETURN return_word_id;
288 -- Normalize a string and look up its name ids (full words).
289 CREATE OR REPLACE FUNCTION word_ids_from_name(lookup_word TEXT)
294 return_word_ids INTEGER[];
296 lookup_token := ' '|| make_standard_name(lookup_word);
297 SELECT array_agg(word_id) FROM word
298 WHERE word_token = lookup_token and class is null and type is null
299 INTO return_word_ids;
300 RETURN return_word_ids;
303 LANGUAGE plpgsql STABLE STRICT;
306 CREATE OR REPLACE FUNCTION create_country(src HSTORE, country_code varchar(2))
316 FOR item IN SELECT (each(src)).* LOOP
318 s := make_standard_name(item.value);
319 w := getorcreate_country(s, country_code);
321 words := regexp_split_to_array(item.value, E'[,;()]');
322 IF array_upper(words, 1) != 1 THEN
323 FOR j IN 1..array_upper(words, 1) LOOP
324 s := make_standard_name(words[j]);
326 w := getorcreate_country(s, country_code);
336 CREATE OR REPLACE FUNCTION make_keywords(src HSTORE)
347 result := '{}'::INTEGER[];
349 FOR item IN SELECT (each(src)).* LOOP
351 s := make_standard_name(item.value);
352 w := getorcreate_name_id(s, item.value);
354 IF not(ARRAY[w] <@ result) THEN
355 result := result || w;
358 w := getorcreate_word_id(s);
360 IF w IS NOT NULL AND NOT (ARRAY[w] <@ result) THEN
361 result := result || w;
364 words := string_to_array(s, ' ');
365 IF array_upper(words, 1) IS NOT NULL THEN
366 FOR j IN 1..array_upper(words, 1) LOOP
367 IF (words[j] != '') THEN
368 w = getorcreate_word_id(words[j]);
369 IF w IS NOT NULL AND NOT (ARRAY[w] <@ result) THEN
370 result := result || w;
376 words := regexp_split_to_array(item.value, E'[,;()]');
377 IF array_upper(words, 1) != 1 THEN
378 FOR j IN 1..array_upper(words, 1) LOOP
379 s := make_standard_name(words[j]);
381 w := getorcreate_word_id(s);
382 IF w IS NOT NULL AND NOT (ARRAY[w] <@ result) THEN
383 result := result || w;
389 s := regexp_replace(item.value, '市$', '');
390 IF s != item.value THEN
391 s := make_standard_name(s);
393 w := getorcreate_name_id(s, item.value);
394 IF NOT (ARRAY[w] <@ result) THEN
395 result := result || w;
408 CREATE OR REPLACE FUNCTION precompute_words(src TEXT)
418 s := make_standard_name(src);
419 w := getorcreate_name_id(s, src);
421 w := getorcreate_word_id(s);
423 words := string_to_array(s, ' ');
424 IF array_upper(words, 1) IS NOT NULL THEN
425 FOR j IN 1..array_upper(words, 1) LOOP
426 IF (words[j] != '') THEN
427 w := getorcreate_word_id(words[j]);
432 words := regexp_split_to_array(src, E'[,;()]');
433 IF array_upper(words, 1) != 1 THEN
434 FOR j IN 1..array_upper(words, 1) LOOP
435 s := make_standard_name(words[j]);
437 w := getorcreate_word_id(s);
442 s := regexp_replace(src, '市$', '');
444 s := make_standard_name(s);
446 w := getorcreate_name_id(s, src);