import itertools
import json
import logging
-import re
from textwrap import dedent
from nominatim.db.connection import connect
@define('CONST_Max_Word_Frequency', 10000000);
@define('CONST_Term_Normalization_Rules', "{self.loader.normalization_rules}");
@define('CONST_Transliteration', "{self.loader.get_search_rules()}");
- require_once('{phpdir}/tokenizer/icu_tokenizer.php');"""))
+ require_once('{phpdir}/tokenizer/icu_tokenizer.php');"""), encoding='utf-8')
def _save_config(self):
+ [(k, v, part_ids.get(v, None)) for k, v in partial_tokens.items()]
- @staticmethod
- def normalize_postcode(postcode):
+ def normalize_postcode(self, postcode):
""" Convert the postcode to a standardized form.
This function must yield exactly the same result as the SQL function
def _process_place_address(self, token_info, address):
for item in address:
if item.kind == 'postcode':
- self._add_postcode(item.name)
+ token_info.set_postcode(self._add_postcode(item))
elif item.kind == 'housenumber':
token_info.add_housenumber(*self._compute_housenumber_token(item))
elif item.kind == 'street':
if not item.suffix:
token_info.add_place(self._compute_partial_tokens(item.name))
elif not item.kind.startswith('_') and not item.suffix and \
- item.kind not in ('country', 'full'):
+ item.kind not in ('country', 'full', 'inclusion'):
token_info.add_address_term(item.kind, self._compute_partial_tokens(item.name))
return full_tokens, partial_tokens
- def _add_postcode(self, postcode):
+ def _add_postcode(self, item):
""" Make sure the normalized postcode is present in the word table.
"""
- if re.search(r'[:,;]', postcode) is None:
- postcode = self.normalize_postcode(postcode)
+ analyzer = self.token_analysis.get_analyzer('@postcode')
+
+ if analyzer is None:
+ postcode_name = item.name.strip().upper()
+ variant_base = None
+ else:
+ postcode_name = analyzer.normalize(item.name)
+ variant_base = item.get_attr("variant")
- if postcode not in self._cache.postcodes:
- term = self._search_normalized(postcode)
- if not term:
- return
+ if variant_base is not None:
+ postcode = f'{postcode_name}@{variant_base}'
+ else:
+ postcode = postcode_name
- with self.conn.cursor() as cur:
- # no word_id needed for postcodes
- cur.execute("""INSERT INTO word (word_token, type, word)
- (SELECT %s, 'P', pc FROM (VALUES (%s)) as v(pc)
- WHERE NOT EXISTS
- (SELECT * FROM word
- WHERE type = 'P' and word = pc))
- """, (term, postcode))
- self._cache.postcodes.add(postcode)
+ if postcode not in self._cache.postcodes:
+ term = self._search_normalized(postcode_name)
+ if not term:
+ return
+
+ variants = {term}
+ if analyzer is not None and variant_base is not None:
+ variants.update(analyzer.get_variants_ascii(variant_base))
+
+ with self.conn.cursor() as cur:
+ cur.execute("SELECT create_postcode_word(%s, %s)",
+ (postcode, list(variants)))
+ self._cache.postcodes.add(postcode)
class _TokenInfo:
self.street_tokens = set()
self.place_tokens = set()
self.address_tokens = {}
+ self.postcode = None
@staticmethod
if partials:
self.address_tokens[key] = self._mk_array(partials)
+ def set_postcode(self, postcode):
+ """ Set the postcode to the given one.
+ """
+ self.postcode = postcode
+
class _TokenCache:
""" Cache for token information to avoid repeated database queries.