1 # SPDX-License-Identifier: GPL-3.0-or-later
3 # This file is part of Nominatim. (https://nominatim.org)
5 # Copyright (C) 2026 by the Nominatim developer community.
6 # For a full list of authors see the git log.
8 Abstract class definitions for tokenizers. These base classes are here
9 mainly for documentation purposes.
11 from abc import ABC, abstractmethod
12 from typing import List, Tuple, Any, Optional, Iterable
14 from ..typing import Protocol
15 from ..config import Configuration
16 from ..db.connection import Connection
17 from ..data.place_info import PlaceInfo
18 from ..data.place_name import PlaceNames
21 class AbstractAnalyzer(ABC):
22 """ The analyzer provides the functions for analysing names and building
25 Analyzers are instantiated on a per-thread base. Access to global data
26 structures must be synchronised accordingly.
29 def __enter__(self) -> 'AbstractAnalyzer':
32 def __exit__(self, exc_type: Any, exc_value: Any, traceback: Any) -> None:
36 def close(self) -> None:
37 """ Free all resources used by the analyzer.
41 def get_word_token_info(self, words: List[str]) -> List[Tuple[str, str, Optional[int]]]:
42 """ Return token information for the given list of words.
44 The function is used for testing and debugging only
45 and does not need to be particularly efficient.
48 words: A list of words to look up the tokens for.
49 If a word starts with # it is assumed to be a full name
50 otherwise is a partial term.
53 The function returns the list of all tuples that could be
54 found for the given words. Each list entry is a tuple of
55 (original word, word token, word id).
59 def normalize_postcode(self, postcode: str) -> str:
60 """ Convert the postcode to its standardized form.
63 postcode: The postcode to be normalized.
66 The given postcode after normalization.
70 def update_postcodes_from_db(self) -> None:
71 """ Update the tokenizer's postcode tokens from the current content
72 of the `location_postcodes` table.
76 def update_special_phrases(self,
77 phrases: Iterable[Tuple[str, str, str, str]],
78 should_replace: bool) -> None:
79 """ Update the tokenizer's special phrase tokens from the given
80 list of special phrases.
83 phrases: The new list of special phrases. Each entry is
84 a tuple of (phrase, class, type, operator).
85 should_replace: If true, replace the current list of phrases.
86 When false, just add the given phrases to the
87 ones that already exist.
91 def add_country_names(self, country_code: str, names: PlaceNames) -> None:
92 """ Add the given names to the tokenizer's list of country tokens.
95 country_code: two-letter country code for the country the names
97 names: List of names to add.
101 def process_place(self, place: PlaceInfo) -> Any:
102 """ Extract tokens for the given place and compute the
103 information to be handed to the PL/pgSQL processor for building
107 place: Place information retrieved from the database.
110 A JSON-serialisable structure that will be handed into
111 the database via the `token_info` field.
115 class AbstractTokenizer(ABC):
116 """ The tokenizer instance is the central instance of the tokenizer in
117 the system. There will only be a single instance of the tokenizer
122 def init_new_db(self, config: Configuration, init_db: bool = True) -> None:
123 """ Set up a new tokenizer for the database.
125 The function should copy all necessary data into the project
126 directory or save it in the property table to make sure that
127 the tokenizer remains stable over updates.
130 config: Read-only object with configuration options.
132 init_db: When set to False, then initialisation of database
133 tables should be skipped. This option is only required for
134 migration purposes and can be safely ignored by custom
139 def init_from_project(self, config: Configuration) -> None:
140 """ Initialise the tokenizer from an existing database setup.
142 The function should load all previously saved configuration from
143 the project directory and/or the property table.
146 config: Read-only object with configuration options.
150 def finalize_import(self, config: Configuration, threads: int = 1) -> None:
151 """ This function is called at the very end of an import when all
152 data has been imported and indexed. The tokenizer may create
153 at this point any additional indexes and data structures needed
157 config: Read-only object with configuration options.
158 threads: Number of threads to use
162 def update_sql_functions(self, config: Configuration) -> None:
163 """ Update the SQL part of the tokenizer. This function is called
164 automatically on migrations or may be called explicitly by the
165 user through the `nominatim refresh --functions` command.
167 The tokenizer must only update the code of the tokenizer. The
168 data structures or data itself must not be changed by this function.
171 config: Read-only object with configuration options.
175 def check_database(self, config: Configuration) -> Optional[str]:
176 """ Check that the database is set up correctly and ready for being
180 config: Read-only object with configuration options.
183 If an issue was found, return an error message with the
184 description of the issue as well as hints for the user on
185 how to resolve the issue. If everything is okay, return `None`.
189 def update_statistics(self, config: Configuration, threads: int = 1) -> None:
190 """ Recompute any tokenizer statistics necessary for efficient lookup.
191 This function is meant to be called from time to time by the user
192 to improve performance. However, the tokenizer must not depend on
193 it to be called in order to work.
197 def update_word_tokens(self) -> None:
198 """ Do house-keeping on the tokenizers internal data structures.
199 Remove unused word tokens, resort data etc.
203 def name_analyzer(self) -> AbstractAnalyzer:
204 """ Create a new analyzer for tokenizing names and queries
205 using this tokinzer. Analyzers are context managers and should
209 with tokenizer.name_analyzer() as analyzer:
213 When used outside the with construct, the caller must ensure to
214 call the close() function before destructing the analyzer.
218 def most_frequent_words(self, conn: Connection, num: int) -> List[str]:
219 """ Return a list of the most frequent full words in the database.
222 conn: Open connection to the database which may be used to
224 num: Maximum number of words to return.
228 class TokenizerModule(Protocol):
229 """ Interface that must be exported by modules that implement their
233 def create(self, dsn: str) -> AbstractTokenizer:
234 """ Factory for new tokenizers.