php ./utils/update.php --init-updates
php ./utils/update.php --import-osmosis
working-directory: build
+
+ - name: Run reverse-only import
+ run : |
+ dropdb nominatim
+ php ./utils/setup.php --osm-file ../monaco-latest.osm.pbf --reverse-only --all
+ working-directory: build
* `viewbox=<x1>,<y1>,<x2>,<y2>`
The preferred area to find search results. Any two corner points of the box
-are accepted in any order as long as they span a real box. `x` is longitude,
+are accepted as long as they span a real box. `x` is longitude,
`y` is latitude.
$this->oNormalizer
);
+ $oCtx->setFullNameWords($oValidTokens->getFullWordIDs());
+
// Try more interpretations for Tokens that could not be matched.
foreach ($aTokens as $sToken) {
if ($sToken[0] == ' ' && !$oValidTokens->contains($sToken)) {
public $sqlCountryList = '';
/// List of place IDs to exclude (as SQL).
private $sqlExcludeList = '';
+ /// Subset of word ids of full words in the query.
+ private $aFullNameWords = array();
+ public function setFullNameWords($aWordList)
+ {
+ $this->aFullNameWords = $aWordList;
+ }
+
+ public function getFullNameTerms()
+ {
+ return $this->aFullNameWords;
+ }
/**
* Check if a reference point is defined.
private $bRareName = false;
/// List of word ids making up the address of the object.
private $aAddress = array();
- /// Subset of word ids of full words making up the address.
- private $aFullNameAddress = array();
/// List of word ids that appear in the name but should be ignored.
private $aNameNonSearch = array();
/// List of word ids that appear in the address but should be ignored.
) {
$oSearch = clone $this;
$oSearch->iSearchRank++;
+ if (strlen($oSearchTerm->sPostcode) < 4) {
+ $oSearch->iSearchRank += 4 - strlen($oSearchTerm->sPostcode);
+ }
$oSearch->sPostcode = $oSearchTerm->sPostcode;
$aNewSearches[] = $oSearch;
}
$oSearch->iSearchRank++;
}
$aNewSearches[] = $oSearch;
+ // Housenumbers may appear in the name when the place has its own
+ // address terms.
+ if ($oSearchTerm->iId !== null
+ && ($this->iNamePhrase >= 0 || empty($this->aName))
+ && empty($this->aAddress)
+ ) {
+ $oSearch = clone $this;
+ $oSearch->iSearchRank++;
+ $oSearch->aAddress = $this->aName;
+ $oSearch->aName = array($oSearchTerm->iId => $oSearchTerm->iId);
+ $aNewSearches[] = $oSearch;
+ }
}
} elseif ($sPhraseType == ''
&& is_a($oSearchTerm, '\Nominatim\Token\SpecialTerm')
if (!empty($this->aName) || !($bFirstPhrase || $sPhraseType == '')) {
if (($sPhraseType == '' || !$bFirstPhrase) && !$bHasPartial) {
$oSearch = clone $this;
- $oSearch->iSearchRank += 5;
+ $oSearch->iSearchRank += 3 * $oSearchTerm->iTermCount;
$oSearch->aAddress[$iWordID] = $iWordID;
$aNewSearches[] = $oSearch;
- } else {
- $this->aFullNameAddress[$iWordID] = $iWordID;
}
} else {
$oSearch = clone $this;
) {
if ($oSearchTerm->iSearchNameCount < CONST_Max_Word_Frequency) {
$oSearch = clone $this;
- $oSearch->iSearchRank += 2;
+ $oSearch->iSearchRank += $oSearchTerm->iTermCount;
+ if (empty($this->aName)) {
+ $oSearch->iSearchRank++;
+ }
+ if (preg_match('#^[0-9]+$#', $sToken)) {
+ $oSearch->iSearchRank++;
+ }
$oSearch->aAddress[$iWordID] = $iWordID;
$aNewSearches[] = $oSearch;
} else {
$oSearch = clone $this;
$oSearch->iSearchRank++;
$oSearch->aAddressNonSearch[$iWordID] = $iWordID;
- if (preg_match('#^[0-9]+$#', $sToken)) {
- $oSearch->iSearchRank += 2;
- }
if (!empty($aFullTokens)) {
$oSearch->iSearchRank++;
}
foreach ($aFullTokens as $oSearchTermToken) {
if (is_a($oSearchTermToken, '\Nominatim\Token\Word')) {
$oSearch = clone $this;
- $oSearch->iSearchRank++;
+ $oSearch->iSearchRank += 3;
$oSearch->aAddress[$oSearchTermToken->iId]
= $oSearchTermToken->iId;
$aNewSearches[] = $oSearch;
$sImportanceSQL .= $this->oContext->viewboxImportanceSQL('centroid');
$aOrder[] = "$sImportanceSQL DESC";
- if (!empty($this->aFullNameAddress)) {
+ $aFullNameAddress = $this->oContext->getFullNameTerms();
+ if (!empty($aFullNameAddress)) {
$sExactMatchSQL = ' ( ';
$sExactMatchSQL .= ' SELECT count(*) FROM ( ';
- $sExactMatchSQL .= ' SELECT unnest('.$oDB->getArraySQL($this->aFullNameAddress).')';
+ $sExactMatchSQL .= ' SELECT unnest('.$oDB->getArraySQL($aFullNameAddress).')';
$sExactMatchSQL .= ' INTERSECT ';
$sExactMatchSQL .= ' SELECT unnest(nameaddress_vector)';
$sExactMatchSQL .= ' ) s';
return isset($this->aTokens[$sWord]) ? $this->aTokens[$sWord] : array();
}
+ public function getFullWordIDs()
+ {
+ $ids = array();
+
+ foreach ($this->aTokens as $aTokenList) {
+ foreach ($aTokenList as $oToken) {
+ if (is_a($oToken, '\Nominatim\Token\Word') && !$oToken->bPartial) {
+ $ids[$oToken->iId] = $oToken->iId;
+ }
+ }
+ }
+
+ return $ids;
+ }
+
/**
* Add token information from the word table in the database.
*
$oToken = new Token\Word(
$iId,
$aWord['word_token'][0] != ' ',
- (int) $aWord['count']
+ (int) $aWord['count'],
+ substr_count($aWord['word_token'], ' ')
);
}
public $bPartial;
/// Number of appearances in the database.
public $iSearchNameCount;
+ /// Number of terms in the word.
+ public $iTermCount;
- public function __construct($iId, $bPartial, $iSearchNameCount)
+ public function __construct($iId, $bPartial, $iSearchNameCount, $iTermCount)
{
$this->iId = $iId;
$this->bPartial = $bPartial;
$this->iSearchNameCount = $iSearchNameCount;
+ $this->iTermCount = $iTermCount;
}
public function debugInfo()
"administrative8" : 14
}
}
+},
+{ "countries" : [ "nl" ],
+ "tags" : {
+ "boundary" : {
+ "administrative7" : [13, 0],
+ "administrative8" : 14,
+ "administrative9" : [15, 0],
+ "administrative10" : 16
+ }
+ }
}
]
IF search_unlisted_place is not null THEN
RETURN NEXT ROW(null, null, null, hstore('name', search_unlisted_place),
- 'place', 'locality', null, null, true, true, 26, 0)::addressline;
+ 'place', 'locality', null, null, true, true, 25, 0)::addressline;
END IF;
IF searchpostcode IS NOT NULL THEN
END LOOP;
END IF;
-
- -- If the POI is named, simply mix in all address terms and be done.
- IF array_length(initial_name_vector, 1) is not NULL THEN
- -- Cheating here by not recomputing all terms but simply using the ones
- -- from the parent object.
- name_vector := initial_name_vector;
- nameaddress_vector := array_merge(nameaddress_vector, parent_name_vector);
- nameaddress_vector := array_merge(nameaddress_vector, parent_address_vector);
-
- IF not address ? 'street' and address ? 'place' THEN
- -- make sure addr:place terms are always searchable
- nameaddress_vector := array_merge(nameaddress_vector,
- addr_ids_from_name(address->'place'));
- END IF;
-
- RETURN;
- END IF;
-
- ----- unnamed POIS
-
- IF (array_length(nameaddress_vector, 1) is null
- and (address ? 'street'or not address ? 'place'))
- or housenumber is null
- THEN
- RETURN;
- END IF;
+ name_vector := initial_name_vector;
-- Check if the parent covers all address terms.
-- If not, create a search name entry with the house number as the name.
-- This is unusual for the search_name table but prevents that the place
-- is returned when we only search for the street/place.
- IF not nameaddress_vector <@ parent_address_vector THEN
- name_vector := ARRAY[getorcreate_name_id(housenumber)];
+ IF housenumber is not null and not nameaddress_vector <@ parent_address_vector THEN
+ name_vector := array_merge(name_vector,
+ ARRAY[getorcreate_housenumber_id(make_standard_name(housenumber))]);
END IF;
IF not address ? 'street' and address ? 'place' THEN
addr_place_ids := addr_ids_from_name(address->'place');
IF not addr_place_ids <@ parent_name_vector THEN
- -- addr:place tag exists without a corresponding place. Mix in addr:place
- -- in the address.
- name_vector := ARRAY[getorcreate_name_id(housenumber)];
+ -- make sure addr:place terms are always searchable
nameaddress_vector := array_merge(nameaddress_vector, addr_place_ids);
+ -- If there is a housenumber, also add the place name as a name,
+ -- so we can search it by the usual housenumber+place algorithms.
+ IF housenumber is not null THEN
+ name_vector := array_merge(name_vector,
+ ARRAY[getorcreate_name_id(make_standard_name(address->'place'))]);
+ END IF;
END IF;
END IF;
- -- Merge the parent name and address.
+ -- Cheating here by not recomputing all terms but simply using the ones
+ -- from the parent object.
nameaddress_vector := array_merge(nameaddress_vector, parent_name_vector);
nameaddress_vector := array_merge(nameaddress_vector, parent_address_vector);
END IF;
- IF array_length(name_vector, 1) is not NULL
- OR inherited_address is not NULL OR NEW.address is not NULL
+ IF not %REVERSE-ONLY% AND (array_length(name_vector, 1) is not NULL
+ OR inherited_address is not NULL OR NEW.address is not NULL)
THEN
SELECT * INTO name_vector, nameaddress_vector
FROM create_poi_search_terms(NEW.place_id,
NEW.country_code, NEW.housenumber,
name_vector, NEW.centroid);
- IF not %REVERSE-ONLY% AND array_length(name_vector, 1) is not NULL THEN
+ IF array_length(name_vector, 1) is not NULL THEN
INSERT INTO search_name (place_id, search_rank, address_rank,
importance, country_code, name_vector,
nameaddress_vector, centroid)
FROM get_postcode_rank(country, postcode);
ELSEIF extended_type = 'N' AND place_class = 'highway' THEN
search_rank = 30;
- address_rank = 0;
+ address_rank = 30;
ELSEIF place_class = 'landuse' AND extended_type != 'A' THEN
search_rank = 30;
- address_rank = 0;
+ address_rank = 30;
ELSE
IF place_class = 'boundary' and place_type = 'administrative' THEN
classtype = place_type || admin_level::TEXT;
AND l.class = place_class AND (l.type = classtype or l.type is NULL)
ORDER BY l.country_code, l.class, l.type LIMIT 1;
- IF search_rank is NULL THEN
+ IF search_rank is NULL OR address_rank is NULL THEN
search_rank := 30;
- END IF;
-
- IF address_rank is NULL THEN
address_rank := 30;
END IF;
When importing
Then placex contains
| object | rank_search | rank_address |
- | N1 | 30 | 0 |
+ | N1 | 30 | 30 |
| W1 | 26 | 26 |
| W2 | 26 | 26 |
| W3 | 26 | 26 |
When importing
Then placex contains
| object | rank_search | rank_address |
- | N2 | 30 | 0 |
- | W2 | 30 | 0 |
+ | N2 | 30 | 30 |
+ | W2 | 30 | 30 |
| W4 | 22 | 22 |
| R2 | 22 | 22 |
| R3 | 22 | 0 |
| W1 | highway | residential | Rose Street | :w-north |
When importing
Then search_name contains
- | object | name_vector | nameaddress_vector |
- | N1 | #23 | Rose Street, Walltown |
+ | object | nameaddress_vector |
+ | N1 | Rose, Street, Walltown |
When searching for "23 Rose Street, Walltown"
Then results contain
| osm_type | osm_id | name |
| N | 1 | 23, Rose Street |
+ When searching for "Walltown, Rose Street 23"
+ Then results contain
+ | osm_type | osm_id | name |
+ | N | 1 | 23, Rose Street |
+ When searching for "Rose Street 23, Walltown"
+ Then results contain
+ | osm_type | osm_id | name |
+ | N | 1 | 23, Rose Street |
Scenario: Searching for unknown addr: tags also works for multiple words
Given the scene roads-with-pois
| W1 | highway | residential | Rose Street | :w-north |
When importing
Then search_name contains
- | object | name_vector | nameaddress_vector |
- | N1 | #23 | Rose Street, Little, Big, Town |
+ | object | nameaddress_vector |
+ | N1 | Rose Street, Little, Big, Town |
When searching for "23 Rose Street, Little Big Town"
Then results contain
| osm_type | osm_id | name |
| N | 1 | 23, Rose Street |
+ When searching for "Rose Street 23, Little Big Town"
+ Then results contain
+ | osm_type | osm_id | name |
+ | N | 1 | 23, Rose Street |
+ When searching for "Little big Town, Rose Street 23"
+ Then results contain
+ | osm_type | osm_id | name |
+ | N | 1 | 23, Rose Street |
Scenario: Unnamed POI has no search entry when it has known addr: tags
Given the scene roads-with-pois
| N1 | N2 |
Then search_name contains
| object | name_vector | nameaddress_vector |
- | N1 | #23 | Walltown, Strange, Town |
+ | N1 | #Walltown | Strange, Town |
When searching for "23 Rose Street"
Then exactly 1 results are returned
And results contain
Then results contain
| osm_type | osm_id | name |
| N | 1 | 23, Walltown, Strange Town |
+ When searching for "Walltown 23, Strange Town"
+ Then results contain
+ | osm_type | osm_id | name |
+ | N | 1 | 23, Walltown, Strange Town |
+ When searching for "Strange Town, Walltown 23"
+ Then results contain
+ | osm_type | osm_id | name |
+ | N | 1 | 23, Walltown, Strange Town |
+
+ Scenario: Named POIs can be searched by housenumber when unknown addr:place is present
+ Given the scene roads-with-pois
+ And the places
+ | osm | class | type | name | housenr | addr+place | geometry |
+ | N1 | place | house | Blue house | 23 | Walltown | :p-N1 |
+ And the places
+ | osm | class | type | name+name | geometry |
+ | W1 | highway | residential | Rose Street | :w-north |
+ | N2 | place | city | Strange Town | :p-N1 |
+ When importing
+ Then search_name contains
+ | object | name_vector | nameaddress_vector |
+ | N1 | #Walltown, #Blue house | Walltown, Strange, Town |
+ When searching for "23 Walltown, Strange Town"
+ Then results contain
+ | osm_type | osm_id | name |
+ | N | 1 | Blue house, 23, Walltown, Strange Town |
+ When searching for "Walltown 23, Strange Town"
+ Then results contain
+ | osm_type | osm_id | name |
+ | N | 1 | Blue house, 23, Walltown, Strange Town |
+ When searching for "Strange Town, Walltown 23"
+ Then results contain
+ | osm_type | osm_id | name |
+ | N | 1 | Blue house, 23, Walltown, Strange Town |
+ When searching for "Strange Town, Walltown 23, Blue house"
+ Then results contain
+ | osm_type | osm_id | name |
+ | N | 1 | Blue house, 23, Walltown, Strange Town |
+ When searching for "Strange Town, Walltown, Blue house"
+ Then results contain
+ | osm_type | osm_id | name |
+ | N | 1 | Blue house, 23, Walltown, Strange Town |
+
+ Scenario: Named POIs can be found when unknown multi-word addr:place is present
+ Given the scene roads-with-pois
+ And the places
+ | osm | class | type | name | housenr | addr+place | geometry |
+ | N1 | place | house | Blue house | 23 | Moon sun | :p-N1 |
+ And the places
+ | osm | class | type | name+name | geometry |
+ | W1 | highway | residential | Rose Street | :w-north |
+ | N2 | place | city | Strange Town | :p-N1 |
+ When importing
+ Then search_name contains
+ | object | name_vector | nameaddress_vector |
+ | N1 | #Moon sun, #Blue house | Moon, Sun, Strange, Town |
+ When searching for "23 Moon Sun, Strange Town"
+ Then results contain
+ | osm_type | osm_id | name |
+ | N | 1 | Blue house, 23, Moon sun, Strange Town |
+ When searching for "Blue house, Moon Sun, Strange Town"
+ Then results contain
+ | osm_type | osm_id | name |
+ | N | 1 | Blue house, 23, Moon sun, Strange Town |
Scenario: Unnamed POIs doesn't inherit parent name when addr:place is present only in parent address
Given the scene roads-with-pois
When importing
Then search_name contains
| object | name_vector | nameaddress_vector |
- | N1 | #23 | Walltown |
+ | N1 | #Walltown | Strange, Town |
When searching for "23 Rose Street, Walltown"
Then exactly 1 result is returned
And results contain
When searching for "23 Lily Street"
Then exactly 0 results are returned
- Scenario: Named POIs have unknown address tags added in the search_name table
+ Scenario: Named POIs get unknown address tags added in the search_name table
Given the scene roads-with-pois
And the places
- | osm | class | type | name+name | addr+city | geometry |
- | N1 | place | house | Green Moss | Walltown | :p-N1 |
+ | osm | class | type | name+name | housenr | addr+city | geometry |
+ | N1 | place | house | Green Moss | 26 | Walltown | :p-N1 |
And the places
| osm | class | type | name+name | geometry |
| W1 | highway | residential | Rose Street | :w-north |
When importing
Then search_name contains
| object | name_vector | nameaddress_vector |
- | N1 | #Green Moss | Rose Street, Walltown |
+ | N1 | #Green Moss | Rose, Street, Walltown |
When searching for "Green Moss, Rose Street, Walltown"
Then results contain
| osm_type | osm_id | name |
- | N | 1 | Green Moss, Rose Street |
+ | N | 1 | Green Moss, 26, Rose Street |
+ When searching for "Green Moss, 26, Rose Street, Walltown"
+ Then results contain
+ | osm_type | osm_id | name |
+ | N | 1 | Green Moss, 26, Rose Street |
+ When searching for "26, Rose Street, Walltown"
+ Then results contain
+ | osm_type | osm_id | name |
+ | N | 1 | Green Moss, 26, Rose Street |
+ When searching for "Rose Street 26, Walltown"
+ Then results contain
+ | osm_type | osm_id | name |
+ | N | 1 | Green Moss, 26, Rose Street |
+ When searching for "Walltown, Rose Street 26"
+ Then results contain
+ | osm_type | osm_id | name |
+ | N | 1 | Green Moss, 26, Rose Street |
Scenario: Named POI doesn't inherit parent name when addr:place is present only in parent address
Given the scene roads-with-pois
""",
(terms, words))
if not exclude:
- ok_(subcur.rowcount >= len(terms),
- "No word entry found for " + row[h])
+ ok_(subcur.rowcount >= len(terms) + len(words),
+ "No word entry found for " + row[h] + ". Entries found: " + str(subcur.rowcount))
for wid in subcur:
if exclude:
assert_not_in(wid[0], res[h],
$this->assertEquals(array(new Token\HouseNumber(999, '1051')), $TL->get('1051'));
$this->assertEquals(array(new Token\Country(999, 'de')), $TL->get('alemagne'));
$this->assertEquals(array(new Token\Postcode(999, '64286')), $TL->get('64286'));
- $this->assertEquals(array(new Token\Word(999, true, 533)), $TL->get('darmstadt'));
+ $this->assertEquals(array(new Token\Word(999, true, 533, 0)), $TL->get('darmstadt'));
}
}
$oGeocode = new Nominatim\Geocode($oDB);
$oGeocode->setLanguagePreference($oParams->getPreferredLanguages(false));
+$oGeocode->setReverseInPlan(true);
$oGeocode->loadParamArray($oParams);
if ($oParams->getBool('search')) {