mirror of
https://github.com/osm-search/Nominatim.git
synced 2026-02-14 18:37:58 +00:00
Compare commits
771 Commits
helm-chart
...
4.2.x
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6c03099372 | ||
|
|
9f11be4c6a | ||
|
|
6d4da5123c | ||
|
|
037042f85b | ||
|
|
1da2192fb0 | ||
|
|
35a5424332 | ||
|
|
1187d0ab9a | ||
|
|
ffe32af531 | ||
|
|
5baa827b8a | ||
|
|
3a3475acce | ||
|
|
b17cdb5740 | ||
|
|
069f3f5dea | ||
|
|
18f912b29f | ||
|
|
35e7e52501 | ||
|
|
067719481f | ||
|
|
8b6540c989 | ||
|
|
325392310f | ||
|
|
0265d6dafc | ||
|
|
637ef30af1 | ||
|
|
45c184d45b | ||
|
|
28770146f9 | ||
|
|
a9444a06c5 | ||
|
|
d756e5f0e5 | ||
|
|
fabe45f60a | ||
|
|
1de8bdaafe | ||
|
|
000a70639f | ||
|
|
6eadf6797e | ||
|
|
40b061afd2 | ||
|
|
eb3a6aa509 | ||
|
|
9f7e6da971 | ||
|
|
3729bdde7d | ||
|
|
f8df574b78 | ||
|
|
51f3485874 | ||
|
|
a0e107d57f | ||
|
|
b6ae3f3f09 | ||
|
|
4f1ddcd521 | ||
|
|
34d629f677 | ||
|
|
bb613a1d85 | ||
|
|
2fe0e0629a | ||
|
|
a0e4e123b1 | ||
|
|
92abae7850 | ||
|
|
6fe3dc63f5 | ||
|
|
e2dcc9ebf8 | ||
|
|
9b233362c6 | ||
|
|
a727624b9e | ||
|
|
3313369a39 | ||
|
|
7d140970b7 | ||
|
|
cfd631e99c | ||
|
|
3d39847e26 | ||
|
|
a664beb810 | ||
|
|
04ee39467a | ||
|
|
1f3edf6eba | ||
|
|
a15c197547 | ||
|
|
13dbeb75c7 | ||
|
|
6aded60045 | ||
|
|
8dfdf64dd5 | ||
|
|
41e8bddaa9 | ||
|
|
fd3dec8efe | ||
|
|
55ee08f42b | ||
|
|
b6ff697ff0 | ||
|
|
925ac1e1b9 | ||
|
|
77acc1c2be | ||
|
|
ebe489c227 | ||
|
|
9c152a030a | ||
|
|
b310c86c55 | ||
|
|
c9ff7d2130 | ||
|
|
52456230cc | ||
|
|
4422533adb | ||
|
|
c4b13f2b7f | ||
|
|
4f05a03d13 | ||
|
|
7a2e586cce | ||
|
|
98ce424650 | ||
|
|
3059a3da4e | ||
|
|
d63d7cb9a8 | ||
|
|
f3f542e864 | ||
|
|
93ada250f7 | ||
|
|
d8e3ba3b54 | ||
|
|
a46348da38 | ||
|
|
36cf0eb922 | ||
|
|
63a9bc94f7 | ||
|
|
2dafc4cf4f | ||
|
|
68d09f9cad | ||
|
|
b98d3d3f00 | ||
|
|
3683cf7ddc | ||
|
|
84e5e601e1 | ||
|
|
a1da149211 | ||
|
|
74405e9684 | ||
|
|
2fac507453 | ||
|
|
51ed55cc32 | ||
|
|
de2a3bd5f8 | ||
|
|
981e9700be | ||
|
|
b52ce4f9f2 | ||
|
|
64c591da7f | ||
|
|
2387648a85 | ||
|
|
846ecff0c5 | ||
|
|
26a5b59c28 | ||
|
|
6ddb39fda3 | ||
|
|
1fdcec985a | ||
|
|
30f526c943 | ||
|
|
253127cb9f | ||
|
|
3237ca587f | ||
|
|
0dbc0ae6d5 | ||
|
|
7461ff4680 | ||
|
|
afc714e1d3 | ||
|
|
3bc0db8d91 | ||
|
|
d573da5b2c | ||
|
|
ecd5a3fdf9 | ||
|
|
543d63e7a9 | ||
|
|
7a22ae6bf9 | ||
|
|
ebe23d6882 | ||
|
|
33c805aee0 | ||
|
|
616ff4ae25 | ||
|
|
e221eaa977 | ||
|
|
eed7abb839 | ||
|
|
5f6dcd36ed | ||
|
|
f395054536 | ||
|
|
afeafc8aa7 | ||
|
|
f1ece658f8 | ||
|
|
b3abb355eb | ||
|
|
5877b69d51 | ||
|
|
5ec2c1b712 | ||
|
|
0a73ed7d64 | ||
|
|
abf349fb0d | ||
|
|
3185fad918 | ||
|
|
0ab0f0ea44 | ||
|
|
ac467c7a2d | ||
|
|
c85b74497b | ||
|
|
3381a92d92 | ||
|
|
a2ee58d8a1 | ||
|
|
051f3720ce | ||
|
|
f017e1e9a1 | ||
|
|
33ba6896a8 | ||
|
|
f4d3ae6f70 | ||
|
|
860f3559a1 | ||
|
|
d8be8a7293 | ||
|
|
9750a361c9 | ||
|
|
ed3dd81d04 | ||
|
|
bef1aebf1c | ||
|
|
26688ba35d | ||
|
|
a1158feeb8 | ||
|
|
aef014a47d | ||
|
|
d6a0947e5a | ||
|
|
bc94318d83 | ||
|
|
d4c6e58b57 | ||
|
|
66832cf0a5 | ||
|
|
bcfe817212 | ||
|
|
07d72f950b | ||
|
|
dddfa3a075 | ||
|
|
74019877a4 | ||
|
|
465d82a92f | ||
|
|
49f889bf09 | ||
|
|
5e477e3b5b | ||
|
|
67cfad6a2c | ||
|
|
487e81fe3c | ||
|
|
18f525ac54 | ||
|
|
e0c184e097 | ||
|
|
78716ab8b9 | ||
|
|
8d082c13e0 | ||
|
|
196dc2a659 | ||
|
|
4fe797d704 | ||
|
|
3c188164ab | ||
|
|
5330370076 | ||
|
|
eecc73ea1a | ||
|
|
8c73c0795e | ||
|
|
7d68aa8f04 | ||
|
|
a0cd96e05e | ||
|
|
b19c90b9a6 | ||
|
|
e427712cb0 | ||
|
|
9864b191b1 | ||
|
|
e7574f119e | ||
|
|
51b6d16dc6 | ||
|
|
34d27ed45c | ||
|
|
094100bbf6 | ||
|
|
c8873d34af | ||
|
|
f0d640961a | ||
|
|
3746befd88 | ||
|
|
a8b037669a | ||
|
|
d819036daa | ||
|
|
6d41046b15 | ||
|
|
7b7203c149 | ||
|
|
95d4061b2a | ||
|
|
375b57a96a | ||
|
|
12ace4329d | ||
|
|
09e0be0e39 | ||
|
|
cd4bcea894 | ||
|
|
1bee151fe3 | ||
|
|
f5e52e748f | ||
|
|
b7f6c7c76a | ||
|
|
bc7f6209d8 | ||
|
|
372a548c28 | ||
|
|
5aad105c73 | ||
|
|
f40c83d025 | ||
|
|
83054af46f | ||
|
|
cb81f11422 | ||
|
|
a849f3c9ec | ||
|
|
25d854dc5c | ||
|
|
9963261d8d | ||
|
|
459ab3bbdc | ||
|
|
a21d4d3ac4 | ||
|
|
4da1f0da6f | ||
|
|
17bbe2637a | ||
|
|
6c6bbe5747 | ||
|
|
18b16e06ca | ||
|
|
e37cfc64d2 | ||
|
|
77510f4a3b | ||
|
|
d35e3c25b6 | ||
|
|
62eedbb8f6 | ||
|
|
5617bffe2f | ||
|
|
8adab2c6ca | ||
|
|
d0c44431d0 | ||
|
|
282a61ce51 | ||
|
|
7a1d22ff15 | ||
|
|
0dff71a410 | ||
|
|
26f30bff28 | ||
|
|
e6775e713c | ||
|
|
69f9122bef | ||
|
|
fc254fc744 | ||
|
|
845c43137a | ||
|
|
aaf2b6032e | ||
|
|
c4928c646d | ||
|
|
f12fe54d2b | ||
|
|
fc03c0266a | ||
|
|
7b042de300 | ||
|
|
681aad7e0d | ||
|
|
f22fa992f7 | ||
|
|
992e6f72cf | ||
|
|
e6ee3c772c | ||
|
|
9d716f0f7d | ||
|
|
95ed95c616 | ||
|
|
bf36f33e79 | ||
|
|
58ab8319b9 | ||
|
|
a87cb77ce8 | ||
|
|
2be45a35b4 | ||
|
|
9b636fdc10 | ||
|
|
b1903f0fbf | ||
|
|
00f5b78160 | ||
|
|
d58061473e | ||
|
|
33cb925f2e | ||
|
|
c70ca7f57b | ||
|
|
a6dab5e300 | ||
|
|
7cafec0750 | ||
|
|
4b12d52ef5 | ||
|
|
300612c5a8 | ||
|
|
856925d19b | ||
|
|
cbbcbb1fd7 | ||
|
|
bce93d60bd | ||
|
|
69e51aebab | ||
|
|
8ac133f2ee | ||
|
|
67996929e0 | ||
|
|
ccf119206d | ||
|
|
bc63f10057 | ||
|
|
6f15306766 | ||
|
|
161d83af5b | ||
|
|
3bf3b894ea | ||
|
|
536f08f33a | ||
|
|
3dd7410bb7 | ||
|
|
93d5be097a | ||
|
|
6eb9044353 | ||
|
|
612d34930b | ||
|
|
5be320368c | ||
|
|
7f2ad4ac7e | ||
|
|
0f00f4968c | ||
|
|
37b2c6a830 | ||
|
|
e86db3001f | ||
|
|
7b6ec4fc6c | ||
|
|
67dfa38e60 | ||
|
|
2eca9fc8af | ||
|
|
b5e5efc131 | ||
|
|
80ea13437d | ||
|
|
bf86b45178 | ||
|
|
4885fdf0f9 | ||
|
|
b7704833e4 | ||
|
|
ca7b46511d | ||
|
|
18864afa8a | ||
|
|
5ba75df507 | ||
|
|
9cf700e85d | ||
|
|
9172696324 | ||
|
|
49626ba709 | ||
|
|
baee6f3de0 | ||
|
|
28ab2f6048 | ||
|
|
90d4d339db | ||
|
|
6e0014e138 | ||
|
|
8080625747 | ||
|
|
21fb501699 | ||
|
|
0cd3a1b9bd | ||
|
|
8de483a45b | ||
|
|
3ea87169ac | ||
|
|
42d16d8296 | ||
|
|
adf3ae004f | ||
|
|
fced1172c4 | ||
|
|
299e98776e | ||
|
|
b803505402 | ||
|
|
8fb9795d04 | ||
|
|
d8623d6818 | ||
|
|
6c58a4c46c | ||
|
|
19f67e167c | ||
|
|
00d8df6fc3 | ||
|
|
02068aec7f | ||
|
|
3493d317e4 | ||
|
|
a2b486a5b0 | ||
|
|
3d0f8bdc39 | ||
|
|
04644102f2 | ||
|
|
f833cc80df | ||
|
|
df0142678a | ||
|
|
800240550b | ||
|
|
15cf7dd416 | ||
|
|
2c05fc858a | ||
|
|
a024c7665c | ||
|
|
cbb4749996 | ||
|
|
4b0d9f71e8 | ||
|
|
218c56f9a6 | ||
|
|
a35eda3d2a | ||
|
|
8a0e3e2f3d | ||
|
|
12a3d51bcc | ||
|
|
60367d95dd | ||
|
|
bd0e157b91 | ||
|
|
1821f68ca0 | ||
|
|
b5ac546275 | ||
|
|
46689df668 | ||
|
|
e828d0d3f7 | ||
|
|
cce0e5ea38 | ||
|
|
042e314589 | ||
|
|
61d813bfef | ||
|
|
ecee5cf801 | ||
|
|
9e4e913bf7 | ||
|
|
98fc528d8e | ||
|
|
d1cd2d1674 | ||
|
|
b593fe9c3e | ||
|
|
6ca6725f6e | ||
|
|
1d203fdb3c | ||
|
|
3f30699131 | ||
|
|
22bd9c4993 | ||
|
|
4654701c10 | ||
|
|
8a67ddcb2b | ||
|
|
ab71f17c47 | ||
|
|
f314abcfe1 | ||
|
|
2d1a22705f | ||
|
|
e74e577029 | ||
|
|
aa0ae610c6 | ||
|
|
dc6c4bf22e | ||
|
|
a7a5f0161f | ||
|
|
739fe1c2c4 | ||
|
|
3ba975466c | ||
|
|
d14a585cc9 | ||
|
|
7f7a7df3a2 | ||
|
|
5d5f40a82f | ||
|
|
ae6b029543 | ||
|
|
bb2bd76f91 | ||
|
|
4e1e166c6a | ||
|
|
5ff35d9984 | ||
|
|
c6a426a885 | ||
|
|
11103268e9 | ||
|
|
b332b1ae23 | ||
|
|
7e70e5f503 | ||
|
|
99fa23040a | ||
|
|
adeebec32a | ||
|
|
b93ef23d3f | ||
|
|
4002bee0c1 | ||
|
|
ed6fda6968 | ||
|
|
2ae13c5583 | ||
|
|
821dabb138 | ||
|
|
9d468f6da0 | ||
|
|
3a8ddf736e | ||
|
|
720c7b7519 | ||
|
|
0de83c4a51 | ||
|
|
8c073993ef | ||
|
|
a79ab41782 | ||
|
|
f509526e5c | ||
|
|
896199c9d4 | ||
|
|
08672cdf0a | ||
|
|
8163723e22 | ||
|
|
32a5f812a9 | ||
|
|
372874e89a | ||
|
|
8ebb8ee304 | ||
|
|
3d58254462 | ||
|
|
95de411a81 | ||
|
|
439d17569d | ||
|
|
8bcdba1a14 | ||
|
|
37e5f07d83 | ||
|
|
3c68b12176 | ||
|
|
63dc4b39bc | ||
|
|
0ea099bfd5 | ||
|
|
310776671b | ||
|
|
4b84de400b | ||
|
|
8677da2a72 | ||
|
|
de828b723e | ||
|
|
a515761193 | ||
|
|
784dad866f | ||
|
|
403e6f7e5c | ||
|
|
27f7c7fd88 | ||
|
|
4f59644cc2 | ||
|
|
c3f1d34b71 | ||
|
|
f8f20899a3 | ||
|
|
a319b0a0b4 | ||
|
|
604ddc0f9d | ||
|
|
126cabacb8 | ||
|
|
f78ae969e9 | ||
|
|
d1479072ae | ||
|
|
9a56e53d50 | ||
|
|
7899654675 | ||
|
|
a79c1bda9b | ||
|
|
665fae8343 | ||
|
|
6bee188f24 | ||
|
|
82dbcbb12a | ||
|
|
76c146f326 | ||
|
|
fd4ab3f262 | ||
|
|
cfbd3652ef | ||
|
|
e9c14979a4 | ||
|
|
e9f979b67b | ||
|
|
a323b8f63a | ||
|
|
9411c14fd2 | ||
|
|
8525e7542f | ||
|
|
7dabbc5462 | ||
|
|
de18cd1523 | ||
|
|
36a1560117 | ||
|
|
b5f311d6bc | ||
|
|
83dd4362aa | ||
|
|
a71cab639b | ||
|
|
5e0155ae29 | ||
|
|
afef83b1c6 | ||
|
|
9db13aac72 | ||
|
|
9a1f891998 | ||
|
|
7bb7ed468a | ||
|
|
4fc61d260f | ||
|
|
1ceb6926b7 | ||
|
|
d33c82cb66 | ||
|
|
4c66c35ed6 | ||
|
|
54db1d8915 | ||
|
|
a0ed80d821 | ||
|
|
e65913d376 | ||
|
|
2f266d946b | ||
|
|
b6ac4ad837 | ||
|
|
42f0282f14 | ||
|
|
af739d2f57 | ||
|
|
fa2aca1cbc | ||
|
|
943e5fe699 | ||
|
|
d09670d208 | ||
|
|
83b4b8d9c1 | ||
|
|
d32a7c1888 | ||
|
|
d0c1b73fb3 | ||
|
|
90ac15748e | ||
|
|
6be2077d92 | ||
|
|
456d439e97 | ||
|
|
2723553593 | ||
|
|
23de4c7aca | ||
|
|
ce14964943 | ||
|
|
e133476c35 | ||
|
|
524dc64ab7 | ||
|
|
17da5f45be | ||
|
|
42cd021d04 | ||
|
|
433d2f4c7d | ||
|
|
be8f5778a1 | ||
|
|
ef98a85b05 | ||
|
|
b4bd4ff67d | ||
|
|
930a5cd12a | ||
|
|
7e3701b64a | ||
|
|
165d17f7f7 | ||
|
|
3939cb614e | ||
|
|
377cf36be3 | ||
|
|
8b6652a40b | ||
|
|
479d726774 | ||
|
|
1fcc9717bb | ||
|
|
c35b3ea5c7 | ||
|
|
15beeef6ce | ||
|
|
92bc3cd0a7 | ||
|
|
0a9f971e44 | ||
|
|
4a3bbd0319 | ||
|
|
89e1446131 | ||
|
|
b694a97edf | ||
|
|
13ed184efd | ||
|
|
f03a05f6bb | ||
|
|
a6903651fc | ||
|
|
b8c544cc98 | ||
|
|
243725aae1 | ||
|
|
0bb59b2e22 | ||
|
|
837d44391c | ||
|
|
691ec08586 | ||
|
|
5425394654 | ||
|
|
1d82569f6d | ||
|
|
f74228830d | ||
|
|
a9e3329c39 | ||
|
|
a3e4e8e5cd | ||
|
|
898febcec5 | ||
|
|
855909b4e9 | ||
|
|
85d65a2fd2 | ||
|
|
cd9b0c9a20 | ||
|
|
0e11ca9b76 | ||
|
|
fd38dd02ce | ||
|
|
474418f03c | ||
|
|
6b9fea6f1a | ||
|
|
02894ca4a4 | ||
|
|
7d19209fa1 | ||
|
|
a6b4e8ff67 | ||
|
|
38c3ef3da0 | ||
|
|
610f2cc254 | ||
|
|
a79a3210e6 | ||
|
|
39ede26b5c | ||
|
|
c3f206733f | ||
|
|
69481d1590 | ||
|
|
6877668cab | ||
|
|
dc520bd156 | ||
|
|
bc4a343502 | ||
|
|
fbc8884693 | ||
|
|
c50c534d19 | ||
|
|
45627b485f | ||
|
|
b6fa121f53 | ||
|
|
9b31ffaa9f | ||
|
|
39e300640e | ||
|
|
2ffc1537e7 | ||
|
|
64abc90d30 | ||
|
|
788505095e | ||
|
|
98432395c3 | ||
|
|
6b89624f33 | ||
|
|
4b28b4fed4 | ||
|
|
fea4dbba50 | ||
|
|
83d2c440d5 | ||
|
|
e6d855b954 | ||
|
|
9f64c34f1a | ||
|
|
638ed15ada | ||
|
|
c0d8b95f67 | ||
|
|
c65938d53c | ||
|
|
2e3f3a55f1 | ||
|
|
cdd0f78bc6 | ||
|
|
9fac20ceef | ||
|
|
38bd08d25f | ||
|
|
b44493e7f2 | ||
|
|
f6ec8d2e33 | ||
|
|
c170d323d9 | ||
|
|
3ce123ab69 | ||
|
|
d8b7a51ab6 | ||
|
|
344a2bfc1a | ||
|
|
86588419fb | ||
|
|
d09db09849 | ||
|
|
1e5a8561c0 | ||
|
|
f3c9578bca | ||
|
|
3741afa6dc | ||
|
|
560a006892 | ||
|
|
4774e45218 | ||
|
|
206ee87188 | ||
|
|
a7e048484b | ||
|
|
d6b5f2f5da | ||
|
|
3df560ea38 | ||
|
|
adbaf700cd | ||
|
|
4a41bff3ab | ||
|
|
b453b0ea95 | ||
|
|
0192a7af96 | ||
|
|
630ad38a67 | ||
|
|
21156fc2a2 | ||
|
|
fa99f5bc03 | ||
|
|
09aa1e7af4 | ||
|
|
2034ed387b | ||
|
|
d6140d6d54 | ||
|
|
fb54bd3fcf | ||
|
|
a486ee347a | ||
|
|
5fb3582b31 | ||
|
|
8b0b9db31e | ||
|
|
f9889f81d6 | ||
|
|
efafa52719 | ||
|
|
8bda59fbe7 | ||
|
|
c3788d765e | ||
|
|
e407558f76 | ||
|
|
042df4198a | ||
|
|
ab6f35d83a | ||
|
|
f20d85738f | ||
|
|
f9b56a8581 | ||
|
|
fedc8ed474 | ||
|
|
79aeb31088 | ||
|
|
04857d32cd | ||
|
|
109cdce92c | ||
|
|
b7554d9ed8 | ||
|
|
6106f1a32e | ||
|
|
f2a8307bb6 | ||
|
|
470ee7aef9 | ||
|
|
aefca48e78 | ||
|
|
5e792078b3 | ||
|
|
7f7d2fd5b3 | ||
|
|
5e435b41ba | ||
|
|
44cfce1ca4 | ||
|
|
bb175cc958 | ||
|
|
5a9fb6eaf7 | ||
|
|
54d35ddfe9 | ||
|
|
7beccb7997 | ||
|
|
14a78f55cd | ||
|
|
7617a9316e | ||
|
|
a52ed366e4 | ||
|
|
7be164e2a5 | ||
|
|
a24f25c0d8 | ||
|
|
993b238a41 | ||
|
|
bbbfc8201c | ||
|
|
6f03a4d6ce | ||
|
|
c8958a22d2 | ||
|
|
37afa2180b | ||
|
|
b2df8e478a | ||
|
|
50fccb52be | ||
|
|
b90e719da5 | ||
|
|
97f1723181 | ||
|
|
80e0a3cce4 | ||
|
|
79effae933 | ||
|
|
810056349f | ||
|
|
b1d490ea53 | ||
|
|
345637290b | ||
|
|
9628df3031 | ||
|
|
423f338d04 | ||
|
|
3a2597e5c4 | ||
|
|
641f261495 | ||
|
|
5884a6e7a6 | ||
|
|
10e979e841 | ||
|
|
8dc1441635 | ||
|
|
c79dcfad9a | ||
|
|
1886952666 | ||
|
|
7326b246b7 | ||
|
|
345c812e43 | ||
|
|
fd4ba3989e | ||
|
|
e2d2571ad0 | ||
|
|
d479a0585d | ||
|
|
addfae31b6 | ||
|
|
ccf61db726 | ||
|
|
5b86b2078a | ||
|
|
a069479340 | ||
|
|
d11bf9288e | ||
|
|
86eeb4d2ed | ||
|
|
2275fe59ab | ||
|
|
48be8c33ba | ||
|
|
d3d07128b2 | ||
|
|
37eeccbf4c | ||
|
|
1722fc537f | ||
|
|
b240b182cb | ||
|
|
c0f347fc8c | ||
|
|
53dbe58ada | ||
|
|
2c4b798f9b | ||
|
|
1cf14a8e94 | ||
|
|
4864bf1509 | ||
|
|
9934421442 | ||
|
|
d7267c1603 | ||
|
|
5c778c6d32 | ||
|
|
85797acf1e | ||
|
|
c4f5c11a4e | ||
|
|
5a1c3dbea3 | ||
|
|
8e439d3dd9 | ||
|
|
9ebf921c53 | ||
|
|
7bd9094aaa | ||
|
|
16cc395f78 | ||
|
|
13e7398566 | ||
|
|
8b90ee4364 | ||
|
|
1098ab732f | ||
|
|
507fdd4f40 | ||
|
|
0ae8d7ac08 | ||
|
|
c77df2d1eb | ||
|
|
cefae021db | ||
|
|
771aee8cd8 | ||
|
|
2d13d8b3b6 | ||
|
|
c1fa70639b | ||
|
|
12643c5986 | ||
|
|
a0f5613a23 | ||
|
|
824562357b | ||
|
|
ec7184c533 | ||
|
|
e8e2502e2f | ||
|
|
c86cfefc48 | ||
|
|
2635fe8b4c | ||
|
|
632436d54d | ||
|
|
74be6828dd | ||
|
|
f4acfed48f | ||
|
|
91e1c1bea8 | ||
|
|
bbb9a41ea4 | ||
|
|
f6418887b2 | ||
|
|
a3f8a097a1 | ||
|
|
751563644f | ||
|
|
e52b801cd0 | ||
|
|
445a6428a6 | ||
|
|
d59b26dad7 | ||
|
|
47417d1871 | ||
|
|
381aecb952 | ||
|
|
45344575c6 | ||
|
|
83381625bd | ||
|
|
552fb16cb2 | ||
|
|
75c631f080 | ||
|
|
e2464fdf62 | ||
|
|
9ff98073db | ||
|
|
98ee5def37 | ||
|
|
3649487f5e | ||
|
|
4b007ae740 | ||
|
|
6c79a60e19 | ||
|
|
2a94bfc703 | ||
|
|
299934fd2a | ||
|
|
b18d042832 | ||
|
|
97a10ec218 | ||
|
|
d35400a7d7 | ||
|
|
92f6ec2328 | ||
|
|
9ba2019470 | ||
|
|
c171d88194 | ||
|
|
7cfcbacfc7 | ||
|
|
52847b61a3 | ||
|
|
5a36559834 | ||
|
|
19d4e047f6 | ||
|
|
6b348d43c6 | ||
|
|
732cd27d2e | ||
|
|
8171fe4571 | ||
|
|
16daa57e47 | ||
|
|
5e5addcdbf | ||
|
|
be65c8303f | ||
|
|
231250f2eb | ||
|
|
d44a428b74 | ||
|
|
40f9d52ad8 | ||
|
|
7f3b05c179 | ||
|
|
09c9fad6c3 | ||
|
|
bb18479d5b | ||
|
|
779ea8ac62 | ||
|
|
bd7c7ddad0 | ||
|
|
c6fdcf9b0d | ||
|
|
59fe74ddf6 | ||
|
|
6d7c067461 | ||
|
|
316205e455 | ||
|
|
834ae0a93f | ||
|
|
d562f11298 | ||
|
|
972628c751 | ||
|
|
09b1db63f4 | ||
|
|
e9d54f752c | ||
|
|
c335025167 | ||
|
|
2b2109c89a | ||
|
|
56124546a6 | ||
|
|
336258ecf8 | ||
|
|
b894d2c04a | ||
|
|
8e1d4818ac | ||
|
|
28c98584c1 | ||
|
|
1c42780bb5 | ||
|
|
18554dfed7 | ||
|
|
2e493fec46 | ||
|
|
98c2e08add | ||
|
|
94d3dee369 | ||
|
|
7e7dd769fd | ||
|
|
79da96b369 | ||
|
|
78fcabade8 | ||
|
|
284645f505 | ||
|
|
0b349761a8 | ||
|
|
d18794931a | ||
|
|
b7d4ff3201 | ||
|
|
4c6d674e03 | ||
|
|
2c97af8021 | ||
|
|
832f75a55e | ||
|
|
4e77969545 | ||
|
|
6ebbbfee61 | ||
|
|
0fabeefc3e | ||
|
|
c70d72f06b | ||
|
|
cc141bf1a5 | ||
|
|
199532c802 | ||
|
|
28ee3d0949 | ||
|
|
925195725d | ||
|
|
f6d22df76e | ||
|
|
118858a55e | ||
|
|
656c1291b1 | ||
|
|
f00b8dd1c3 | ||
|
|
5f2b9e317a | ||
|
|
4ae5ba7fc4 | ||
|
|
3656eed9ad | ||
|
|
2e82a6ce03 | ||
|
|
c4b8a3b768 | ||
|
|
1147b83b22 | ||
|
|
0fb8eade13 | ||
|
|
78d11fe628 | ||
|
|
90b40fc3e6 | ||
|
|
e25e268e2e | ||
|
|
68bff31cc9 | ||
|
|
31d9545702 | ||
|
|
e449071a35 | ||
|
|
23e3724abb | ||
|
|
75a5c7013f | ||
|
|
56d24085f9 | ||
|
|
95b82af42a | ||
|
|
87dedde5d6 | ||
|
|
8b6489c60e | ||
|
|
bf4f05fff3 |
2
.github/FUNDING.yml
vendored
Normal file
2
.github/FUNDING.yml
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
github: lonvia
|
||||
custom: "https://nominatim.org/funding/"
|
||||
@@ -7,6 +7,8 @@ assignees: ''
|
||||
|
||||
---
|
||||
|
||||
<!-- Note: this template is for reporting problems with searching. If you have found an issue with the data, you need to report/fix the issue directly in OpenStreetMap. See https://www.openstreetmap.org/fixthemap for details. -->
|
||||
|
||||
## What did you search for?
|
||||
|
||||
<!-- Please try to provide a link to your search. You can go to https://nominatim.openstreetmap.org and repeat your search there. If you originally found the issue somewhere else, please tell us what software/website you were using. -->
|
||||
@@ -15,11 +17,11 @@ assignees: ''
|
||||
|
||||
## What result did you expect?
|
||||
|
||||
**Is the result in the right place and just named wrongly?**
|
||||
**When the result in the right place and just named wrongly:**
|
||||
|
||||
<!-- Please tell us the display name you expected. -->
|
||||
|
||||
**Is the result missing completely?**
|
||||
**When the result missing completely:**
|
||||
|
||||
<!-- Make sure that the data you are looking for is in OpenStreetMap. Provide a link to the OpenStreetMap object or if you cannot get it, a link to the map on https://openstreetmap.org where you expect the result to be.
|
||||
|
||||
|
||||
31
.github/actions/build-nominatim/action.yml
vendored
31
.github/actions/build-nominatim/action.yml
vendored
@@ -5,34 +5,43 @@ inputs:
|
||||
description: 'Version of Ubuntu to install on'
|
||||
required: false
|
||||
default: '20'
|
||||
cmake-args:
|
||||
description: 'Additional options to hand to cmake'
|
||||
required: false
|
||||
default: ''
|
||||
lua:
|
||||
description: 'Version of Lua to use'
|
||||
required: false
|
||||
default: '5.3'
|
||||
|
||||
runs:
|
||||
using: "composite"
|
||||
|
||||
steps:
|
||||
- name: Clean out the disk
|
||||
run: |
|
||||
sudo rm -rf /opt/hostedtoolcache/go /opt/hostedtoolcache/CodeQL /usr/lib/jvm /usr/local/share/chromium /usr/local/lib/android
|
||||
df -h
|
||||
shell: bash
|
||||
- name: Install prerequisites
|
||||
run: |
|
||||
sudo apt-get install -y -qq libboost-system-dev libboost-filesystem-dev libexpat1-dev zlib1g-dev libbz2-dev libpq-dev libproj-dev libicu-dev
|
||||
sudo apt-get install -y -qq libboost-system-dev libboost-filesystem-dev libexpat1-dev zlib1g-dev libbz2-dev libpq-dev libproj-dev libicu-dev liblua${LUA_VERSION}-dev lua${LUA_VERSION}
|
||||
if [ "x$UBUNTUVER" == "x18" ]; then
|
||||
pip3 install python-dotenv psycopg2==2.7.7 jinja2==2.8 psutil==5.4.2 pyicu osmium PyYAML==5.1 datrie
|
||||
pip3 install python-dotenv psycopg2==2.7.7 jinja2==2.8 psutil==5.4.2 pyicu==2.9 osmium PyYAML==5.1 datrie
|
||||
else
|
||||
sudo apt-get install -y -qq python3-icu python3-datrie python3-pyosmium python3-jinja2 python3-psutil python3-psycopg2 python3-dotenv python3-yaml
|
||||
fi
|
||||
shell: bash
|
||||
env:
|
||||
UBUNTUVER: ${{ inputs.ubuntu }}
|
||||
|
||||
- name: Download dependencies
|
||||
run: |
|
||||
if [ ! -f country_grid.sql.gz ]; then
|
||||
wget --no-verbose https://www.nominatim.org/data/country_grid.sql.gz
|
||||
fi
|
||||
cp country_grid.sql.gz Nominatim/data/country_osm_grid.sql.gz
|
||||
shell: bash
|
||||
CMAKE_ARGS: ${{ inputs.cmake-args }}
|
||||
LUA_VERSION: ${{ inputs.lua }}
|
||||
|
||||
- name: Configure
|
||||
run: mkdir build && cd build && cmake ../Nominatim
|
||||
run: mkdir build && cd build && cmake $CMAKE_ARGS ../Nominatim
|
||||
shell: bash
|
||||
env:
|
||||
CMAKE_ARGS: ${{ inputs.cmake-args }}
|
||||
|
||||
- name: Build
|
||||
run: |
|
||||
|
||||
6
.github/actions/setup-postgresql/action.yml
vendored
6
.github/actions/setup-postgresql/action.yml
vendored
@@ -15,14 +15,16 @@ runs:
|
||||
- name: Remove existing PostgreSQL
|
||||
run: |
|
||||
sudo apt-get purge -yq postgresql*
|
||||
sudo sh -c 'echo "deb http://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" > /etc/apt/sources.list.d/pgdg.list'
|
||||
sudo apt install curl ca-certificates gnupg
|
||||
curl https://www.postgresql.org/media/keys/ACCC4CF8.asc | gpg --dearmor | sudo tee /etc/apt/trusted.gpg.d/apt.postgresql.org.gpg >/dev/null
|
||||
sudo sh -c 'echo "deb https://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" > /etc/apt/sources.list.d/pgdg.list'
|
||||
sudo apt-get update -qq
|
||||
|
||||
shell: bash
|
||||
|
||||
- name: Install PostgreSQL
|
||||
run: |
|
||||
sudo apt-get install -y -qq --no-install-suggests --no-install-recommends postgresql-client-${PGVER} postgresql-${PGVER}-postgis-${POSTGISVER} postgresql-${PGVER}-postgis-${POSTGISVER}-scripts postgresql-contrib-${PGVER} postgresql-${PGVER} postgresql-server-dev-${PGVER}
|
||||
sudo apt-get install -y -qq --no-install-suggests --no-install-recommends postgresql-client-${PGVER} postgresql-${PGVER}-postgis-${POSTGISVER} postgresql-${PGVER}-postgis-${POSTGISVER}-scripts postgresql-contrib-${PGVER} postgresql-${PGVER}
|
||||
shell: bash
|
||||
env:
|
||||
PGVER: ${{ inputs.postgresql-version }}
|
||||
|
||||
336
.github/workflows/ci-tests.yml
vendored
336
.github/workflows/ci-tests.yml
vendored
@@ -3,54 +3,77 @@ name: CI Tests
|
||||
on: [ push, pull_request ]
|
||||
|
||||
jobs:
|
||||
create-archive:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: true
|
||||
|
||||
- uses: actions/cache@v3
|
||||
with:
|
||||
path: |
|
||||
data/country_osm_grid.sql.gz
|
||||
key: nominatim-country-data-1
|
||||
|
||||
- name: Package tarball
|
||||
run: |
|
||||
if [ ! -f data/country_osm_grid.sql.gz ]; then
|
||||
wget --no-verbose -O data/country_osm_grid.sql.gz https://www.nominatim.org/data/country_grid.sql.gz
|
||||
fi
|
||||
cd ..
|
||||
tar czf nominatim-src.tar.bz2 Nominatim
|
||||
mv nominatim-src.tar.bz2 Nominatim
|
||||
|
||||
- name: 'Upload Artifact'
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: full-source
|
||||
path: nominatim-src.tar.bz2
|
||||
retention-days: 1
|
||||
|
||||
tests:
|
||||
needs: create-archive
|
||||
strategy:
|
||||
matrix:
|
||||
ubuntu: [18, 20]
|
||||
ubuntu: [20, 22]
|
||||
include:
|
||||
- ubuntu: 18
|
||||
postgresql: 9.5
|
||||
postgis: 2.5
|
||||
pytest: pytest
|
||||
php: 7.2
|
||||
- ubuntu: 20
|
||||
postgresql: 13
|
||||
postgis: 3
|
||||
pytest: py.test-3
|
||||
php: 7.4
|
||||
- ubuntu: 22
|
||||
postgresql: 15
|
||||
postgis: 3
|
||||
pytest: py.test-3
|
||||
php: 8.1
|
||||
|
||||
runs-on: ubuntu-${{ matrix.ubuntu }}.04
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/download-artifact@v3
|
||||
with:
|
||||
submodules: true
|
||||
path: Nominatim
|
||||
name: full-source
|
||||
|
||||
- name: Unpack Nominatim
|
||||
run: tar xf nominatim-src.tar.bz2
|
||||
|
||||
- name: Setup PHP
|
||||
uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
php-version: ${{ matrix.php }}
|
||||
coverage: xdebug
|
||||
tools: phpunit, phpcs, composer
|
||||
tools: phpunit:9, phpcs, composer
|
||||
ini-values: opcache.jit=disable
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- uses: actions/setup-python@v2
|
||||
- uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: 3.6
|
||||
if: matrix.ubuntu == 18
|
||||
|
||||
- name: Get Date
|
||||
id: get-date
|
||||
run: |
|
||||
echo "::set-output name=date::$(/bin/date -u "+%Y%W")"
|
||||
shell: bash
|
||||
|
||||
- uses: actions/cache@v2
|
||||
with:
|
||||
path: |
|
||||
country_grid.sql.gz
|
||||
key: nominatim-country-data-${{ steps.get-date.outputs.date }}
|
||||
|
||||
- uses: ./Nominatim/.github/actions/setup-postgresql
|
||||
with:
|
||||
postgresql-version: ${{ matrix.postgresql }}
|
||||
@@ -61,157 +84,234 @@ jobs:
|
||||
ubuntu: ${{ matrix.ubuntu }}
|
||||
|
||||
- name: Install test prerequsites
|
||||
run: sudo apt-get install -y -qq pylint python3-pytest python3-behave python3-pytest-cov php-codecoverage
|
||||
run: sudo apt-get install -y -qq python3-pytest python3-behave
|
||||
if: matrix.ubuntu == 20
|
||||
|
||||
- name: Install test prerequsites
|
||||
run: |
|
||||
pip3 install pylint==2.6.0 pytest pytest-cov behave==1.2.6
|
||||
if: matrix.ubuntu == 18
|
||||
run: pip3 install pylint pytest behave==1.2.6
|
||||
if: ${{ (matrix.ubuntu == 18) || (matrix.ubuntu == 22) }}
|
||||
|
||||
- name: Install test prerequsites
|
||||
run: sudo apt-get install -y -qq python3-pytest
|
||||
if: matrix.ubuntu == 22
|
||||
|
||||
- name: Install latest pylint/mypy
|
||||
run: pip3 install -U pylint mypy types-PyYAML types-jinja2 types-psycopg2 types-psutil types-requests typing-extensions
|
||||
if: matrix.ubuntu == 22
|
||||
|
||||
- name: PHP linting
|
||||
run: phpcs --report-width=120 .
|
||||
working-directory: Nominatim
|
||||
if: matrix.ubuntu == 22
|
||||
|
||||
- name: Python linting
|
||||
run: pylint nominatim
|
||||
working-directory: Nominatim
|
||||
if: matrix.ubuntu == 22
|
||||
|
||||
- name: Python static typechecking
|
||||
run: mypy --strict nominatim
|
||||
working-directory: Nominatim
|
||||
if: matrix.ubuntu == 22
|
||||
|
||||
|
||||
- name: PHP unit tests
|
||||
run: phpunit --coverage-clover ../../coverage-php.xml ./
|
||||
run: phpunit ./
|
||||
working-directory: Nominatim/test/php
|
||||
if: matrix.ubuntu == 20
|
||||
if: ${{ (matrix.ubuntu == 20) || (matrix.ubuntu == 22) }}
|
||||
|
||||
- name: Python unit tests
|
||||
run: $PYTEST --cov=nominatim --cov-report=xml test/python
|
||||
run: $PYTEST test/python
|
||||
working-directory: Nominatim
|
||||
env:
|
||||
PYTEST: ${{ matrix.pytest }}
|
||||
|
||||
- name: BDD tests
|
||||
run: |
|
||||
mkdir cov
|
||||
behave -DREMOVE_TEMPLATE=1 -DBUILDDIR=$GITHUB_WORKSPACE/build --format=progress3 -DPHPCOV=./cov
|
||||
composer require phpunit/phpcov:7.0.2
|
||||
vendor/bin/phpcov merge --clover ../../coverage-bdd.xml ./cov
|
||||
working-directory: Nominatim/test/bdd
|
||||
if: matrix.ubuntu == 20
|
||||
|
||||
- name: BDD tests
|
||||
run: |
|
||||
behave -DREMOVE_TEMPLATE=1 -DBUILDDIR=$GITHUB_WORKSPACE/build --format=progress3
|
||||
working-directory: Nominatim/test/bdd
|
||||
if: matrix.ubuntu == 18
|
||||
|
||||
- name: BDD tests (legacy_icu tokenizer)
|
||||
run: |
|
||||
behave -DREMOVE_TEMPLATE=1 -DBUILDDIR=$GITHUB_WORKSPACE/build -DTOKENIZER=legacy_icu --format=progress3
|
||||
working-directory: Nominatim/test/bdd
|
||||
|
||||
- name: Upload coverage to Codecov
|
||||
uses: codecov/codecov-action@v1
|
||||
with:
|
||||
files: ./Nominatim/coverage*.xml
|
||||
directory: ./
|
||||
name: codecov-umbrella
|
||||
fail_ci_if_error: false
|
||||
path_to_write_report: ./coverage/codecov_report.txt
|
||||
verbose: true
|
||||
if: matrix.ubuntu == 20
|
||||
|
||||
import:
|
||||
strategy:
|
||||
matrix:
|
||||
ubuntu: [18, 20]
|
||||
include:
|
||||
- ubuntu: 18
|
||||
postgresql: 9.5
|
||||
postgis: 2.5
|
||||
- ubuntu: 20
|
||||
postgresql: 13
|
||||
postgis: 3
|
||||
|
||||
runs-on: ubuntu-${{ matrix.ubuntu }}.04
|
||||
legacy-test:
|
||||
needs: create-archive
|
||||
runs-on: ubuntu-20.04
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/download-artifact@v3
|
||||
with:
|
||||
submodules: true
|
||||
path: Nominatim
|
||||
name: full-source
|
||||
|
||||
- name: Get Date
|
||||
id: get-date
|
||||
run: |
|
||||
echo "::set-output name=date::$(/bin/date -u "+%Y%W")"
|
||||
shell: bash
|
||||
- name: Unpack Nominatim
|
||||
run: tar xf nominatim-src.tar.bz2
|
||||
|
||||
- uses: actions/cache@v2
|
||||
- name: Setup PHP
|
||||
uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
path: |
|
||||
country_grid.sql.gz
|
||||
key: nominatim-country-data-${{ steps.get-date.outputs.date }}
|
||||
|
||||
- uses: actions/cache@v2
|
||||
with:
|
||||
path: |
|
||||
monaco-latest.osm.pbf
|
||||
key: nominatim-test-data-${{ steps.get-date.outputs.date }}
|
||||
|
||||
- uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: 3.6
|
||||
if: matrix.ubuntu == 18
|
||||
php-version: 7.4
|
||||
|
||||
- uses: ./Nominatim/.github/actions/setup-postgresql
|
||||
with:
|
||||
postgresql-version: ${{ matrix.postgresql }}
|
||||
postgis-version: ${{ matrix.postgis }}
|
||||
postgresql-version: 13
|
||||
postgis-version: 3
|
||||
|
||||
- name: Install Postgresql server dev
|
||||
run: sudo apt-get install postgresql-server-dev-13
|
||||
|
||||
- uses: ./Nominatim/.github/actions/build-nominatim
|
||||
with:
|
||||
ubuntu: ${{ matrix.ubuntu }}
|
||||
ubuntu: 20
|
||||
cmake-args: -DBUILD_MODULE=on
|
||||
|
||||
- name: Clean installation
|
||||
run: rm -rf Nominatim build
|
||||
- name: Install test prerequsites
|
||||
run: sudo apt-get install -y -qq python3-behave
|
||||
|
||||
- name: BDD tests (legacy tokenizer)
|
||||
run: |
|
||||
behave -DREMOVE_TEMPLATE=1 -DBUILDDIR=$GITHUB_WORKSPACE/build -DTOKENIZER=legacy --format=progress3
|
||||
working-directory: Nominatim/test/bdd
|
||||
|
||||
|
||||
install:
|
||||
runs-on: ubuntu-latest
|
||||
needs: create-archive
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
name: [Ubuntu-18, Ubuntu-20, Ubuntu-22]
|
||||
include:
|
||||
- name: Ubuntu-18
|
||||
flavour: ubuntu
|
||||
image: "ubuntu:18.04"
|
||||
ubuntu: 18
|
||||
install_mode: install-nginx
|
||||
- name: Ubuntu-20
|
||||
flavour: ubuntu
|
||||
image: "ubuntu:20.04"
|
||||
ubuntu: 20
|
||||
install_mode: install-apache
|
||||
- name: Ubuntu-22
|
||||
flavour: ubuntu
|
||||
image: "ubuntu:22.04"
|
||||
ubuntu: 22
|
||||
install_mode: install-apache
|
||||
|
||||
container:
|
||||
image: ${{ matrix.image }}
|
||||
env:
|
||||
LANG: en_US.UTF-8
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: sudo -Hu nominatim bash --noprofile --norc -eo pipefail {0}
|
||||
|
||||
steps:
|
||||
- name: Prepare container (Ubuntu)
|
||||
run: |
|
||||
export APT_LISTCHANGES_FRONTEND=none
|
||||
export DEBIAN_FRONTEND=noninteractive
|
||||
apt-get update -qq
|
||||
apt-get install -y git sudo wget
|
||||
ln -snf /usr/share/zoneinfo/$CONTAINER_TIMEZONE /etc/localtime && echo $CONTAINER_TIMEZONE > /etc/timezone
|
||||
shell: bash
|
||||
if: matrix.flavour == 'ubuntu'
|
||||
|
||||
- name: Prepare container (CentOS)
|
||||
run: |
|
||||
dnf update -y
|
||||
dnf install -y sudo glibc-langpack-en
|
||||
shell: bash
|
||||
if: matrix.flavour == 'centos'
|
||||
|
||||
- name: Setup import user
|
||||
run: |
|
||||
useradd -m nominatim
|
||||
echo 'nominatim ALL=(ALL:ALL) NOPASSWD: ALL' > /etc/sudoers.d/nominiatim
|
||||
echo "/home/nominatim/Nominatim/vagrant/Install-on-${OS}.sh no $INSTALL_MODE" > /home/nominatim/vagrant.sh
|
||||
shell: bash
|
||||
env:
|
||||
OS: ${{ matrix.name }}
|
||||
INSTALL_MODE: ${{ matrix.install_mode }}
|
||||
|
||||
- uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: full-source
|
||||
path: /home/nominatim
|
||||
|
||||
- name: Install Nominatim
|
||||
run: |
|
||||
export USERNAME=nominatim
|
||||
export USERHOME=/home/nominatim
|
||||
export NOSYSTEMD=yes
|
||||
export HAVE_SELINUX=no
|
||||
tar xf nominatim-src.tar.bz2
|
||||
. vagrant.sh
|
||||
working-directory: /home/nominatim
|
||||
|
||||
- name: Prepare import environment
|
||||
run: |
|
||||
if [ ! -f monaco-latest.osm.pbf ]; then
|
||||
wget --no-verbose https://download.geofabrik.de/europe/monaco-latest.osm.pbf
|
||||
fi
|
||||
mkdir data-env
|
||||
cd data-env
|
||||
shell: bash
|
||||
mv Nominatim/test/testdb/apidb-test-data.pbf test.pbf
|
||||
rm -rf Nominatim
|
||||
mkdir data-env-reverse
|
||||
working-directory: /home/nominatim
|
||||
|
||||
- name: Prepare import environment (CentOS)
|
||||
run: |
|
||||
sudo ln -s /usr/local/bin/nominatim /usr/bin/nominatim
|
||||
echo NOMINATIM_DATABASE_WEBUSER="apache" > nominatim-project/.env
|
||||
cp nominatim-project/.env data-env-reverse/.env
|
||||
working-directory: /home/nominatim
|
||||
if: matrix.flavour == 'centos'
|
||||
|
||||
- name: Print version
|
||||
run: nominatim --version
|
||||
working-directory: /home/nominatim/nominatim-project
|
||||
|
||||
- name: Collect host OS information
|
||||
run: nominatim admin --collect-os-info
|
||||
working-directory: /home/nominatim/nominatim-project
|
||||
|
||||
- name: Import
|
||||
run: nominatim import --osm-file ../monaco-latest.osm.pbf
|
||||
shell: bash
|
||||
working-directory: data-env
|
||||
run: nominatim import --osm-file ../test.pbf
|
||||
working-directory: /home/nominatim/nominatim-project
|
||||
|
||||
- name: Import special phrases
|
||||
run: nominatim special-phrases --import-from-wiki
|
||||
working-directory: data-env
|
||||
working-directory: /home/nominatim/nominatim-project
|
||||
|
||||
- name: Check full import
|
||||
run: nominatim admin --check-database
|
||||
working-directory: data-env
|
||||
working-directory: /home/nominatim/nominatim-project
|
||||
|
||||
- name: Warm up database
|
||||
run: nominatim admin --warm
|
||||
working-directory: data-env
|
||||
working-directory: /home/nominatim/nominatim-project
|
||||
|
||||
- name: Prepare update (Ubuntu)
|
||||
run: apt-get install -y python3-pip
|
||||
shell: bash
|
||||
if: matrix.flavour == 'ubuntu'
|
||||
|
||||
- name: Run update
|
||||
run: |
|
||||
nominatim replication --init
|
||||
nominatim replication --once
|
||||
working-directory: data-env
|
||||
pip3 install --user osmium
|
||||
nominatim replication --init
|
||||
NOMINATIM_REPLICATION_MAX_DIFF=1 nominatim replication --once
|
||||
working-directory: /home/nominatim/nominatim-project
|
||||
|
||||
- name: Clean up database
|
||||
run: nominatim refresh --postcodes --word-tokens
|
||||
working-directory: /home/nominatim/nominatim-project
|
||||
|
||||
- name: Run reverse-only import
|
||||
run : nominatim import --osm-file ../monaco-latest.osm.pbf --reverse-only --no-updates
|
||||
working-directory: data-env
|
||||
env:
|
||||
NOMINATIM_DATABASE_DSN: pgsql:dbname=reverse
|
||||
run : |
|
||||
echo 'NOMINATIM_DATABASE_DSN="pgsql:dbname=reverse"' >> .env
|
||||
nominatim import --osm-file ../test.pbf --reverse-only --no-updates
|
||||
working-directory: /home/nominatim/data-env-reverse
|
||||
|
||||
- name: Check reverse import
|
||||
- name: Check reverse-only import
|
||||
run: nominatim admin --check-database
|
||||
working-directory: data-env
|
||||
working-directory: /home/nominatim/data-env-reverse
|
||||
|
||||
- name: Clean up database (reverse-only import)
|
||||
run: nominatim refresh --postcodes --word-tokens
|
||||
working-directory: /home/nominatim/nominatim-project
|
||||
|
||||
7
.gitignore
vendored
7
.gitignore
vendored
@@ -1,12 +1,9 @@
|
||||
*.log
|
||||
*.pyc
|
||||
|
||||
build
|
||||
settings/local.php
|
||||
docs/develop/*.png
|
||||
|
||||
data/wiki_import.sql
|
||||
data/wiki_specialphrases.sql
|
||||
data/osmosischange.osc
|
||||
build
|
||||
|
||||
.vagrant
|
||||
data/country_osm_grid.sql.gz
|
||||
|
||||
13
.mypy.ini
Normal file
13
.mypy.ini
Normal file
@@ -0,0 +1,13 @@
|
||||
[mypy]
|
||||
|
||||
[mypy-icu.*]
|
||||
ignore_missing_imports = True
|
||||
|
||||
[mypy-osmium.*]
|
||||
ignore_missing_imports = True
|
||||
|
||||
[mypy-datrie.*]
|
||||
ignore_missing_imports = True
|
||||
|
||||
[mypy-dotenv.*]
|
||||
ignore_missing_imports = True
|
||||
@@ -10,6 +10,9 @@ ignored-modules=icu,datrie
|
||||
# closing added here because it sometimes triggers a false positive with
|
||||
# 'with' statements.
|
||||
ignored-classes=NominatimArgs,closing
|
||||
disable=too-few-public-methods,duplicate-code
|
||||
# 'too-many-ancestors' is triggered already by deriving from UserDict
|
||||
# 'not-context-manager' disabled because it causes false positives once
|
||||
# typed Python is enabled. See also https://github.com/PyCQA/pylint/issues/5273
|
||||
disable=too-few-public-methods,duplicate-code,too-many-ancestors,bad-option-value,no-self-use,not-context-manager,use-dict-literal
|
||||
|
||||
good-names=i,x,y,fd,db
|
||||
good-names=i,x,y,m,fd,db,cc
|
||||
|
||||
16
AUTHORS
16
AUTHORS
@@ -1,15 +1,15 @@
|
||||
Nominatim was written by:
|
||||
|
||||
Brian Quinion
|
||||
Sarah Hoffmann
|
||||
Marc Tobias Metten
|
||||
* Brian Quinion
|
||||
* Sarah Hoffmann
|
||||
* Marc Tobias Metten
|
||||
|
||||
markigail
|
||||
gemo1011
|
||||
IrlJidel
|
||||
Frederik Ramm
|
||||
* markigail
|
||||
* AntoJvlt
|
||||
* gemo1011
|
||||
* darkshredder
|
||||
|
||||
and many more.
|
||||
|
||||
For a full list of contributors see
|
||||
For a full list of contributors see the Git logs or visit
|
||||
https://github.com/openstreetmap/Nominatim/graphs/contributors
|
||||
|
||||
@@ -18,14 +18,25 @@ list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake")
|
||||
|
||||
project(nominatim)
|
||||
|
||||
set(NOMINATIM_VERSION_MAJOR 3)
|
||||
set(NOMINATIM_VERSION_MINOR 7)
|
||||
set(NOMINATIM_VERSION_PATCH 0)
|
||||
set(NOMINATIM_VERSION_MAJOR 4)
|
||||
set(NOMINATIM_VERSION_MINOR 2)
|
||||
set(NOMINATIM_VERSION_PATCH 4)
|
||||
|
||||
set(NOMINATIM_VERSION "${NOMINATIM_VERSION_MAJOR}.${NOMINATIM_VERSION_MINOR}.${NOMINATIM_VERSION_PATCH}")
|
||||
|
||||
add_definitions(-DNOMINATIM_VERSION="${NOMINATIM_VERSION}")
|
||||
|
||||
# Setting GIT_HASH
|
||||
find_package(Git)
|
||||
if (GIT_FOUND)
|
||||
execute_process(
|
||||
COMMAND "${GIT_EXECUTABLE}" log -1 --format=%h
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}
|
||||
OUTPUT_VARIABLE GIT_HASH
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
ERROR_QUIET
|
||||
)
|
||||
endif()
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# Configuration
|
||||
@@ -33,11 +44,12 @@ add_definitions(-DNOMINATIM_VERSION="${NOMINATIM_VERSION}")
|
||||
|
||||
set(BUILD_IMPORTER on CACHE BOOL "Build everything for importing/updating the database")
|
||||
set(BUILD_API on CACHE BOOL "Build everything for the API server")
|
||||
set(BUILD_MODULE on CACHE BOOL "Build PostgreSQL module")
|
||||
set(BUILD_MODULE off CACHE BOOL "Build PostgreSQL module for legacy tokenizer")
|
||||
set(BUILD_TESTS on CACHE BOOL "Build test suite")
|
||||
set(BUILD_DOCS on CACHE BOOL "Build documentation")
|
||||
set(BUILD_MANPAGE on CACHE BOOL "Build Manual Page")
|
||||
set(BUILD_OSM2PGSQL on CACHE BOOL "Build osm2pgsql (expert only)")
|
||||
set(INSTALL_MUNIN_PLUGINS on CACHE BOOL "Install Munin plugins for supervising Nominatim")
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# osm2pgsql (imports/updates only)
|
||||
@@ -51,7 +63,6 @@ if (BUILD_IMPORTER AND BUILD_OSM2PGSQL)
|
||||
endif()
|
||||
set(BUILD_TESTS_SAVED "${BUILD_TESTS}")
|
||||
set(BUILD_TESTS off)
|
||||
set(WITH_LUA off CACHE BOOL "")
|
||||
add_subdirectory(osm2pgsql)
|
||||
set(BUILD_TESTS ${BUILD_TESTS_SAVED})
|
||||
endif()
|
||||
@@ -153,7 +164,7 @@ if (BUILD_TESTS)
|
||||
if (PHPCS)
|
||||
message(STATUS "Using phpcs binary ${PHPCS}")
|
||||
add_test(NAME phpcs
|
||||
COMMAND ${PHPCS} --report-width=120 --colors lib website utils
|
||||
COMMAND ${PHPCS} --report-width=120 --colors lib-php
|
||||
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR})
|
||||
else()
|
||||
message(WARNING "phpcs not found. PHP linting tests disabled." )
|
||||
@@ -199,7 +210,7 @@ endif()
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
if (BUILD_MANPAGE)
|
||||
add_subdirectory(manual)
|
||||
add_subdirectory(man)
|
||||
endif()
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
@@ -211,6 +222,7 @@ include(GNUInstallDirs)
|
||||
set(NOMINATIM_DATADIR ${CMAKE_INSTALL_FULL_DATADIR}/${PROJECT_NAME})
|
||||
set(NOMINATIM_LIBDIR ${CMAKE_INSTALL_FULL_LIBDIR}/${PROJECT_NAME})
|
||||
set(NOMINATIM_CONFIGDIR ${CMAKE_INSTALL_FULL_SYSCONFDIR}/${PROJECT_NAME})
|
||||
set(NOMINATIM_MUNINDIR ${CMAKE_INSTALL_FULL_DATADIR}/munin/plugins)
|
||||
|
||||
if (BUILD_IMPORTER)
|
||||
configure_file(${PROJECT_SOURCE_DIR}/cmake/tool-installed.tmpl installed.bin)
|
||||
@@ -224,8 +236,7 @@ if (BUILD_IMPORTER)
|
||||
PATTERN __pycache__ EXCLUDE)
|
||||
install(DIRECTORY lib-sql DESTINATION ${NOMINATIM_LIBDIR})
|
||||
|
||||
install(FILES data/country_name.sql
|
||||
${COUNTRY_GRID_FILE}
|
||||
install(FILES ${COUNTRY_GRID_FILE}
|
||||
data/words.sql
|
||||
DESTINATION ${NOMINATIM_DATADIR})
|
||||
endif()
|
||||
@@ -258,6 +269,24 @@ install(FILES settings/env.defaults
|
||||
settings/import-address.style
|
||||
settings/import-full.style
|
||||
settings/import-extratags.style
|
||||
settings/legacy_icu_tokenizer.yaml
|
||||
settings/icu-rules/extended-unicode-to-asccii.yaml
|
||||
settings/import-admin.lua
|
||||
settings/import-street.lua
|
||||
settings/import-address.lua
|
||||
settings/import-full.lua
|
||||
settings/import-extratags.lua
|
||||
settings/flex-base.lua
|
||||
settings/icu_tokenizer.yaml
|
||||
settings/country_settings.yaml
|
||||
DESTINATION ${NOMINATIM_CONFIGDIR})
|
||||
|
||||
install(DIRECTORY settings/icu-rules
|
||||
DESTINATION ${NOMINATIM_CONFIGDIR})
|
||||
install(DIRECTORY settings/country-names
|
||||
DESTINATION ${NOMINATIM_CONFIGDIR})
|
||||
|
||||
if (INSTALL_MUNIN_PLUGINS)
|
||||
install(FILES munin/nominatim_importlag
|
||||
munin/nominatim_query_speed
|
||||
munin/nominatim_requests
|
||||
DESTINATION ${NOMINATIM_MUNINDIR})
|
||||
endif()
|
||||
|
||||
@@ -36,7 +36,7 @@ Nominatim historically hasn't followed a particular coding style but we
|
||||
are in process of consolidating the style. The following rules apply:
|
||||
|
||||
* Python code uses the official Python style
|
||||
* indention
|
||||
* indentation
|
||||
* SQL use 2 spaces
|
||||
* all other file types use 4 spaces
|
||||
* [BSD style](https://en.wikipedia.org/wiki/Indent_style#Allman_style) for braces
|
||||
@@ -64,3 +64,39 @@ Before submitting a pull request make sure that the tests pass:
|
||||
cd build
|
||||
make test
|
||||
```
|
||||
|
||||
## Releases
|
||||
|
||||
Nominatim follows semantic versioning. Major releases are done for large changes
|
||||
that require (or at least strongly recommend) a reimport of the databases.
|
||||
Minor releases can usually be applied to exisiting databases Patch releases
|
||||
contain bug fixes only and are released from a separate branch where the
|
||||
relevant changes are cherry-picked from the master branch.
|
||||
|
||||
Checklist for releases:
|
||||
|
||||
* [ ] increase version in `nominatim/version.py` and CMakeLists.txt
|
||||
* [ ] update `ChangeLog` (copy information from patch releases from release branch)
|
||||
* [ ] complete `docs/admin/Migration.md`
|
||||
* [ ] update EOL dates in `SECURITY.md`
|
||||
* [ ] commit and make sure CI tests pass
|
||||
* [ ] test migration
|
||||
* download, build and import previous version
|
||||
* migrate using master version
|
||||
* run updates using master version
|
||||
* [ ] prepare tarball:
|
||||
* `git clone --recursive https://github.com/osm-search/Nominatim` (switch to right branch!)
|
||||
* `rm -r .git* osm2pgsql/.git*`
|
||||
* copy country data into `data/`
|
||||
* add version to base directory and package
|
||||
* [ ] upload tarball to https://nominatim.org
|
||||
* [ ] prepare documentation
|
||||
* check out new docs branch
|
||||
* change git checkout instructions to tarball download instructions or adapt version on existing ones
|
||||
* build documentation and copy to https://github.com/osm-search/nominatim-org-site
|
||||
* add new version to history
|
||||
* [ ] check release tarball
|
||||
* download tarball as per new documentation instructions
|
||||
* compile and import Nominatim
|
||||
* run `nominatim --version` to confirm correct version
|
||||
* [ ] tag new release and add a release on github.com
|
||||
|
||||
156
ChangeLog
156
ChangeLog
@@ -1,3 +1,158 @@
|
||||
4.2.4
|
||||
* fix a potential SQL injection in 'nominatim admin --collect-os-info'
|
||||
* fix compatibility issue with PostGIS 3.4
|
||||
|
||||
4.2.3
|
||||
|
||||
* fix deletion handling for 'nominatim add-data'
|
||||
* adapt place_force_delete() to new deletion handling
|
||||
* flex style: avoid dropping of postcode areas
|
||||
* fix update errors on address interpolation handling
|
||||
|
||||
4.2.2
|
||||
|
||||
* extend flex-style library to fully support all default styles
|
||||
* fix handling of Hebrew aleph
|
||||
* do not assign postcodes to rivers
|
||||
* fix string matching in PHP code
|
||||
* update osm2pgsql (various updates to flex)
|
||||
* fix slow query when deleting places on update
|
||||
* fix CLI details query
|
||||
* fix recalculation of importance values
|
||||
* fix polygon simplification in reverse results
|
||||
* add class/type information to reverse geocodejson result
|
||||
* minor improvements to default tokenizer configuration
|
||||
* various smaller fixes to documentation
|
||||
|
||||
4.2.1
|
||||
|
||||
* fix XSS vulnerability in debug view
|
||||
|
||||
4.2.0
|
||||
|
||||
* add experimental support for osm2pgsql flex style
|
||||
* introduce secondary importance value to be retrieved from a raster data file
|
||||
(currently still unused, to replace address importance, thanks to @tareqpi)
|
||||
* add new report tool `nominatim admin --collect-os-info`
|
||||
(thanks @micahcochran, @tareqpi)
|
||||
* reorganise index to improve lookup performance and size
|
||||
* run index creation after import in parallel
|
||||
* run ANALYZE more selectively to speed up continuation of indexing
|
||||
* fix crash on update when addr:interpolation receives an illegal value
|
||||
* fix minimum number of retrieved results to be at least 10
|
||||
* fix search for combinations of special term + name (e.g Hotel Bellevue)
|
||||
* do not return interpolations without a parent street on reverse search
|
||||
* improve invalidation of linked places on updates
|
||||
* fix address parsing for interpolation lines
|
||||
* make sure socket timeouts are respected during replication
|
||||
(working around a bug in some versions of pyosmium)
|
||||
* update bundled osm2pgsql to 1.7.1
|
||||
* add support for PostgreSQL 15
|
||||
* typing fixes to work with latest type annotations from typeshed
|
||||
* smaller improvements to documentation (thanks to @mausch)
|
||||
|
||||
4.1.1
|
||||
|
||||
* fix XSS vulnerability in debug view
|
||||
|
||||
4.1.0
|
||||
|
||||
* switch to ICU tokenizer as default
|
||||
* add housenumber normalization and support optional spaces during search
|
||||
* add postcode format checking and support optional spaces during search
|
||||
* add function for cleaning housenumbers in word table
|
||||
* add updates/deletion of country names imported from OSM
|
||||
* linked places no longer overwrite names from a place permanently
|
||||
* move default country name configuration into yaml file (thanks @tareqpi)
|
||||
* more compact layout for interpolation and TIGER tables
|
||||
* introduce mutations to ICU tokenizer (used for German umlauts)
|
||||
* support reinitializing a full project directory with refresh --website
|
||||
* fix various issues with linked places on updates
|
||||
* add support for external sanitizers and token analyzers
|
||||
* add CLI commands for forced indexing
|
||||
* add CLI command for version report
|
||||
* add offline import mode
|
||||
* change geocodejson to return a feature class in the 'type' field
|
||||
* add ISO3166-2 to address output (thanks @I70l0teN4ik)
|
||||
* improve parsing and matching of addr: tags
|
||||
* support relations as street members of associatedStreet
|
||||
* better ranking for address results from TIGER data
|
||||
* adapt rank classification to changed tag usage in OSM
|
||||
* update bundled osm2pgsql to 1.6.0
|
||||
* add typing information to Python code
|
||||
* improve unit test coverage
|
||||
* reorganise and speed up code for BDD tests, drop support for scenes
|
||||
* move PHP unit tests to PHP 9.5
|
||||
* extensive typo fixes in documentation (thanks @woodpeck,@StephanGeorg,
|
||||
@amandasaurus, @nslxndr, @stefkiourk, @Luflosi, @kianmeng)
|
||||
* drop official support for installation on CentOS
|
||||
* add installation instructions for Ubuntu 22.04
|
||||
* add support for PHP8
|
||||
* add setup instructions for updates and systemd
|
||||
* drop support for PostgreSQL 9.5
|
||||
|
||||
4.0.2
|
||||
|
||||
* fix XSS vulnerability in debug view
|
||||
|
||||
4.0.1
|
||||
|
||||
* fix initialisation error in replication script
|
||||
* ICU tokenizer: avoid any special characters in word tokens
|
||||
* better error message when API php script does not exist
|
||||
* fix quoting of house numbers in SQL queries
|
||||
* small fixes and improvements in search query parsing
|
||||
* add documentation for moving the database to a different machine
|
||||
|
||||
4.0.0
|
||||
|
||||
* refactor name token computation and introduce ICU tokenizer
|
||||
* name processing now happens in the indexer outside the DB
|
||||
* reorganizes abbreviation handling and moves it to the indexing phases
|
||||
* adds preprocessing of names
|
||||
* add country-specific ranking for Spain, Slovakia
|
||||
* partially switch to using SP-GIST indexes
|
||||
* better updating of dependent addresses for name changes in streets
|
||||
* remove unused/broken tables for external housenumbers
|
||||
* move external postcodes to CSV format and no longer save them in tables
|
||||
(adds support for postcodes for arbitrary countries)
|
||||
* remove postcode helper entries from placex (thanks @AntoJvlt)
|
||||
* change required format for TIGER data to CSV
|
||||
* move configuration of default languages from wiki into config file
|
||||
* expect customized configuration files in project directory by default
|
||||
* disable search API for reverse-only import (thanks @darkshredder)
|
||||
* port most of maintenance/import code to Python and remove PHP utils
|
||||
* add catch-up mode for replication
|
||||
* add updating of special phrases (thanks @AntoJvlt)
|
||||
* add support for special phrases in CSV files (thanks @AntoJvlt)
|
||||
* switch to case-independent matching between place and boundary names
|
||||
* remove disabling of reverse query parsing
|
||||
* minor tweaks to search algorithm to avoid more false positives
|
||||
* major overhaul of the administrator and developer documentation
|
||||
* add security disclosure policy
|
||||
* add testing of installation scripts via CI
|
||||
* drop support for Python < 3.6 and Postgresql < 9.5
|
||||
|
||||
3.7.3
|
||||
|
||||
* fix XSS vulnerability in debug view
|
||||
|
||||
3.7.2
|
||||
|
||||
* fix database check for reverse-only imports
|
||||
* do not error out in status API result when import date is missing
|
||||
* add array_key_last function for PHP < 7.3 (thanks to @woodpeck)
|
||||
* fix more url when server name is unknown (thanks to @mogita)
|
||||
* commit changes to replication log table
|
||||
|
||||
3.7.1
|
||||
|
||||
* fix smaller issues with special phrases import (thanks @AntoJvlt)
|
||||
* add index to speed up continued indexing during import
|
||||
* fix index on location_property_tiger(parent_place_id) (thanks @changpingc)
|
||||
* make sure Python code is backward-compatible with Python 3.5
|
||||
* various documentation fixes
|
||||
|
||||
3.7.0
|
||||
|
||||
* switch to dotenv for configuration file
|
||||
@@ -20,7 +175,6 @@
|
||||
* add non-key indexes to speed up housenumber + street searches
|
||||
* switch housenumber field in placex to save transliterated names
|
||||
|
||||
|
||||
3.6.0
|
||||
|
||||
* add full support for searching by and displaying of addr:* tags
|
||||
|
||||
@@ -20,14 +20,6 @@ https://nominatim.org/release-docs/develop/ .
|
||||
Installation
|
||||
============
|
||||
|
||||
**Nominatim is a complex piece of software and runs in a complex environment.
|
||||
Installing and running Nominatim is something for experienced system
|
||||
administrators only who can do some trouble-shooting themselves. We are sorry,
|
||||
but we can not provide installation support. We are all doing this in our free
|
||||
time and there is just so much of that time to go around. Do not open issues in
|
||||
our bug tracker if you need help. Use the discussions forum
|
||||
or ask for help on [help.openstreetmap.org](https://help.openstreetmap.org/).**
|
||||
|
||||
The latest stable release can be downloaded from https://nominatim.org.
|
||||
There you can also find [installation instructions for the release](https://nominatim.org/release-docs/latest/admin/Installation), as well as an extensive [Troubleshooting/FAQ section](https://nominatim.org/release-docs/latest/admin/Faq/).
|
||||
|
||||
|
||||
@@ -9,10 +9,11 @@ versions.
|
||||
|
||||
| Version | End of support for security updates |
|
||||
| ------- | ----------------------------------- |
|
||||
| 4.2.x | 2024-11-24 |
|
||||
| 4.1.x | 2024-08-05 |
|
||||
| 4.0.x | 2023-11-02 |
|
||||
| 3.7.x | 2023-04-05 |
|
||||
| 3.6.x | 2022-12-12 |
|
||||
| 3.5.x | 2022-06-05 |
|
||||
| 3.4.x | 2021-10-24 |
|
||||
|
||||
## Reporting a Vulnerability
|
||||
|
||||
|
||||
40
VAGRANT.md
40
VAGRANT.md
@@ -1,6 +1,6 @@
|
||||
# Install Nominatim in a virtual machine for development and testing
|
||||
|
||||
This document describes how you can install Nominatim inside a Ubuntu 16
|
||||
This document describes how you can install Nominatim inside a Ubuntu 22
|
||||
virtual machine on your desktop/laptop (host machine). The goal is to give
|
||||
you a development environment to easily edit code and run the test suite
|
||||
without affecting the rest of your system.
|
||||
@@ -42,9 +42,9 @@ is.
|
||||
|
||||
```
|
||||
# inside the virtual machine:
|
||||
cd build
|
||||
wget --no-verbose --output-document=/tmp/monaco.osm.pbf http://download.geofabrik.de/europe/monaco-latest.osm.pbf
|
||||
./utils/setup.php --osm-file /tmp/monaco.osm.pbf --osm2pgsql-cache 1000 --all 2>&1 | tee monaco.$$.log
|
||||
cd nominatim-project
|
||||
wget --no-verbose --output-document=monaco.osm.pbf http://download.geofabrik.de/europe/monaco-latest.osm.pbf
|
||||
nominatim import --osm-file monaco.osm.pbf 2>&1 | tee monaco.$$.log
|
||||
```
|
||||
|
||||
To repeat an import you'd need to delete the database first
|
||||
@@ -56,7 +56,7 @@ is.
|
||||
## Development
|
||||
|
||||
Vagrant maps the virtual machine's port 8089 to your host machine. Thus you can
|
||||
see Nominatim in action on [locahost:8089](http://localhost:8089/nominatim/).
|
||||
see Nominatim in action on [localhost:8089](http://localhost:8089/nominatim/).
|
||||
|
||||
You edit code on your host machine in any editor you like. There is no need to
|
||||
restart any software: just refresh your browser window.
|
||||
@@ -69,8 +69,7 @@ installation.
|
||||
PHP errors are written to `/var/log/apache2/error.log`.
|
||||
|
||||
With `echo` and `var_dump()` you write into the output (HTML/XML/JSON) when
|
||||
you either add `&debug=1` to the URL (preferred) or set
|
||||
`@define('CONST_Debug', true);` in `settings/local.php`.
|
||||
you either add `&debug=1` to the URL.
|
||||
|
||||
In the Python BDD test you can use `logger.info()` for temporary debug
|
||||
statements.
|
||||
@@ -130,6 +129,10 @@ and then
|
||||
Yes, Vagrant and Virtualbox can be installed on MS Windows just fine. You need a 64bit
|
||||
version of Windows.
|
||||
|
||||
##### Will it run on Apple Silicon?
|
||||
|
||||
You might need to replace Virtualbox with [Parallels](https://www.parallels.com/products/desktop/).
|
||||
There is no free/open source version of Parallels.
|
||||
|
||||
##### Why Monaco, can I use another country?
|
||||
|
||||
@@ -141,11 +144,12 @@ No. Long running Nominatim installations will differ once new import features (o
|
||||
bug fixes) get added since those usually only get applied to new/changed data.
|
||||
|
||||
Also this document skips the optional Wikipedia data import which affects ranking
|
||||
of search results. See [Nominatim installation](https://nominatim.org/release-docs/latest/admin/Installation) for details.
|
||||
of search results. See [Nominatim installation](https://nominatim.org/release-docs/latest/admin/Installation)
|
||||
for details.
|
||||
|
||||
##### Why Ubuntu? Can I test CentOS/Fedora/CoreOS/FreeBSD?
|
||||
|
||||
There is a Vagrant script for CentOS available, but the Nominatim directory
|
||||
There used to be a Vagrant script for CentOS available, but the Nominatim directory
|
||||
isn't symlinked/mounted to the host which makes development trickier. We used
|
||||
it mainly for debugging installation with SELinux.
|
||||
|
||||
@@ -154,14 +158,17 @@ are slightly different, e.g. the name of the package manager, Apache2 package
|
||||
name, location of files. We chose Ubuntu because that is closest to the
|
||||
nominatim.openstreetmap.org production environment.
|
||||
|
||||
You can configure/download other Vagrant boxes from [https://app.vagrantup.com/boxes/search](https://app.vagrantup.com/boxes/search).
|
||||
You can configure/download other Vagrant boxes from
|
||||
[https://app.vagrantup.com/boxes/search](https://app.vagrantup.com/boxes/search).
|
||||
|
||||
##### How can I connect to an existing database?
|
||||
|
||||
Let's say you have a Postgres database named `nominatim_it` on server `your-server.com` and port `5432`. The Postgres username is `postgres`. You can edit `settings/local.php` and point Nominatim to it.
|
||||
Let's say you have a Postgres database named `nominatim_it` on server `your-server.com`
|
||||
and port `5432`. The Postgres username is `postgres`. You can edit the `.env` in your
|
||||
project directory and point Nominatim to it.
|
||||
|
||||
NOMINATIM_DATABASE_DSN="pgsql:host=your-server.com;port=5432;user=postgres;dbname=nominatim_it
|
||||
|
||||
pgsql:host=your-server.com;port=5432;user=postgres;dbname=nominatim_it
|
||||
|
||||
No data import or restarting necessary.
|
||||
|
||||
If the Postgres installation is behind a firewall, you can try
|
||||
@@ -169,11 +176,12 @@ If the Postgres installation is behind a firewall, you can try
|
||||
ssh -L 9999:localhost:5432 your-username@your-server.com
|
||||
|
||||
inside the virtual machine. It will map the port to `localhost:9999` and then
|
||||
you edit `settings/local.php` with
|
||||
you edit `.env` file with
|
||||
|
||||
@define('CONST_Database_DSN', 'pgsql:host=localhost;port=9999;user=postgres;dbname=nominatim_it');
|
||||
NOMINATIM_DATABASE_DSN="pgsql:host=localhost;port=9999;user=postgres;dbname=nominatim_it"
|
||||
|
||||
To access postgres directly remember to specify the hostname, e.g. `psql --host localhost --port 9999 nominatim_it`
|
||||
To access postgres directly remember to specify the hostname,
|
||||
e.g. `psql --host localhost --port 9999 nominatim_it`
|
||||
|
||||
|
||||
##### My computer is slow and the import takes too long. Can I start the virtual machine "in the cloud"?
|
||||
|
||||
@@ -7,6 +7,9 @@ sys.path.insert(1, '@NOMINATIM_LIBDIR@/lib-python')
|
||||
os.environ['NOMINATIM_NOMINATIM_TOOL'] = os.path.abspath(__file__)
|
||||
|
||||
from nominatim import cli
|
||||
from nominatim import version
|
||||
|
||||
version.GIT_COMMIT_HASH = '@GIT_HASH@'
|
||||
|
||||
exit(cli.nominatim(module_dir='@NOMINATIM_LIBDIR@/module',
|
||||
osm2pgsql_path='@NOMINATIM_LIBDIR@/osm2pgsql',
|
||||
|
||||
@@ -7,6 +7,9 @@ sys.path.insert(1, '@CMAKE_SOURCE_DIR@')
|
||||
os.environ['NOMINATIM_NOMINATIM_TOOL'] = os.path.abspath(__file__)
|
||||
|
||||
from nominatim import cli
|
||||
from nominatim import version
|
||||
|
||||
version.GIT_COMMIT_HASH = '@GIT_HASH@'
|
||||
|
||||
exit(cli.nominatim(module_dir='@CMAKE_BINARY_DIR@/module',
|
||||
osm2pgsql_path='@CMAKE_BINARY_DIR@/osm2pgsql/osm2pgsql',
|
||||
|
||||
14
codecov.yml
14
codecov.yml
@@ -1,14 +0,0 @@
|
||||
codecov:
|
||||
require_ci_to_pass: yes
|
||||
|
||||
coverage:
|
||||
status:
|
||||
project: off
|
||||
patch: off
|
||||
|
||||
comment:
|
||||
require_changes: true
|
||||
after_n_builds: 2
|
||||
|
||||
fixes:
|
||||
- "Nominatim/::"
|
||||
File diff suppressed because one or more lines are too long
@@ -10,6 +10,7 @@ set (DOC_SOURCES
|
||||
admin
|
||||
develop
|
||||
api
|
||||
customize
|
||||
index.md
|
||||
extra.css
|
||||
styles.css
|
||||
@@ -22,11 +23,13 @@ foreach (src ${DOC_SOURCES})
|
||||
endforeach()
|
||||
|
||||
ADD_CUSTOM_TARGET(doc
|
||||
COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/bash2md.sh ${PROJECT_SOURCE_DIR}/vagrant/Install-on-Centos-7.sh ${CMAKE_CURRENT_BINARY_DIR}/appendix/Install-on-Centos-7.md
|
||||
COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/bash2md.sh ${PROJECT_SOURCE_DIR}/vagrant/Install-on-Centos-8.sh ${CMAKE_CURRENT_BINARY_DIR}/appendix/Install-on-Centos-8.md
|
||||
COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/bash2md.sh ${PROJECT_SOURCE_DIR}/vagrant/Install-on-Ubuntu-18.sh ${CMAKE_CURRENT_BINARY_DIR}/appendix/Install-on-Ubuntu-18.md
|
||||
COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/bash2md.sh ${PROJECT_SOURCE_DIR}/vagrant/Install-on-Ubuntu-20.sh ${CMAKE_CURRENT_BINARY_DIR}/appendix/Install-on-Ubuntu-20.md
|
||||
COMMAND mkdocs build -d ${CMAKE_CURRENT_BINARY_DIR}/../site-html -f ${CMAKE_CURRENT_BINARY_DIR}/../mkdocs.yml
|
||||
COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/bash2md.sh ${PROJECT_SOURCE_DIR}/vagrant/Install-on-Ubuntu-22.sh ${CMAKE_CURRENT_BINARY_DIR}/appendix/Install-on-Ubuntu-22.md
|
||||
COMMAND PYTHONPATH=${PROJECT_SOURCE_DIR} mkdocs build -d ${CMAKE_CURRENT_BINARY_DIR}/../site-html -f ${CMAKE_CURRENT_BINARY_DIR}/../mkdocs.yml
|
||||
)
|
||||
|
||||
|
||||
ADD_CUSTOM_TARGET(serve-doc
|
||||
COMMAND PYTHONPATH=${PROJECT_SOURCE_DIR} mkdocs serve
|
||||
WORKING_DIRECTORY ${PROJECT_BINARY_DIR}
|
||||
)
|
||||
|
||||
@@ -5,9 +5,34 @@ your Nominatim database. It is assumed that you have already successfully
|
||||
installed the Nominatim software itself, if not return to the
|
||||
[installation page](Installation.md).
|
||||
|
||||
## Importing multiple regions
|
||||
## Importing multiple regions (without updates)
|
||||
|
||||
To import multiple regions in your database, you need to configure and run `utils/import_multiple_regions.sh` file. This script will set up the update directory which has the following structure:
|
||||
To import multiple regions in your database you can simply give multiple
|
||||
OSM files to the import command:
|
||||
|
||||
```
|
||||
nominatim import --osm-file file1.pbf --osm-file file2.pbf
|
||||
```
|
||||
|
||||
If you already have imported a file and want to add another one, you can
|
||||
use the add-data function to import the additional data as follows:
|
||||
|
||||
```
|
||||
nominatim add-data --file <FILE>
|
||||
nominatim refresh --postcodes
|
||||
nominatim index -j <NUMBER OF THREADS>
|
||||
```
|
||||
|
||||
Please note that adding additional data is always significantly slower than
|
||||
the original import.
|
||||
|
||||
## Importing multiple regions (with updates)
|
||||
|
||||
If you want to import multiple regions _and_ be able to keep them up-to-date
|
||||
with updates, then you can use the scripts provided in the `utils` directory.
|
||||
|
||||
These scripts will set up an `update` directory in your project directory,
|
||||
which has the following structure:
|
||||
|
||||
```bash
|
||||
update
|
||||
@@ -17,7 +42,6 @@ update
|
||||
│ └── monaco
|
||||
│ └── sequence.state
|
||||
└── tmp
|
||||
├── combined.osm.pbf
|
||||
└── europe
|
||||
├── andorra-latest.osm.pbf
|
||||
└── monaco-latest.osm.pbf
|
||||
@@ -25,87 +49,59 @@ update
|
||||
|
||||
```
|
||||
|
||||
The `sequence.state` files will contain the sequence ID, which will be used by pyosmium to get updates. The tmp folder is used for import dump.
|
||||
The `sequence.state` files contain the sequence ID for each region. They will
|
||||
be used by pyosmium to get updates. The `tmp` folder is used for import dump and
|
||||
can be deleted once the import is complete.
|
||||
|
||||
### Configuring multiple regions
|
||||
|
||||
The file `import_multiple_regions.sh` needs to be edited as per your requirement:
|
||||
|
||||
1. List of countries. eg:
|
||||
|
||||
COUNTRIES="europe/monaco europe/andorra"
|
||||
|
||||
2. Path to Build directory. eg:
|
||||
|
||||
NOMINATIMBUILD="/srv/nominatim/build"
|
||||
|
||||
3. Path to Update directory. eg:
|
||||
|
||||
UPDATEDIR="/srv/nominatim/update"
|
||||
|
||||
4. Replication URL. eg:
|
||||
|
||||
BASEURL="https://download.geofabrik.de"
|
||||
DOWNCOUNTRYPOSTFIX="-latest.osm.pbf"
|
||||
|
||||
### Setting up multiple regions
|
||||
|
||||
!!! tip
|
||||
If your database already exists and you want to add more countries,
|
||||
replace the setting up part
|
||||
`${SETUPFILE} --osm-file ${UPDATEDIR}/tmp/combined.osm.pbf --all 2>&1`
|
||||
with `${UPDATEFILE} --import-file ${UPDATEDIR}/tmp/combined.osm.pbf --index --index-instances N 2>&1`
|
||||
where N is the numbers of CPUs in your system.
|
||||
Create a project directory as described for the
|
||||
[simple import](Import.md#creating-the-project-directory). If necessary,
|
||||
you can also add an `.env` configuration with customized options. In particular,
|
||||
you need to make sure that `NOMINATIM_REPLICATION_UPDATE_INTERVAL` and
|
||||
`NOMINATIM_REPLICATION_RECHECK_INTERVAL` are set according to the update
|
||||
interval of the extract server you use.
|
||||
|
||||
Run the following command from your Nominatim directory after configuring the file.
|
||||
Copy the scripts `utils/import_multiple_regions.sh` and `utils/update_database.sh`
|
||||
into the project directory.
|
||||
|
||||
bash ./utils/import_multiple_regions.sh
|
||||
Now customize both files as per your requirements
|
||||
|
||||
!!! danger "Important"
|
||||
This file uses osmium-tool. It must be installed before executing the import script.
|
||||
Installation instructions can be found [here](https://osmcode.org/osmium-tool/manual.html#installation).
|
||||
|
||||
### Updating multiple regions
|
||||
|
||||
To import multiple regions in your database, you need to configure and run ```utils/update_database.sh```.
|
||||
This uses the update directory set up while setting up the DB.
|
||||
|
||||
### Configuring multiple regions
|
||||
|
||||
The file `update_database.sh` needs to be edited as per your requirement:
|
||||
|
||||
1. List of countries. eg:
|
||||
1. List of countries. e.g.
|
||||
|
||||
COUNTRIES="europe/monaco europe/andorra"
|
||||
|
||||
2. Path to Build directory. eg:
|
||||
2. URL to the service providing the extracts and updates. eg:
|
||||
|
||||
NOMINATIMBUILD="/srv/nominatim/build"
|
||||
|
||||
3. Path to Update directory. eg:
|
||||
|
||||
UPDATEDIR="/srv/nominatim/update"
|
||||
|
||||
4. Replication URL. eg:
|
||||
|
||||
BASEURL="https://download.geofabrik.de"
|
||||
DOWNCOUNTRYPOSTFIX="-updates"
|
||||
DOWNCOUNTRYPOSTFIX="-latest.osm.pbf"
|
||||
|
||||
5. Followup can be set according to your installation. eg: For Photon,
|
||||
5. Followup in the update script can be set according to your installation.
|
||||
E.g. for Photon,
|
||||
|
||||
FOLLOWUP="curl http://localhost:2322/nominatim-update"
|
||||
|
||||
will handle the indexing.
|
||||
|
||||
|
||||
To start the initial import, change into the project directory and run
|
||||
|
||||
```
|
||||
bash import_multiple_regions.sh
|
||||
```
|
||||
|
||||
### Updating the database
|
||||
|
||||
Run the following command from your Nominatim directory after configuring the file.
|
||||
Change into the project directory and run the following command:
|
||||
|
||||
bash ./utils/update_database.sh
|
||||
bash update_database.sh
|
||||
|
||||
This will get diffs from the replication server, import diffs and index the database. The default replication server in the script([Geofabrik](https://download.geofabrik.de)) provides daily updates.
|
||||
This will get diffs from the replication server, import diffs and index
|
||||
the database. The default replication server in the
|
||||
script([Geofabrik](https://download.geofabrik.de)) provides daily updates.
|
||||
|
||||
## Importing Nominatim to an external PostgreSQL database
|
||||
## Using an external PostgreSQL database
|
||||
|
||||
You can install Nominatim using a database that runs on a different server when
|
||||
you have physical access to the file system on the other server. Nominatim
|
||||
@@ -113,6 +109,11 @@ uses a custom normalization library that needs to be made accessible to the
|
||||
PostgreSQL server. This section explains how to set up the normalization
|
||||
library.
|
||||
|
||||
!!! note
|
||||
The external module is only needed when using the legacy tokenizer.
|
||||
If you have chosen the ICU tokenizer, then you can ignore this section
|
||||
and follow the standard import documentation.
|
||||
|
||||
### Option 1: Compiling the library on the database server
|
||||
|
||||
The most sure way to get a working library is to compile it on the database
|
||||
@@ -170,4 +171,46 @@ NOMINATIM_DATABASE_MODULE_PATH="<directory on the database server where nominati
|
||||
```
|
||||
|
||||
Now change the `NOMINATIM_DATABASE_DSN` to point to your remote server and continue
|
||||
to follow the [standard instructions for importing](/admin/Import).
|
||||
to follow the [standard instructions for importing](Import.md).
|
||||
|
||||
|
||||
## Moving the database to another machine
|
||||
|
||||
For some configurations it may be useful to run the import on one machine, then
|
||||
move the database to another machine and run the Nominatim service from there.
|
||||
For example, you might want to use a large machine to be able to run the import
|
||||
quickly but only want a smaller machine for production because there is not so
|
||||
much load. Or you might want to do the import once and then replicate the
|
||||
database to many machines.
|
||||
|
||||
The important thing to keep in mind when transferring the Nominatim installation
|
||||
is that you need to transfer the database _and the project directory_. Both
|
||||
parts are essential for your installation.
|
||||
|
||||
The Nominatim database can be transferred using the `pg_dump`/`pg_restore` tool.
|
||||
Make sure to use the same version of PostgreSQL and PostGIS on source and
|
||||
target machine.
|
||||
|
||||
!!! note
|
||||
Before creating a dump of your Nominatim database, consider running
|
||||
`nominatim freeze` first. Your database looses the ability to receive further
|
||||
data updates but the resulting database is only about a third of the size
|
||||
of a full database.
|
||||
|
||||
Next install Nominatim on the target machine by following the standard installation
|
||||
instructions. Again, make sure to use the same version as the source machine.
|
||||
|
||||
Create a project directory on your destination machine and set up the `.env`
|
||||
file to match the configuration on the source machine. Finally run
|
||||
|
||||
nominatim refresh --website
|
||||
|
||||
to make sure that the local installation of Nominatim will be used.
|
||||
|
||||
If you are using the legacy tokenizer you might also have to switch to the
|
||||
PostgreSQL module that was compiled on your target machine. If you get errors
|
||||
that PostgreSQL cannot find or access `nominatim.so` then rerun
|
||||
|
||||
nominatim refresh --functions
|
||||
|
||||
on the target machine to update the the location of the module.
|
||||
|
||||
@@ -1,101 +0,0 @@
|
||||
# Customization of the Database
|
||||
|
||||
This section explains in detail how to configure a Nominatim import and
|
||||
the various means to use external data.
|
||||
|
||||
## External postcode data
|
||||
|
||||
Nominatim creates a table of known postcode centroids during import. This table
|
||||
is used for searches of postcodes and for adding postcodes to places where the
|
||||
OSM data does not provide one. These postcode centroids are mainly computed
|
||||
from the OSM data itself. In addition, Nominatim supports reading postcode
|
||||
information from an external CSV file, to supplement the postcodes that are
|
||||
missing in OSM.
|
||||
|
||||
To enable external postcode support, simply put one CSV file per country into
|
||||
your project directory and name it `<CC>_postcodes.csv`. `<CC>` must be the
|
||||
two-letter country code for which to apply the file. The file may also be
|
||||
gzipped. Then it must be called `<CC>_postcodes.csv.gz`.
|
||||
|
||||
The CSV file must use commas as a delimiter and have a header line. Nominatim
|
||||
expects three columns to be present: `postcode`, `lat` and `lon`. All other
|
||||
columns are ignored. `lon` and `lat` must describe the x and y coordinates of the
|
||||
postcode centroids in WGS84.
|
||||
|
||||
The postcode files are loaded only when there is data for the given country
|
||||
in your database. For example, if there is a `us_postcodes.csv` file in your
|
||||
project directory but you import only an excerpt of Italy, then the US postcodes
|
||||
will simply be ignored.
|
||||
|
||||
As a rule, the external postcode data should be put into the project directory
|
||||
**before** starting the initial import. Still, you can add, remove and update the
|
||||
external postcode data at any time. Simply
|
||||
run:
|
||||
|
||||
```
|
||||
nominatim refresh --postcodes
|
||||
```
|
||||
|
||||
to make the changes visible in your database. Be aware, however, that the changes
|
||||
only have an immediate effect on searches for postcodes. Postcodes that were
|
||||
added to places are only updated, when they are reindexed. That usually happens
|
||||
only during replication updates.
|
||||
|
||||
## Installing Tiger housenumber data for the US
|
||||
|
||||
Nominatim is able to use the official [TIGER](https://www.census.gov/geographies/mapping-files/time-series/geo/tiger-line-file.html)
|
||||
address set to complement the OSM house number data in the US. You can add
|
||||
TIGER data to your own Nominatim instance by following these steps. The
|
||||
entire US adds about 10GB to your database.
|
||||
|
||||
1. Get preprocessed TIGER 2020 data:
|
||||
|
||||
cd $PROJECT_DIR
|
||||
wget https://nominatim.org/data/tiger2020-nominatim-preprocessed.csv.tar.gz
|
||||
|
||||
2. Import the data into your Nominatim database:
|
||||
|
||||
nominatim add-data --tiger-data tiger2020-nominatim-preprocessed.csv.tar.gz
|
||||
|
||||
3. Enable use of the Tiger data in your `.env` by adding:
|
||||
|
||||
echo NOMINATIM_USE_US_TIGER_DATA=yes >> .env
|
||||
|
||||
4. Apply the new settings:
|
||||
|
||||
nominatim refresh --functions
|
||||
|
||||
|
||||
See the [developer's guide](../develop/data-sources.md#us-census-tiger) for more
|
||||
information on how the data got preprocessed.
|
||||
|
||||
## Special phrases import
|
||||
|
||||
As described in the [Importation chapter](Import.md), it is possible to
|
||||
import special phrases from the wiki with the following command:
|
||||
|
||||
```sh
|
||||
nominatim special-phrases --import-from-wiki
|
||||
```
|
||||
|
||||
But, it is also possible to import some phrases from a csv file.
|
||||
To do so, you have access to the following command:
|
||||
|
||||
```sh
|
||||
nominatim special-phrases --import-from-csv <csv file>
|
||||
```
|
||||
|
||||
Note that the two previous import commands will update the phrases from your database.
|
||||
This means that if you import some phrases from a csv file, only the phrases
|
||||
present in the csv file will be kept into the database. All other phrases will
|
||||
be removed.
|
||||
|
||||
If you want to only add new phrases and not update the other ones you can add
|
||||
the argument `--no-replace` to the import command. For example:
|
||||
|
||||
```sh
|
||||
nominatim special-phrases --import-from-csv <csv file> --no-replace
|
||||
```
|
||||
|
||||
This will add the phrases present in the csv file into the database without
|
||||
removing the other ones.
|
||||
@@ -82,7 +82,7 @@ The website should now be available on `http://localhost/nominatim`.
|
||||
|
||||
### Installing the required packages
|
||||
|
||||
Nginx has no built-in PHP interpreter. You need to use php-fpm as a deamon for
|
||||
Nginx has no built-in PHP interpreter. You need to use php-fpm as a daemon for
|
||||
serving PHP cgi.
|
||||
|
||||
On Ubuntu/Debian install nginx and php-fpm with:
|
||||
@@ -99,7 +99,7 @@ Unix socket instead, change the pool configuration
|
||||
|
||||
``` ini
|
||||
; Replace the tcp listener and add the unix socket
|
||||
listen = /var/run/php-fpm.sock
|
||||
listen = /var/run/php-fpm-nominatim.sock
|
||||
|
||||
; Ensure that the daemon runs as the correct user
|
||||
listen.owner = www-data
|
||||
@@ -121,7 +121,7 @@ location @php {
|
||||
fastcgi_param SCRIPT_FILENAME "$document_root$uri.php";
|
||||
fastcgi_param PATH_TRANSLATED "$document_root$uri.php";
|
||||
fastcgi_param QUERY_STRING $args;
|
||||
fastcgi_pass unix:/var/run/php-fpm.sock;
|
||||
fastcgi_pass unix:/var/run/php-fpm-nominatim.sock;
|
||||
fastcgi_index index.php;
|
||||
include fastcgi_params;
|
||||
}
|
||||
@@ -131,7 +131,7 @@ location ~ [^/]\.php(/|$) {
|
||||
if (!-f $document_root$fastcgi_script_name) {
|
||||
return 404;
|
||||
}
|
||||
fastcgi_pass unix:/var/run/php-fpm.sock;
|
||||
fastcgi_pass unix:/var/run/php-fpm-nominatim.sock;
|
||||
fastcgi_index search.php;
|
||||
include fastcgi.conf;
|
||||
}
|
||||
@@ -140,3 +140,9 @@ location ~ [^/]\.php(/|$) {
|
||||
Restart the nginx and php-fpm services and the website should now be available
|
||||
at `http://localhost/`.
|
||||
|
||||
## Nominatim with other webservers
|
||||
|
||||
Users have created instructions for other webservers:
|
||||
|
||||
* [Caddy](https://github.com/osm-search/Nominatim/discussions/2580)
|
||||
|
||||
|
||||
@@ -79,7 +79,7 @@ When running the import you may get a version mismatch:
|
||||
|
||||
pg_config seems to use bad includes sometimes when multiple versions
|
||||
of PostgreSQL are available in the system. Make sure you remove the
|
||||
server development libraries (`postgresql-server-dev-9.5` on Ubuntu)
|
||||
server development libraries (`postgresql-server-dev-13` on Ubuntu)
|
||||
and recompile (`cmake .. && make`).
|
||||
|
||||
|
||||
@@ -106,11 +106,6 @@ If you are using a flatnode file, then it may also be that the underlying
|
||||
filesystem does not fully support 'mmap'. A notable candidate is virtualbox's
|
||||
vboxfs.
|
||||
|
||||
### I see the error: "clang: Command not found" on CentOS
|
||||
|
||||
On CentOS 7 users reported `/opt/rh/llvm-toolset-7/root/usr/bin/clang: Command not found`.
|
||||
Double-check clang is installed. Instead of `make` try running `make CLANG=true`.
|
||||
|
||||
### nominatim UPDATE failed: ERROR: buffer 179261 is not owned by resource owner Portal
|
||||
|
||||
Several users [reported this](https://github.com/openstreetmap/Nominatim/issues/1168)
|
||||
@@ -126,22 +121,6 @@ The server cannot access your database. Add `&debug=1` to your URL
|
||||
to get the full error message.
|
||||
|
||||
|
||||
### On CentOS the website shows "Could not connect to server"
|
||||
|
||||
`could not connect to server: No such file or directory`
|
||||
|
||||
On CentOS v7 the PostgreSQL server is started with `systemd`. Check if
|
||||
`/usr/lib/systemd/system/httpd.service` contains a line `PrivateTmp=true`. If
|
||||
so then Apache cannot see the `/tmp/.s.PGSQL.5432` file. It's a good security
|
||||
feature, so use the
|
||||
[preferred solution](../appendix/Install-on-Centos-7/#adding-selinux-security-settings).
|
||||
|
||||
However, you can solve this the quick and dirty way by commenting out that line and then run
|
||||
|
||||
sudo systemctl daemon-reload
|
||||
sudo systemctl restart httpd
|
||||
|
||||
|
||||
### Website reports "DB Error: insufficient permissions"
|
||||
|
||||
The user the webserver, e.g. Apache, runs under needs to have access to the
|
||||
@@ -181,9 +160,6 @@ by everybody, e.g.
|
||||
|
||||
Try `chmod a+r nominatim.so; chmod a+x nominatim.so`.
|
||||
|
||||
When running SELinux, make sure that the
|
||||
[context is set up correctly](../appendix/Install-on-Centos-7/#adding-selinux-security-settings).
|
||||
|
||||
When you recently updated your operating system, updated PostgreSQL to
|
||||
a new version or moved files (e.g. the build directory) you should
|
||||
recreate `nominatim.so`. Try
|
||||
|
||||
@@ -47,8 +47,9 @@ You can also set the same configuration via environment variables. All
|
||||
settings have a `NOMINATIM_` prefix to avoid conflicts with other environment
|
||||
variables.
|
||||
|
||||
There are lots of configuration settings you can tweak. Have a look
|
||||
at `Nominatim/settings/env.default` for a full list. Most should have a sensible default.
|
||||
There are lots of configuration settings you can tweak. A full reference
|
||||
can be found in the chapter [Configuration Settings](../customize/Settings.md).
|
||||
Most should have a sensible default.
|
||||
|
||||
#### Flatnode files
|
||||
|
||||
@@ -73,15 +74,15 @@ but it will improve the quality of the results if this is installed.
|
||||
This data is available as a binary download. Put it into your project directory:
|
||||
|
||||
cd $PROJECT_DIR
|
||||
wget https://www.nominatim.org/data/wikimedia-importance.sql.gz
|
||||
wget https://nominatim.org/data/wikimedia-importance.sql.gz
|
||||
|
||||
The file is about 400MB and adds around 4GB to the Nominatim database.
|
||||
|
||||
!!! tip
|
||||
If you forgot to download the wikipedia rankings, you can also add
|
||||
importances after the import. Download the files, then run
|
||||
`nominatim refresh --wiki-data --importance`. Updating importances for
|
||||
a planet can take a couple of hours.
|
||||
If you forgot to download the wikipedia rankings, then you can
|
||||
also add importances after the import. Download the SQL files, then
|
||||
run `nominatim refresh --wiki-data --importance`. Updating
|
||||
importances for a planet will take a couple of hours.
|
||||
|
||||
### External postcodes
|
||||
|
||||
@@ -91,11 +92,11 @@ and the UK (using the [CodePoint OpenData set](https://osdatahub.os.uk/downloads
|
||||
This data can be optionally downloaded into the project directory:
|
||||
|
||||
cd $PROJECT_DIR
|
||||
wget https://www.nominatim.org/data/gb_postcodes.csv.gz
|
||||
wget https://www.nominatim.org/data/us_postcodes.csv.gz
|
||||
wget https://nominatim.org/data/gb_postcodes.csv.gz
|
||||
wget https://nominatim.org/data/us_postcodes.csv.gz
|
||||
|
||||
You can also add your own custom postcode sources, see
|
||||
[Customization of postcodes](Customization.md#external-postcode-data).
|
||||
[Customization of postcodes](../customize/Postcodes.md).
|
||||
|
||||
## Choosing the data to import
|
||||
|
||||
@@ -111,7 +112,7 @@ If you only need geocoding for a smaller region, then precomputed OSM extracts
|
||||
are a good way to reduce the database size and import time.
|
||||
[Geofabrik](https://download.geofabrik.de) offers extracts for most countries.
|
||||
They even have daily updates which can be used with the update process described
|
||||
[in the next section](../Update). There are also
|
||||
[in the next section](Update.md). There are also
|
||||
[other providers for extracts](https://wiki.openstreetmap.org/wiki/Planet.osm#Downloading).
|
||||
|
||||
Please be aware that some extracts are not cut exactly along the country
|
||||
@@ -137,11 +138,19 @@ Note that you still need to provide for sufficient disk space for the initial
|
||||
import. So this option is particularly interesting if you plan to transfer the
|
||||
database or reuse the space later.
|
||||
|
||||
!!! warning
|
||||
The data structure for updates are also required when adding additional data
|
||||
after the import, for example [TIGER housenumber data](../customize/Tiger.md).
|
||||
If you plan to use those, you must not use the `--no-updates` parameter.
|
||||
Do a normal import, add the external data and once you are done with
|
||||
everything run `nominatim freeze`.
|
||||
|
||||
|
||||
### Reverse-only Imports
|
||||
|
||||
If you only want to use the Nominatim database for reverse lookups or
|
||||
if you plan to use the installation only for exports to a
|
||||
[photon](https://photon.komoot.de/) database, then you can set up a database
|
||||
[photon](https://photon.komoot.io/) database, then you can set up a database
|
||||
without search indexes. Add `--reverse-only` to your setup command above.
|
||||
|
||||
This saves about 5% of disk space.
|
||||
@@ -152,15 +161,15 @@ Nominatim normally sets up a full search database containing administrative
|
||||
boundaries, places, streets, addresses and POI data. There are also other
|
||||
import styles available which only read selected data:
|
||||
|
||||
* **settings/import-admin.style**
|
||||
* **admin**
|
||||
Only import administrative boundaries and places.
|
||||
* **settings/import-street.style**
|
||||
* **street**
|
||||
Like the admin style but also adds streets.
|
||||
* **settings/import-address.style**
|
||||
* **address**
|
||||
Import all data necessary to compute addresses down to house number level.
|
||||
* **settings/import-full.style**
|
||||
* **full**
|
||||
Default style that also includes points of interest.
|
||||
* **settings/import-extratags.style**
|
||||
* **extratags**
|
||||
Like the full style but also adds most of the OSM tags into the extratags
|
||||
column.
|
||||
|
||||
@@ -183,8 +192,8 @@ full | 54h | 640 GB | 330 GB
|
||||
extratags | 54h | 650 GB | 340 GB
|
||||
|
||||
You can also customize the styles further.
|
||||
A [description of the style format](../develop/Import.md#configuring-the-import)
|
||||
can be found in the development section.
|
||||
A [description of the style format](../customize/Import-Styles.md)
|
||||
can be found in the customization guide.
|
||||
|
||||
## Initial import of the data
|
||||
|
||||
@@ -200,7 +209,7 @@ nominatim import --osm-file <data file> 2>&1 | tee setup.log
|
||||
```
|
||||
|
||||
The **project directory** is the one that you have set up at the beginning.
|
||||
See [creating the project directory](Import#creating-the-project-directory).
|
||||
See [creating the project directory](#creating-the-project-directory).
|
||||
|
||||
### Notes on full planet imports
|
||||
|
||||
@@ -219,7 +228,7 @@ to load the OSM data into the PostgreSQL database. This step is very demanding
|
||||
in terms of RAM usage. osm2pgsql and PostgreSQL are running in parallel at
|
||||
this point. PostgreSQL blocks at least the part of RAM that has been configured
|
||||
with the `shared_buffers` parameter during
|
||||
[PostgreSQL tuning](Installation#postgresql-tuning)
|
||||
[PostgreSQL tuning](Installation.md#postgresql-tuning)
|
||||
and needs some memory on top of that. osm2pgsql needs at least 2GB of RAM for
|
||||
its internal data structures, potentially more when it has to process very large
|
||||
relations. In addition it needs to maintain a cache for node locations. The size
|
||||
@@ -238,7 +247,8 @@ reduce the cache size or even consider using a flatnode file.
|
||||
|
||||
### Testing the installation
|
||||
|
||||
Run this script to verify all required tables and indices got created successfully.
|
||||
Run this script to verify that all required tables and indices got created
|
||||
successfully.
|
||||
|
||||
```sh
|
||||
nominatim admin --check-database
|
||||
@@ -261,23 +271,10 @@ reverse query, e.g. `http://localhost:8088/reverse.php?lat=27.1750090510034&lon=
|
||||
To run Nominatim via webservers like Apache or nginx, please read the
|
||||
[Deployment chapter](Deployment.md).
|
||||
|
||||
## Tuning the database
|
||||
|
||||
Accurate word frequency information for search terms helps PostgreSQL's query
|
||||
planner to make the right decisions. Recomputing them can improve the performance
|
||||
of forward geocoding in particular under high load. To recompute word counts run:
|
||||
|
||||
```sh
|
||||
nominatim refresh --word-counts
|
||||
```
|
||||
|
||||
This will take a couple of hours for a full planet installation. You can
|
||||
also defer that step to a later point in time when you realise that
|
||||
performance becomes an issue. Just make sure that updates are stopped before
|
||||
running this function.
|
||||
## Adding search through category phrases
|
||||
|
||||
If you want to be able to search for places by their type through
|
||||
[special key phrases](https://wiki.openstreetmap.org/wiki/Nominatim/Special_Phrases)
|
||||
[special phrases](https://wiki.openstreetmap.org/wiki/Nominatim/Special_Phrases)
|
||||
you also need to import these key phrases like this:
|
||||
|
||||
```sh
|
||||
@@ -288,4 +285,4 @@ Note that this command downloads the phrases from the wiki link above. You
|
||||
need internet access for the step.
|
||||
|
||||
You can also import special phrases from a csv file, for more
|
||||
information please read the [Customization chapter](Customization.md).
|
||||
information please see the [Customization part](../customize/Special-Phrases.md).
|
||||
|
||||
@@ -4,10 +4,9 @@ This page contains generic installation instructions for Nominatim and its
|
||||
prerequisites. There are also step-by-step instructions available for
|
||||
the following operating systems:
|
||||
|
||||
* [Ubuntu 22.04](../appendix/Install-on-Ubuntu-22.md)
|
||||
* [Ubuntu 20.04](../appendix/Install-on-Ubuntu-20.md)
|
||||
* [Ubuntu 18.04](../appendix/Install-on-Ubuntu-18.md)
|
||||
* [CentOS 8](../appendix/Install-on-Centos-8.md)
|
||||
* [CentOS 7.2](../appendix/Install-on-Centos-7.md)
|
||||
|
||||
These OS-specific instructions can also be found in executable form
|
||||
in the `vagrant/` directory.
|
||||
@@ -24,6 +23,11 @@ and can't offer support.
|
||||
|
||||
### Software
|
||||
|
||||
!!! Warning
|
||||
For larger installations you **must have** PostgreSQL 11+ and PostGIS 3+
|
||||
otherwise import and queries will be slow to the point of being unusable.
|
||||
Query performance has marked improvements with PostgreSQL 13+ and PostGIS 3.2+.
|
||||
|
||||
For compiling:
|
||||
|
||||
* [cmake](https://cmake.org/)
|
||||
@@ -38,8 +42,8 @@ For compiling:
|
||||
|
||||
For running Nominatim:
|
||||
|
||||
* [PostgreSQL](https://www.postgresql.org) (9.5+ will work, 11+ strongly recommended)
|
||||
* [PostGIS](https://postgis.net) (2.2+)
|
||||
* [PostgreSQL](https://www.postgresql.org) (9.6+ will work, 11+ strongly recommended)
|
||||
* [PostGIS](https://postgis.net) (2.2+ will work, 3.0+ strongly recommended)
|
||||
* [Python 3](https://www.python.org/) (3.6+)
|
||||
* [Psycopg2](https://www.psycopg.org) (2.7+)
|
||||
* [Python Dotenv](https://github.com/theskumar/python-dotenv)
|
||||
@@ -63,10 +67,10 @@ the [Development section](../develop/Development-Environment.md).
|
||||
### Hardware
|
||||
|
||||
A minimum of 2GB of RAM is required or installation will fail. For a full
|
||||
planet import 64GB of RAM or more are strongly recommended. Do not report
|
||||
planet import 128GB of RAM or more are strongly recommended. Do not report
|
||||
out of memory problems if you have less than 64GB RAM.
|
||||
|
||||
For a full planet install you will need at least 900GB of hard disk space.
|
||||
For a full planet install you will need at least 1TB of hard disk space.
|
||||
Take into account that the OSM database is growing fast.
|
||||
Fast disks are essential. Using NVME disks is recommended.
|
||||
|
||||
@@ -85,8 +89,7 @@ your `postgresql.conf` file.
|
||||
work_mem = (50MB)
|
||||
effective_cache_size = (24GB)
|
||||
synchronous_commit = off
|
||||
checkpoint_segments = 100 # only for postgresql <= 9.4
|
||||
max_wal_size = 1GB # postgresql > 9.4
|
||||
max_wal_size = 1GB
|
||||
checkpoint_timeout = 10min
|
||||
checkpoint_completion_target = 0.9
|
||||
|
||||
@@ -109,7 +112,7 @@ For the initial import, you should also set:
|
||||
fsync = off
|
||||
full_page_writes = off
|
||||
|
||||
Don't forget to reenable them after the initial import or you risk database
|
||||
Don't forget to re-enable them after the initial import or you risk database
|
||||
corruption.
|
||||
|
||||
|
||||
@@ -126,13 +129,13 @@ If you want to install latest development version from github, make sure to
|
||||
also check out the osm2pgsql subproject:
|
||||
|
||||
```
|
||||
git clone --recursive git://github.com/openstreetmap/Nominatim.git
|
||||
git clone --recursive https://github.com/openstreetmap/Nominatim.git
|
||||
```
|
||||
|
||||
The development version does not include the country grid. Download it separately:
|
||||
|
||||
```
|
||||
wget -O Nominatim/data/country_osm_grid.sql.gz https://www.nominatim.org/data/country_grid.sql.gz
|
||||
wget -O Nominatim/data/country_osm_grid.sql.gz https://nominatim.org/data/country_grid.sql.gz
|
||||
```
|
||||
|
||||
### Building Nominatim
|
||||
@@ -154,6 +157,17 @@ make
|
||||
sudo make install
|
||||
```
|
||||
|
||||
!!! warning
|
||||
The default installation no longer compiles the PostgreSQL module that
|
||||
is needed for the legacy tokenizer from older Nominatim versions. If you
|
||||
are upgrading an older database or want to run the
|
||||
[legacy tokenizer](../customize/Tokenizers.md#legacy-tokenizer) for
|
||||
some other reason, you need to enable the PostgreSQL module via
|
||||
cmake: `cmake -DBUILD_MODULE=on ../Nominatim`. To compile the module
|
||||
you need to have the server development headers for PostgreSQL installed.
|
||||
On Ubuntu/Debian run: `sudo apt install postgresql-server-dev-<postgresql version>`
|
||||
|
||||
|
||||
Nominatim installs itself into `/usr/local` per default. To choose a different
|
||||
installation directory add `-DCMAKE_INSTALL_PREFIX=<install root>` to the
|
||||
cmake command. Make sure that the `bin` directory is available in your path
|
||||
|
||||
75
docs/admin/Maintenance.md
Normal file
75
docs/admin/Maintenance.md
Normal file
@@ -0,0 +1,75 @@
|
||||
This chapter describes the various operations the Nominatim database administrator
|
||||
may use to clean and maintain the database. None of these operations is mandatory
|
||||
but they may help improve the performance and accuracy of results.
|
||||
|
||||
|
||||
## Updating postcodes
|
||||
|
||||
Command: `nominatim refresh --postcodes`
|
||||
|
||||
Postcode centroids (aka 'calculated postcodes') are generated by looking at all
|
||||
postcodes of a country, grouping them and calculating the geometric centroid.
|
||||
There is currently no logic to deal with extreme outliers (typos or other
|
||||
mistakes in OSM data). There is also no check if a postcodes adheres to a
|
||||
country's format, e.g. if Swiss postcodes are 4 digits.
|
||||
|
||||
When running regular updates, postcodes results can be improved by running
|
||||
this command on a regular basis. Note that only the postcode table and the
|
||||
postcode search terms are updated. The postcode that is assigned to each place
|
||||
is only updated when the place is updated.
|
||||
|
||||
The command takes around 70min to run on the planet and needs ca. 40GB of
|
||||
temporary disk space.
|
||||
|
||||
|
||||
## Updating word counts
|
||||
|
||||
Command: `nominatim refresh --word-counts`
|
||||
|
||||
Nominatim keeps frequency statistics about all search terms it indexes. These
|
||||
statistics are currently used to optimise queries to the database. Thus better
|
||||
statistics mean better performance. Word counts are created once after import
|
||||
and are usually sufficient even when running regular updates. You might want
|
||||
to rerun the statistics computation when adding larger amounts of new data,
|
||||
for example, when adding an additional country via `nominatim add-data`.
|
||||
|
||||
|
||||
## Forcing recomputation of places and areas
|
||||
|
||||
Command: `nominatim refresh --data-object [NWR]<id> --data-area [NWR]<id>`
|
||||
|
||||
When running replication updates, Nominatim tries to recompute the search
|
||||
and address information for all places that are affected by a change. But it
|
||||
needs to restrict the total number of changes to make sure it can keep up
|
||||
with the minutely updates. Therefore it will refrain from propagating changes
|
||||
that affect a lot of objects.
|
||||
|
||||
The administrator may force an update of places in the database.
|
||||
`nominatim refresh --data-object` invalidates a single OSM object.
|
||||
`nominatim refresh --data-area` invalidates an OSM object and all dependent
|
||||
objects. That are usually the places that inside its area or around the
|
||||
center of the object. Both commands expect the OSM object as an argument
|
||||
of the form OSM type + OSM id. The type must be `N` (node), `W` (way) or
|
||||
`R` (relation).
|
||||
|
||||
After invalidating the object, indexing must be run again. If continuous
|
||||
update are running in the background, the objects will be recomputed together
|
||||
with the next round of updates. Otherwise you need to run `nominatim index`
|
||||
to finish the recomputation.
|
||||
|
||||
|
||||
## Removing large deleted objects
|
||||
|
||||
Nominatim refuses to delete very large areas because often these deletions are
|
||||
accidental and are reverted within hours. Instead the deletions are logged in
|
||||
the `import_polygon_delete` table and left to the administrator to clean up.
|
||||
|
||||
There is currently no command to do that. You can use the following SQL
|
||||
query to force a deletion on all objects that have been deleted more than
|
||||
a certain timespan ago (here: 1 month):
|
||||
|
||||
```sql
|
||||
SELECT place_force_delete(p.place_id) FROM import_polygon_delete d, placex p
|
||||
WHERE p.osm_type = d.osm_type and p.osm_id = d.osm_id
|
||||
and age(p.indexed_date) > '1 month'::interval
|
||||
```
|
||||
@@ -15,6 +15,44 @@ breaking changes. **Please read them before running the migration.**
|
||||
If you are migrating from a version <3.6, then you still have to follow
|
||||
the manual migration steps up to 3.6.
|
||||
|
||||
## 4.0.0 -> 4.1.0
|
||||
|
||||
### ICU tokenizer is the new default
|
||||
|
||||
Nominatim now installs the [ICU tokenizer](../customize/Tokenizers.md#icu-tokenizer)
|
||||
by default. This only has an effect on newly installed databases. When
|
||||
updating older databases, it keeps its installed tokenizer. If you still
|
||||
run with the legacy tokenizer, make sure to compile Nominatim with the
|
||||
PostgreSQL module, see [Installation](Installation.md#building-nominatim).
|
||||
|
||||
### geocodejson output changed
|
||||
|
||||
The `type` field of the geocodejson output has changed. It now contains
|
||||
the address class of the object instead of the value of the OSM tag. If
|
||||
your client has used the `type` field, switch them to read `osm_value`
|
||||
instead.
|
||||
|
||||
## 3.7.0 -> 4.0.0
|
||||
|
||||
### NOMINATIM_PHRASE_CONFIG removed
|
||||
|
||||
Custom blacklist configurations for special phrases now need to be handed
|
||||
with the `--config` parameter to `nominatim special-phrases`. Alternatively
|
||||
you can put your custom configuration in the project directory in a file
|
||||
named `phrase-settings.json`.
|
||||
|
||||
Version 3.8 also removes the automatic converter for the php format of
|
||||
the configuration in older versions. If you are updating from Nominatim < 3.7
|
||||
and still work with a custom `phrase-settings.php`, you need to manually
|
||||
convert it into a json format.
|
||||
|
||||
### PHP utils removed
|
||||
|
||||
The old PHP utils have now been removed completely. You need to switch to
|
||||
the appropriate functions of the nominatim command line tool. See
|
||||
[Introducing `nominatim` command line tool](#introducing-nominatim-command-line-tool)
|
||||
below.
|
||||
|
||||
## 3.6.0 -> 3.7.0
|
||||
|
||||
### New format and name of configuration file
|
||||
@@ -80,7 +118,7 @@ done
|
||||
|
||||
The debugging UI is no longer directly provided with Nominatim. Instead we
|
||||
now provide a simple Javascript application. Please refer to
|
||||
[Setting up the Nominatim UI](../Setup-Nominatim-UI) for details on how to
|
||||
[Setting up the Nominatim UI](Setup-Nominatim-UI.md) for details on how to
|
||||
set up the UI.
|
||||
|
||||
The icons served together with the API responses have been moved to the
|
||||
|
||||
@@ -16,13 +16,14 @@ and run it. Grab the latest release from
|
||||
[nominatim-ui's Github release page](https://github.com/osm-search/nominatim-ui/releases)
|
||||
and unpack it. You can use `nominatim-ui-x.x.x.tar.gz` or `nominatim-ui-x.x.x.zip`.
|
||||
|
||||
Copy the example configuration into the right place:
|
||||
Next you need to adapt the UI to your installation. Custom settings need to be
|
||||
put into `dist/theme/config.theme.js`. At a minimum you need to
|
||||
set `Nominatim_API_Endpoint` to point to your Nominatim installation:
|
||||
|
||||
cd nominatim-ui
|
||||
cp dist/config.example.js dist/config.js
|
||||
echo "Nominatim_Config.Nominatim_API_Endpoint='https://myserver.org/nominatim/';" > dist/theme/config.theme.js
|
||||
|
||||
Now adapt the configuration to your needs. You need at least
|
||||
to change the `Nominatim_API_Endpoint` to point to your Nominatim installation.
|
||||
For the full set of available settings, have a look at `dist/config.defaults.js`.
|
||||
|
||||
Then you can just test it locally by spinning up a webserver in the `dist`
|
||||
directory. For example, with Python:
|
||||
@@ -160,24 +161,16 @@ directory like this:
|
||||
# If no endpoint is given, then use search.
|
||||
RewriteRule ^(/|$) "search.php"
|
||||
|
||||
# If format-html is explicity requested, forward to the UI.
|
||||
# If format-html is explicitly requested, forward to the UI.
|
||||
RewriteCond %{QUERY_STRING} "format=html"
|
||||
RewriteRule ^([^/]+).php ui/$1.html [R,END]
|
||||
# Same but .php suffix is missing.
|
||||
RewriteCond %{QUERY_STRING} "format=html"
|
||||
RewriteRule ^([^/]+) ui/$1.html [R,END]
|
||||
RewriteRule ^([^/]+)(.php)? ui/$1.html [R,END]
|
||||
|
||||
# If no format parameter is there then forward anything
|
||||
# but /reverse and /lookup to the UI.
|
||||
RewriteCond %{QUERY_STRING} "!format="
|
||||
RewriteCond %{REQUEST_URI} "!/lookup"
|
||||
RewriteCond %{REQUEST_URI} "!/reverse"
|
||||
RewriteRule ^([^/]+).php ui/$1.html [R,END]
|
||||
# Same but .php suffix is missing.
|
||||
RewriteCond %{QUERY_STRING} "!format="
|
||||
RewriteCond %{REQUEST_URI} "!/lookup"
|
||||
RewriteCond %{REQUEST_URI} "!/reverse"
|
||||
RewriteRule ^([^/]+) ui/$1.html [R,END]
|
||||
RewriteRule ^([^/]+)(.php)? ui/$1.html [R,END]
|
||||
</Directory>
|
||||
```
|
||||
|
||||
|
||||
@@ -1,205 +0,0 @@
|
||||
# Tokenizers
|
||||
|
||||
The tokenizer module in Nominatim is responsible for analysing the names given
|
||||
to OSM objects and the terms of an incoming query in order to make sure, they
|
||||
can be matched appropriately.
|
||||
|
||||
Nominatim offers different tokenizer modules, which behave differently and have
|
||||
different configuration options. This sections describes the tokenizers and how
|
||||
they can be configured.
|
||||
|
||||
!!! important
|
||||
The use of a tokenizer is tied to a database installation. You need to choose
|
||||
and configure the tokenizer before starting the initial import. Once the import
|
||||
is done, you cannot switch to another tokenizer anymore. Reconfiguring the
|
||||
chosen tokenizer is very limited as well. See the comments in each tokenizer
|
||||
section.
|
||||
|
||||
## Legacy tokenizer
|
||||
|
||||
The legacy tokenizer implements the analysis algorithms of older Nominatim
|
||||
versions. It uses a special Postgresql module to normalize names and queries.
|
||||
This tokenizer is currently the default.
|
||||
|
||||
To enable the tokenizer add the following line to your project configuration:
|
||||
|
||||
```
|
||||
NOMINATIM_TOKENIZER=legacy
|
||||
```
|
||||
|
||||
The Postgresql module for the tokenizer is available in the `module` directory
|
||||
and also installed with the remainder of the software under
|
||||
`lib/nominatim/module/nominatim.so`. You can specify a custom location for
|
||||
the module with
|
||||
|
||||
```
|
||||
NOMINATIM_DATABASE_MODULE_PATH=<path to directory where nominatim.so resides>
|
||||
```
|
||||
|
||||
This is in particular useful when the database runs on a different server.
|
||||
See [Advanced installations](Advanced-Installations.md#importing-nominatim-to-an-external-postgresql-database) for details.
|
||||
|
||||
There are no other configuration options for the legacy tokenizer. All
|
||||
normalization functions are hard-coded.
|
||||
|
||||
## ICU tokenizer
|
||||
|
||||
!!! danger
|
||||
This tokenizer is currently in active development and still subject
|
||||
to backwards-incompatible changes.
|
||||
|
||||
The ICU tokenizer uses the [ICU library](http://site.icu-project.org/) to
|
||||
normalize names and queries. It also offers configurable decomposition and
|
||||
abbreviation handling.
|
||||
|
||||
### How it works
|
||||
|
||||
On import the tokenizer processes names in the following four stages:
|
||||
|
||||
1. The **Normalization** part removes all non-relevant information from the
|
||||
input.
|
||||
2. Incoming names are now converted to **full names**. This process is currently
|
||||
hard coded and mostly serves to handle name tags from OSM that contain
|
||||
multiple names (e.g. [Biel/Bienne](https://www.openstreetmap.org/node/240097197)).
|
||||
3. Next the tokenizer creates **variants** from the full names. These variants
|
||||
cover decomposition and abbreviation handling. Variants are saved to the
|
||||
database, so that it is not necessary to create the variants for a search
|
||||
query.
|
||||
4. The final **Tokenization** step converts the names to a simple ASCII form,
|
||||
potentially removing further spelling variants for better matching.
|
||||
|
||||
At query time only stage 1) and 4) are used. The query is normalized and
|
||||
tokenized and the resulting string used for searching in the database.
|
||||
|
||||
### Configuration
|
||||
|
||||
The ICU tokenizer is configured using a YAML file which can be configured using
|
||||
`NOMINATIM_TOKENIZER_CONFIG`. The configuration is read on import and then
|
||||
saved as part of the internal database status. Later changes to the variable
|
||||
have no effect.
|
||||
|
||||
Here is an example configuration file:
|
||||
|
||||
``` yaml
|
||||
normalization:
|
||||
- ":: lower ()"
|
||||
- "ß > 'ss'" # German szet is unimbigiously equal to double ss
|
||||
transliteration:
|
||||
- !include /etc/nominatim/icu-rules/extended-unicode-to-asccii.yaml
|
||||
- ":: Ascii ()"
|
||||
variants:
|
||||
- language: de
|
||||
words:
|
||||
- ~haus => haus
|
||||
- ~strasse -> str
|
||||
- language: en
|
||||
words:
|
||||
- road -> rd
|
||||
- bridge -> bdge,br,brdg,bri,brg
|
||||
```
|
||||
|
||||
The configuration file contains three sections:
|
||||
`normalization`, `transliteration`, `variants`.
|
||||
|
||||
The normalization and transliteration sections each must contain a list of
|
||||
[ICU transformation rules](https://unicode-org.github.io/icu/userguide/transforms/general/rules.html).
|
||||
The rules are applied in the order in which they appear in the file.
|
||||
You can also include additional rules from external yaml file using the
|
||||
`!include` tag. The included file must contain a valid YAML list of ICU rules
|
||||
and may again include other files.
|
||||
|
||||
!!! warning
|
||||
The ICU rule syntax contains special characters that conflict with the
|
||||
YAML syntax. You should therefore always enclose the ICU rules in
|
||||
double-quotes.
|
||||
|
||||
The variants section defines lists of replacements which create alternative
|
||||
spellings of a name. To create the variants, a name is scanned from left to
|
||||
right and the longest matching replacement is applied until the end of the
|
||||
string is reached.
|
||||
|
||||
The variants section must contain a list of replacement groups. Each group
|
||||
defines a set of properties that describes where the replacements are
|
||||
applicable. In addition, the word section defines the list of replacements
|
||||
to be made. The basic replacement description is of the form:
|
||||
|
||||
```
|
||||
<source>[,<source>[...]] => <target>[,<target>[...]]
|
||||
```
|
||||
|
||||
The left side contains one or more `source` terms to be replaced. The right side
|
||||
lists one or more replacements. Each source is replaced with each replacement
|
||||
term.
|
||||
|
||||
!!! tip
|
||||
The source and target terms are internally normalized using the
|
||||
normalization rules given in the configuration. This ensures that the
|
||||
strings match as expected. In fact, it is better to use unnormalized
|
||||
words in the configuration because then it is possible to change the
|
||||
rules for normalization later without having to adapt the variant rules.
|
||||
|
||||
#### Decomposition
|
||||
|
||||
In its standard form, only full words match against the source. There
|
||||
is a special notation to match the prefix and suffix of a word:
|
||||
|
||||
``` yaml
|
||||
- ~strasse => str # matches "strasse" as full word and in suffix position
|
||||
- hinter~ => hntr # matches "hinter" as full word and in prefix position
|
||||
```
|
||||
|
||||
There is no facility to match a string in the middle of the word. The suffix
|
||||
and prefix notation automatically trigger the decomposition mode: two variants
|
||||
are created for each replacement, one with the replacement attached to the word
|
||||
and one separate. So in above example, the tokenization of "hauptstrasse" will
|
||||
create the variants "hauptstr" and "haupt str". Similarly, the name "rote strasse"
|
||||
triggers the variants "rote str" and "rotestr". By having decomposition work
|
||||
both ways, it is sufficient to create the variants at index time. The variant
|
||||
rules are not applied at query time.
|
||||
|
||||
To avoid automatic decomposition, use the '|' notation:
|
||||
|
||||
``` yaml
|
||||
- ~strasse |=> str
|
||||
```
|
||||
|
||||
simply changes "hauptstrasse" to "hauptstr" and "rote strasse" to "rote str".
|
||||
|
||||
#### Initial and final terms
|
||||
|
||||
It is also possible to restrict replacements to the beginning and end of a
|
||||
name:
|
||||
|
||||
``` yaml
|
||||
- ^south => s # matches only at the beginning of the name
|
||||
- road$ => rd # matches only at the end of the name
|
||||
```
|
||||
|
||||
So the first example would trigger a replacement for "south 45th street" but
|
||||
not for "the south beach restaurant".
|
||||
|
||||
#### Replacements vs. variants
|
||||
|
||||
The replacement syntax `source => target` works as a pure replacement. It changes
|
||||
the name instead of creating a variant. To create an additional version, you'd
|
||||
have to write `source => source,target`. As this is a frequent case, there is
|
||||
a shortcut notation for it:
|
||||
|
||||
```
|
||||
<source>[,<source>[...]] -> <target>[,<target>[...]]
|
||||
```
|
||||
|
||||
The simple arrow causes an additional variant to be added. Note that
|
||||
decomposition has an effect here on the source as well. So a rule
|
||||
|
||||
``` yaml
|
||||
- "~strasse -> str"
|
||||
```
|
||||
|
||||
means that for a word like `hauptstrasse` four variants are created:
|
||||
`hauptstrasse`, `haupt strasse`, `hauptstr` and `haupt str`.
|
||||
|
||||
### Reconfiguration
|
||||
|
||||
Changing the configuration after the import is currently not possible, although
|
||||
this feature may be added at a later time.
|
||||
@@ -10,18 +10,21 @@ For a list of other methods to add or update data see the output of
|
||||
If you have configured a flatnode file for the import, then you
|
||||
need to keep this flatnode file around for updates.
|
||||
|
||||
#### Installing the newest version of Pyosmium
|
||||
### Installing the newest version of Pyosmium
|
||||
|
||||
It is recommended to install Pyosmium via pip. Make sure to use python3.
|
||||
The replication process uses
|
||||
[Pyosmium](https://docs.osmcode.org/pyosmium/latest/updating_osm_data.html)
|
||||
to download update data from the server.
|
||||
It is recommended to install Pyosmium via pip.
|
||||
Run (as the same user who will later run the updates):
|
||||
|
||||
```sh
|
||||
pip3 install --user osmium
|
||||
```
|
||||
|
||||
#### Setting up the update process
|
||||
### Setting up the update process
|
||||
|
||||
Next the update needs to be initialised. By default Nominatim is configured
|
||||
Next the update process needs to be initialised. By default Nominatim is configured
|
||||
to update using the global minutely diffs.
|
||||
|
||||
If you want a different update source you will need to add some settings
|
||||
@@ -45,12 +48,176 @@ what you expect.
|
||||
The `replication --init` command needs to be rerun whenever the replication
|
||||
service is changed.
|
||||
|
||||
#### Updating Nominatim
|
||||
### Updating Nominatim
|
||||
|
||||
The following command will keep your database constantly up to date:
|
||||
Nominatim supports different modes how to retrieve the update data from the
|
||||
server. Which one you want to use depends on your exact setup and how often you
|
||||
want to retrieve updates.
|
||||
|
||||
These instructions are for using a single source of updates. If you have
|
||||
imported multiple country extracts and want to keep them
|
||||
up-to-date, [Advanced installations section](Advanced-Installations.md)
|
||||
contains instructions to set up and update multiple country extracts.
|
||||
|
||||
#### Continuous updates
|
||||
|
||||
This is the easiest mode. Simply run the replication command without any
|
||||
parameters:
|
||||
|
||||
nominatim replication
|
||||
|
||||
If you have imported multiple country extracts and want to keep them
|
||||
up-to-date, [Advanced installations section](Advanced-Installations.md) contains instructions
|
||||
to set up and update multiple country extracts.
|
||||
The update application keeps running forever and retrieves and applies
|
||||
new updates from the server as they are published.
|
||||
|
||||
You can run this command as a simple systemd service. Create a service
|
||||
description like that in `/etc/systemd/system/nominatim-updates.service`:
|
||||
|
||||
```
|
||||
[Unit]
|
||||
Description=Continuous updates of Nominatim
|
||||
|
||||
[Service]
|
||||
WorkingDirectory=/srv/nominatim
|
||||
ExecStart=nominatim replication
|
||||
StandardOutput=append:/var/log/nominatim-updates.log
|
||||
StandardError=append:/var/log/nominatim-updates.error.log
|
||||
User=nominatim
|
||||
Group=nominatim
|
||||
Type=simple
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
```
|
||||
|
||||
Replace the `WorkingDirectory` with your project directory. Also adapt user
|
||||
and group names as required.
|
||||
|
||||
Now activate the service and start the updates:
|
||||
|
||||
```
|
||||
sudo systemctl daemon-reload
|
||||
sudo systemctl enable nominatim-updates
|
||||
sudo systemctl start nominatim-updates
|
||||
```
|
||||
|
||||
#### One-time mode
|
||||
|
||||
When the `--once` parameter is given, then Nominatim will download exactly one
|
||||
batch of updates and then exit. This one-time mode still respects the
|
||||
`NOMINATIM_REPLICATION_UPDATE_INTERVAL` that you have set. If according to
|
||||
the update interval no new data has been published yet, it will go to sleep
|
||||
until the next expected update and only then attempt to download the next batch.
|
||||
|
||||
The one-time mode is particularly useful if you want to run updates continuously
|
||||
but need to schedule other work in between updates. For example, the main
|
||||
service at osm.org uses it, to regularly recompute postcodes -- a process that
|
||||
must not be run while updates are in progress. Its update script
|
||||
looks like this:
|
||||
|
||||
```sh
|
||||
#!/bin/bash
|
||||
|
||||
# Switch to your project directory.
|
||||
cd /srv/nominatim
|
||||
|
||||
while true; do
|
||||
nominatim replication --once
|
||||
if [ -f "/srv/nominatim/schedule-maintenance" ]; then
|
||||
rm /srv/nominatim/schedule-maintenance
|
||||
nominatim refresh --postcodes
|
||||
fi
|
||||
done
|
||||
```
|
||||
|
||||
A cron job then creates the file `/srv/nominatim/schedule-maintenance` once per night.
|
||||
|
||||
##### One-time mode with systemd
|
||||
|
||||
You can run the one-time mode with a systemd timer & service.
|
||||
|
||||
Create a timer description like `/etc/systemd/system/nominatim-updates.timer`:
|
||||
|
||||
```
|
||||
[Unit]
|
||||
Description=Timer to start updates of Nominatim
|
||||
|
||||
[Timer]
|
||||
OnActiveSec=2
|
||||
OnUnitActiveSec=1min
|
||||
Unit=nominatim-updates.service
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
```
|
||||
|
||||
And then a similar service definition: `/etc/systemd/system/nominatim-updates.service`:
|
||||
|
||||
```
|
||||
[Unit]
|
||||
Description=Single updates of Nominatim
|
||||
|
||||
[Service]
|
||||
WorkingDirectory=/srv/nominatim
|
||||
ExecStart=nominatim replication --once
|
||||
StandardOutput=append:/var/log/nominatim-updates.log
|
||||
StandardError=append:/var/log/nominatim-updates.error.log
|
||||
User=nominatim
|
||||
Group=nominatim
|
||||
Type=simple
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
```
|
||||
|
||||
Replace the `WorkingDirectory` with your project directory. Also adapt user and
|
||||
group names as required. `OnUnitActiveSec` defines how often the individual
|
||||
update command is run.
|
||||
|
||||
Now activate the service and start the updates:
|
||||
|
||||
```
|
||||
sudo systemctl daemon-reload
|
||||
sudo systemctl enable nominatim-updates.timer
|
||||
sudo systemctl start nominatim-updates.timer
|
||||
```
|
||||
|
||||
You can stop future data updates, while allowing any current, in-progress
|
||||
update steps to finish, by running `sudo systemctl stop
|
||||
nominatim-updates.timer` and waiting until `nominatim-updates.service` isn't
|
||||
running (`sudo systemctl is-active nominatim-updates.service`). Current output
|
||||
from the update can be seen like above (`systemctl status
|
||||
nominatim-updates.service`).
|
||||
|
||||
|
||||
#### Catch-up mode
|
||||
|
||||
With the `--catch-up` parameter, Nominatim will immediately try to download
|
||||
all changes from the server until the database is up-to-date. The catch-up mode
|
||||
still respects the parameter `NOMINATIM_REPLICATION_MAX_DIFF`. It downloads and
|
||||
applies the changes in appropriate batches until all is done.
|
||||
|
||||
The catch-up mode is foremost useful to bring the database up to speed after the
|
||||
initial import. Give that the service usually is not in production at this
|
||||
point, you can temporarily be a bit more generous with the batch size and
|
||||
number of threads you use for the updates by running catch-up like this:
|
||||
|
||||
```
|
||||
cd /srv/nominatim
|
||||
NOMINATIM_REPLICATION_MAX_DIFF=5000 nominatim replication --catch-up --threads 15
|
||||
```
|
||||
|
||||
The catch-up mode is also useful when you want to apply updates at a lower
|
||||
frequency than what the source publishes. You can set up a cron job to run
|
||||
replication catch-up at whatever interval you desire.
|
||||
|
||||
!!! hint
|
||||
When running scheduled updates with catch-up, it is a good idea to choose
|
||||
a replication source with an update frequency that is an order of magnitude
|
||||
lower. For example, if you want to update once a day, use an hourly updated
|
||||
source. This makes sure that you don't miss an entire day of updates when
|
||||
the source is unexpectedly late to publish its update.
|
||||
|
||||
If you want to use the source with the same update frequency (e.g. a daily
|
||||
updated source with daily updates), use the
|
||||
continuous update mode. It ensures to re-request the newest update until it
|
||||
is published.
|
||||
|
||||
@@ -35,7 +35,7 @@ it contains the county/state/country across the border.
|
||||
#### 3. I get different counties/states/countries when I change the zoom parameter in the reverse query. How is that possible?
|
||||
|
||||
This is basically the same problem as in the previous answer.
|
||||
The zoom level influences at which [search rank](https://wiki.openstreetmap.org/wiki/Nominatim/Development_overview#Country_to_street_level) Nominatim starts looking
|
||||
The zoom level influences at which [search rank](../customize/Ranking.md#search-rank) Nominatim starts looking
|
||||
for the closest object. So the closest house number maybe on one side of the
|
||||
border while the closest street is on the other. As the address details contain
|
||||
the address of the closest object found, you might sometimes get one result,
|
||||
@@ -59,3 +59,27 @@ suited for these kinds of queries.
|
||||
|
||||
That said if you installed your own Nominatim instance you can use the
|
||||
`nominatim export` PHP script as basis to return such lists.
|
||||
|
||||
#### 7. My result has a wrong postcode. Where does it come from?
|
||||
|
||||
Most places in OSM don't have a postcode, so Nominatim tries to interpolate
|
||||
one. It first look at all the places that make up the address of the place.
|
||||
If one of them has a postcode defined, this is the one to be used. When
|
||||
none of the address parts has a postcode either, Nominatim interpolates one
|
||||
from the surrounding objects. If the postcode is for your result is one, then
|
||||
most of the time there is an OSM object with the wrong postcode nearby.
|
||||
|
||||
To find the bad postcode, go to
|
||||
[https://nominatim.openstreetmap.org](https://nominatim.openstreetmap.org)
|
||||
and search for your place. When you have found it, click on the 'details' link
|
||||
under the result to go to the details page. There is a field 'Computed Postcode'
|
||||
which should display the bad postcode. Click on the 'how?' link. A small
|
||||
explanation text appears. It contains a link to a query for Overpass Turbo.
|
||||
Click on that and you get a map with all places in the area that have the bad
|
||||
postcode. If none is displayed, zoom the map out a bit and then click on 'Run'.
|
||||
|
||||
Now go to [OpenStreetMap](https://openstreetmap.org) and fix the error you
|
||||
have just found. It will take at least a day for Nominatim to catch up with
|
||||
your data fix. Sometimes longer, depending on how much editing activity is in
|
||||
the area.
|
||||
|
||||
|
||||
@@ -90,11 +90,11 @@ This overrides the specified machine readable format. (Default: 0)
|
||||
|
||||
##### XML
|
||||
|
||||
[https://nominatim.openstreetmap.org/lookup?osm_ids=R146656,W104393803,N240109189](https://nominatim.openstreetmap.org/lookup?osm_ids=R146656,W104393803,N240109189)
|
||||
[https://nominatim.openstreetmap.org/lookup?osm_ids=R146656,W104393803,N240109189](https://nominatim.openstreetmap.org/lookup?osm_ids=R146656,W50637691,N240109189)
|
||||
|
||||
```xml
|
||||
<lookupresults timestamp="Mon, 29 Jun 15 18:01:33 +0000" attribution="Data © OpenStreetMap contributors, ODbL 1.0. https://www.openstreetmap.org/copyright" querystring="R146656,W104393803,N240109189" polygon="false">
|
||||
<place place_id="127761056" osm_type="relation" osm_id="146656" place_rank="16" lat="53.4791466" lon="-2.2447445" display_name="Manchester, Greater Manchester, North West England, England, United Kingdom" class="boundary" type="administrative" importance="0.704893333438333">
|
||||
<lookupresults timestamp="Mon, 28 Mar 22 14:38:54 +0000" attribution="Data © OpenStreetMap contributors, ODbL 1.0. http://www.openstreetmap.org/copyright" querystring="R146656,W50637691,N240109189" more_url="">
|
||||
<place place_id="282236157" osm_type="relation" osm_id="146656" place_rank="16" address_rank="16" boundingbox="53.3401044,53.5445923,-2.3199185,-2.1468288" lat="53.44246175" lon="-2.2324547359718547" display_name="Manchester, Greater Manchester, North West England, England, United Kingdom" class="boundary" type="administrative" importance="0.35">
|
||||
<city>Manchester</city>
|
||||
<county>Greater Manchester</county>
|
||||
<state_district>North West England</state_district>
|
||||
@@ -102,21 +102,20 @@ This overrides the specified machine readable format. (Default: 0)
|
||||
<country>United Kingdom</country>
|
||||
<country_code>gb</country_code>
|
||||
</place>
|
||||
<place place_id="77769745" osm_type="way" osm_id="104393803" place_rank="30" lat="52.5162024" lon="13.3777343363579" display_name="Brandenburg Gate, 1, Pariser Platz, Mitte, Berlin, 10117, Germany" class="tourism" type="attraction" importance="0.443472858361592">
|
||||
<attraction>Brandenburg Gate</attraction>
|
||||
<house_number>1</house_number>
|
||||
<pedestrian>Pariser Platz</pedestrian>
|
||||
<suburb>Mitte</suburb>
|
||||
<city_district>Mitte</city_district>
|
||||
<city>Berlin</city>
|
||||
<state>Berlin</state>
|
||||
<postcode>10117</postcode>
|
||||
<place place_id="115462561" osm_type="way" osm_id="50637691" place_rank="30" address_rank="30" boundingbox="52.3994612,52.3996426,13.0479574,13.0481754" lat="52.399550700000006" lon="13.048066846939687" display_name="Brandenburger Tor, Brandenburger Straße, Historische Innenstadt, Innenstadt, Potsdam, Brandenburg, 14467, Germany" class="tourism" type="attraction" importance="0.29402874005524">
|
||||
<tourism>Brandenburger Tor</tourism>
|
||||
<road>Brandenburger Straße</road>
|
||||
<suburb>Historische Innenstadt</suburb>
|
||||
<city>Potsdam</city>
|
||||
<state>Brandenburg</state>
|
||||
<postcode>14467</postcode>
|
||||
<country>Germany</country>
|
||||
<country_code>de</country_code>
|
||||
</place>
|
||||
<place place_id="2570600569" osm_type="node" osm_id="240109189" place_rank="15" lat="52.5170365" lon="13.3888599" display_name="Berlin, Germany" class="place" type="city" importance="0.822149797630868">
|
||||
<place place_id="567505" osm_type="node" osm_id="240109189" place_rank="15" address_rank="16" boundingbox="52.3586925,52.6786925,13.2396024,13.5596024" lat="52.5186925" lon="13.3996024" display_name="Berlin, 10178, Germany" class="place" type="city" importance="0.78753902824914">
|
||||
<city>Berlin</city>
|
||||
<state>Berlin</state>
|
||||
<postcode>10178</postcode>
|
||||
<country>Germany</country>
|
||||
<country_code>de</country_code>
|
||||
</place>
|
||||
@@ -125,38 +124,50 @@ This overrides the specified machine readable format. (Default: 0)
|
||||
|
||||
##### JSON with extratags
|
||||
|
||||
[https://nominatim.openstreetmap.org/lookup?osm_ids=W50637691&format=json](https://nominatim.openstreetmap.org/lookup?osm_ids=W50637691&format=json)
|
||||
[https://nominatim.openstreetmap.org/lookup?osm_ids=W50637691&format=json&extratags=1](https://nominatim.openstreetmap.org/lookup?osm_ids=W50637691&format=json&extratags=1)
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"place_id": "84271358",
|
||||
"licence": "Data © OpenStreetMap contributors, ODbL 1.0. https://osm.org/copyright",
|
||||
"osm_type": "way",
|
||||
"osm_id": "50637691",
|
||||
"lat": "52.39955055",
|
||||
"lon": "13.04806574678",
|
||||
"display_name": "Brandenburger Tor, Brandenburger Straße, Nördliche Innenstadt, Innenstadt, Potsdam, Brandenburg, 14467, Germany",
|
||||
"class": "historic",
|
||||
"type": "city_gate",
|
||||
"importance": "0.221233780277011",
|
||||
"address": {
|
||||
"address29": "Brandenburger Tor",
|
||||
"pedestrian": "Brandenburger Straße",
|
||||
"suburb": "Nördliche Innenstadt",
|
||||
"city": "Potsdam",
|
||||
"state": "Brandenburg",
|
||||
"postcode": "14467",
|
||||
"country": "Germany",
|
||||
"country_code": "de"
|
||||
},
|
||||
"extratags": {
|
||||
"image": "http://commons.wikimedia.org/wiki/File:Potsdam_brandenburger_tor.jpg",
|
||||
"wikidata": "Q695045",
|
||||
"wikipedia": "de:Brandenburger Tor (Potsdam)",
|
||||
"wheelchair": "yes",
|
||||
"description": "Kleines Brandenburger Tor in Potsdam"
|
||||
}
|
||||
}
|
||||
{
|
||||
"place_id": 115462561,
|
||||
"licence": "Data © OpenStreetMap contributors, ODbL 1.0. https://osm.org/copyright",
|
||||
"osm_type": "way",
|
||||
"osm_id": 50637691,
|
||||
"boundingbox": [
|
||||
"52.3994612",
|
||||
"52.3996426",
|
||||
"13.0479574",
|
||||
"13.0481754"
|
||||
],
|
||||
"lat": "52.399550700000006",
|
||||
"lon": "13.048066846939687",
|
||||
"display_name": "Brandenburger Tor, Brandenburger Straße, Historische Innenstadt, Innenstadt, Potsdam, Brandenburg, 14467, Germany",
|
||||
"class": "tourism",
|
||||
"type": "attraction",
|
||||
"importance": 0.2940287400552381,
|
||||
"address": {
|
||||
"tourism": "Brandenburger Tor",
|
||||
"road": "Brandenburger Straße",
|
||||
"suburb": "Historische Innenstadt",
|
||||
"city": "Potsdam",
|
||||
"state": "Brandenburg",
|
||||
"postcode": "14467",
|
||||
"country": "Germany",
|
||||
"country_code": "de"
|
||||
},
|
||||
"extratags": {
|
||||
"image": "http://commons.wikimedia.org/wiki/File:Potsdam_brandenburger_tor.jpg",
|
||||
"heritage": "4",
|
||||
"wikidata": "Q695045",
|
||||
"architect": "Carl von Gontard;Georg Christian Unger",
|
||||
"wikipedia": "de:Brandenburger Tor (Potsdam)",
|
||||
"wheelchair": "yes",
|
||||
"description": "Kleines Brandenburger Tor in Potsdam",
|
||||
"heritage:website": "http://www.bldam-brandenburg.de/images/stories/PDF/DML%202012/04-p-internet-13.pdf",
|
||||
"heritage:operator": "bldam",
|
||||
"architect:wikidata": "Q68768;Q95223",
|
||||
"year_of_construction": "1771"
|
||||
}
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
@@ -28,6 +28,7 @@ a single place (for reverse) of the following format:
|
||||
"city": "London",
|
||||
"state_district": "Greater London",
|
||||
"state": "England",
|
||||
"ISO3166-2-lvl4": "GB-ENG",
|
||||
"postcode": "SW1A 2DU",
|
||||
"country": "United Kingdom",
|
||||
"country_code": "gb"
|
||||
@@ -97,7 +98,10 @@ The GeocodeJSON format follows the
|
||||
The following feature attributes are implemented:
|
||||
|
||||
* `osm_type`, `osm_id` - reference to the OSM object (unofficial extension, [see notes](#osm-reference))
|
||||
* `type` - value of the main tag of the object (e.g. residential, restaurant, ...)
|
||||
* `type` - the 'address level' of the object ('house', 'street', `district`, `city`,
|
||||
`county`, `state`, `country`, `locality`)
|
||||
* `osm_key`- key of the main tag of the OSM object (e.g. boundary, highway, amenity)
|
||||
* `osm_value` - value of the main tag of the OSM object (e.g. residential, restaurant)
|
||||
* `label` - full comma-separated address
|
||||
* `name` - localised name of the place
|
||||
* `housenumber`, `street`, `locality`, `district`, `postcode`, `city`,
|
||||
@@ -126,6 +130,7 @@ formats depending on the API call.
|
||||
</result>
|
||||
<addressparts>
|
||||
<state>Bavaria</state>
|
||||
<ISO3166-2-lvl4>DE-BY</ISO3166-2-lvl4>
|
||||
<country>Germany</country>
|
||||
<country_code>de</country_code>
|
||||
</addressparts>
|
||||
@@ -179,6 +184,7 @@ Additional information requested with `addressdetails=1`, `extratags=1` and
|
||||
<city>London</city>
|
||||
<state_district>Greater London</state_district>
|
||||
<state>England</state>
|
||||
<ISO3166-2-lvl4>GB-ENG</ISO3166-2-lvl4>
|
||||
<postcode>SW1A 2DU</postcode>
|
||||
<country>United Kingdom</country>
|
||||
<country_code>gb</country_code>
|
||||
@@ -205,8 +211,8 @@ be more than one. The attributes of that element contain:
|
||||
* `ref` - content of `ref` tag if it exists
|
||||
* `lat`, `lon` - latitude and longitude of the centroid of the object
|
||||
* `boundingbox` - comma-separated list of corner coordinates ([see notes](#boundingbox))
|
||||
* `place_rank` - class [search rank](../develop/Ranking#search-rank)
|
||||
* `address_rank` - place [address rank](../develop/Ranking#address-rank)
|
||||
* `place_rank` - class [search rank](../customize/Ranking.md#search-rank)
|
||||
* `address_rank` - place [address rank](../customize/Ranking.md#address-rank)
|
||||
* `display_name` - full comma-separated address
|
||||
* `class`, `type` - key and value of the main OSM tag
|
||||
* `importance` - computed importance rank
|
||||
@@ -230,7 +236,7 @@ on another server. It may even change its ID on the same server when it is
|
||||
removed and reimported while updating the database with fresh OSM data.
|
||||
It is thus not useful to treat it as permanent for later use.
|
||||
|
||||
The combination `osm_type`+`osm_id` is slighly better but remember in
|
||||
The combination `osm_type`+`osm_id` is slightly better but remember in
|
||||
OpenStreetMap mappers can delete, split, recreate places (and those
|
||||
get a new `osm_id`), there is no link between those old and new ids.
|
||||
Places can also change their meaning without changing their `osm_id`,
|
||||
@@ -279,17 +285,18 @@ with a designation label. Per default the following labels may appear:
|
||||
|
||||
* continent
|
||||
* country, country_code
|
||||
* region, state, state_district, county
|
||||
* region, state, state_district, county, ISO3166-2-lvl<admin_level>
|
||||
* municipality, city, town, village
|
||||
* city_district, district, borough, suburb, subdivision
|
||||
* hamlet, croft, isolated_dwelling
|
||||
* neighbourhood, allotments, quarter
|
||||
* city_block, residental, farm, farmyard, industrial, commercial, retail
|
||||
* city_block, residential, farm, farmyard, industrial, commercial, retail
|
||||
* road
|
||||
* house_number, house_name
|
||||
* emergency, historic, military, natural, landuse, place, railway,
|
||||
man_made, aerialway, boundary, amenity, aeroway, club, craft, leisure,
|
||||
office, mountain_pass, shop, tourism, bridge, tunnel, waterway
|
||||
* postcode
|
||||
|
||||
They roughly correspond to the classification of the OpenStreetMap data
|
||||
according to either the `place` tag or the main key of the object.
|
||||
|
||||
@@ -27,15 +27,15 @@ The main format of the reverse API is
|
||||
https://nominatim.openstreetmap.org/reverse?lat=<value>&lon=<value>&<params>
|
||||
```
|
||||
|
||||
where `lat` and `lon` are latitude and longitutde of a coordinate in WGS84
|
||||
where `lat` and `lon` are latitude and longitude of a coordinate in WGS84
|
||||
projection. The API returns exactly one result or an error when the coordinate
|
||||
is in an area with no OSM data coverage.
|
||||
|
||||
Additional paramters are accepted as listed below.
|
||||
Additional parameters are accepted as listed below.
|
||||
|
||||
!!! warning "Deprecation warning"
|
||||
The reverse API used to allow address lookup for a single OSM object by
|
||||
its OSM id. This use is now deprecated. Use the [Address Lookup API](../Lookup)
|
||||
its OSM id. This use is now deprecated. Use the [Address Lookup API](Lookup.md)
|
||||
instead.
|
||||
|
||||
### Output format
|
||||
@@ -118,7 +118,7 @@ geometry. Topology is preserved in the result. (Default: 0.0)
|
||||
|
||||
* `email=<valid email address>`
|
||||
|
||||
If you are making large numbers of request please include an appropriate email
|
||||
If you are making a large number of requests, please include an appropriate email
|
||||
address to identify your requests. See Nominatim's [Usage Policy](https://operations.osmfoundation.org/policies/nominatim/) for more details.
|
||||
|
||||
|
||||
|
||||
@@ -27,8 +27,8 @@ The search term may be specified with two different sets of parameters:
|
||||
|
||||
Free-form query string to search for.
|
||||
Free-form queries are processed first left-to-right and then right-to-left if that fails. So you may search for
|
||||
[pilkington avenue, birmingham](//nominatim.openstreetmap.org/search?q=pilkington+avenue,birmingham) as well as for
|
||||
[birmingham, pilkington avenue](//nominatim.openstreetmap.org/search?q=birmingham,+pilkington+avenue).
|
||||
[pilkington avenue, birmingham](https://nominatim.openstreetmap.org/search?q=pilkington+avenue,birmingham) as well as for
|
||||
[birmingham, pilkington avenue](https://nominatim.openstreetmap.org/search?q=birmingham,+pilkington+avenue).
|
||||
Commas are optional, but improve performance by reducing the complexity of the search.
|
||||
|
||||
|
||||
@@ -51,6 +51,12 @@ Both query forms accept the additional parameters listed below.
|
||||
|
||||
See [Place Output Formats](Output.md) for details on each format. (Default: jsonv2)
|
||||
|
||||
!!! note
|
||||
The Nominatim service at
|
||||
[https://nominatim.openstreetmap.org](https://nominatim.openstreetmap.org)
|
||||
has a different default behaviour for historical reasons. When the
|
||||
`format` parameter is omitted, the request will be forwarded to the Web UI.
|
||||
|
||||
* `json_callback=<string>`
|
||||
|
||||
Wrap JSON output in a callback function ([JSONP](https://en.wikipedia.org/wiki/JSONP)) i.e. `<string>(<json>)`.
|
||||
|
||||
@@ -57,10 +57,11 @@ code and message, e.g.
|
||||
|
||||
Possible status codes are
|
||||
|
||||
| | message | notes |
|
||||
|-----|----------------------|---------------------------------------------------|
|
||||
| 700 | "No database" | connection failed |
|
||||
| 701 | "Module failed" | database could not load nominatim.so |
|
||||
| 702 | "Module call failed" | nominatim.so loaded but calling a function failed |
|
||||
| 703 | "Query failed" | test query against a database table failed |
|
||||
| 704 | "No value" | test query worked but returned no results |
|
||||
| | message | notes |
|
||||
| --- | ------------------------------ | ----------------------------------------------------------------- |
|
||||
| 700 | "No database" | connection failed |
|
||||
| 701 | "Module failed" | database could not load nominatim.so |
|
||||
| 702 | "Module call failed" | nominatim.so loaded but calling a function failed |
|
||||
| 703 | "Query failed" | test query against a database table failed |
|
||||
| 704 | "No value" | test query worked but returned no results |
|
||||
| 705 | "Import date is not available" | No import dates were returned (enabling replication can fix this) |
|
||||
|
||||
149
docs/customize/Country-Settings.md
Normal file
149
docs/customize/Country-Settings.md
Normal file
@@ -0,0 +1,149 @@
|
||||
# Customizing Per-Country Data
|
||||
|
||||
Whenever an OSM is imported into Nominatim, the object is first assigned
|
||||
a country. Nominatim can use this information to adapt various aspects of
|
||||
the address computation to the local customs of the country. This section
|
||||
explains how country assignment works and the principal per-country
|
||||
localizations.
|
||||
|
||||
## Country assignment
|
||||
|
||||
Countries are assigned on the basis of country data from the OpenStreetMap
|
||||
input data itself. Countries are expected to be tagged according to the
|
||||
[administrative boundary schema](https://wiki.openstreetmap.org/wiki/Tag:boundary%3Dadministrative):
|
||||
a OSM relation with `boundary=administrative` and `admin_level=2`. Nominatim
|
||||
uses the country code to distinguish the countries.
|
||||
|
||||
If there is no country data available for a point, then Nominatim uses the
|
||||
fallback data imported from `data/country_osm_grid.sql.gz`. This was computed
|
||||
from OSM data as well but is guaranteed to cover all countries.
|
||||
|
||||
Some OSM objects may also be located outside any country, for example a buoy
|
||||
in the middle of the ocean. These object do not get any country assigned and
|
||||
get a default treatment when it comes to localized handling of data.
|
||||
|
||||
## Per-country settings
|
||||
|
||||
### Global country settings
|
||||
|
||||
The main place to configure settings per country is the file
|
||||
`settings/country_settings.yaml`. This file has one section per country that
|
||||
is recognised by Nominatim. Each section is tagged with the country code
|
||||
(in lower case) and contains the different localization information. Only
|
||||
countries which are listed in this file are taken into account for computations.
|
||||
|
||||
For example, the section for Andorra looks like this:
|
||||
|
||||
```
|
||||
partition: 35
|
||||
languages: ca
|
||||
names: !include country-names/ad.yaml
|
||||
postcode:
|
||||
pattern: "(ddd)"
|
||||
output: AD\1
|
||||
```
|
||||
|
||||
The individual settings are described below.
|
||||
|
||||
#### `partition`
|
||||
|
||||
Nominatim internally splits the data into multiple tables to improve
|
||||
performance. The partition number tells Nominatim into which table to put
|
||||
the country. This is purely internal management and has no effect on the
|
||||
output data.
|
||||
|
||||
The default is to have one partition per country.
|
||||
|
||||
#### `languages`
|
||||
|
||||
A comma-separated list of ISO-639 language codes of default languages in the
|
||||
country. These are the languages used in name tags without a language suffix.
|
||||
Note that this is not necessarily the same as the list of official languages
|
||||
in the country. There may be officially recognised languages in a country
|
||||
which are only ever used in name tags with the appropriate language suffixes.
|
||||
Conversely, a non-official language may appear a lot in the name tags, for
|
||||
example when used as an unofficial Lingua Franca.
|
||||
|
||||
List the languages in order of frequency of appearance with the most frequently
|
||||
used language first. It is not recommended to add languages when there are only
|
||||
very few occurrences.
|
||||
|
||||
If only one language is listed, then Nominatim will 'auto-complete' the
|
||||
language of names without an explicit language-suffix.
|
||||
|
||||
#### `names`
|
||||
|
||||
List of names of the country and its translations. These names are used as
|
||||
a baseline. It is always possible to search countries by the given names, no
|
||||
matter what other names are in the OSM data. They are also used as a fallback
|
||||
when a needed translation is not available.
|
||||
|
||||
!!! Note
|
||||
The list of names per country is currently fairly large because Nominatim
|
||||
supports translations in many languages per default. That is why the
|
||||
name lists have been separated out into extra files. You can find the
|
||||
name lists in the file `settings/country-names/<country code>.yaml`.
|
||||
The names section in the main country settings file only refers to these
|
||||
files via the special `!include` directive.
|
||||
|
||||
#### `postcode`
|
||||
|
||||
Describes the format of the postcode that is in use in the country.
|
||||
|
||||
When a country has no official postcodes, set this to no. Example:
|
||||
|
||||
```
|
||||
ae:
|
||||
postcode: no
|
||||
```
|
||||
|
||||
When a country has a postcode, you need to state the postcode pattern and
|
||||
the default output format. Example:
|
||||
|
||||
```
|
||||
bm:
|
||||
postcode:
|
||||
pattern: "(ll)[ -]?(dd)"
|
||||
output: \1 \2
|
||||
```
|
||||
|
||||
The **pattern** is a regular expression that describes the possible formats
|
||||
accepted as a postcode. The pattern follows the standard syntax for
|
||||
[regular expressions in Python](https://docs.python.org/3/library/re.html#regular-expression-syntax)
|
||||
with two extra shortcuts: `d` is a shortcut for a single digit([0-9])
|
||||
and `l` for a single ASCII letter ([A-Z]).
|
||||
|
||||
Use match groups to indicate groups in the postcode that may optionally be
|
||||
separated with a space or a hyphen.
|
||||
|
||||
For example, the postcode for Bermuda above always consists of two letters
|
||||
and two digits. They may optionally be separated by a space or hyphen. That
|
||||
means that Nominatim will consider `AB56`, `AB 56` and `AB-56` spelling variants
|
||||
for one and the same postcode.
|
||||
|
||||
Never add the country code in front of the postcode pattern. Nominatim will
|
||||
automatically accept variants with a country code prefix for all postcodes.
|
||||
|
||||
The **output** field is an optional field that describes what the canonical
|
||||
spelling of the postcode should be. The format is the
|
||||
[regular expression expand syntax](https://docs.python.org/3/library/re.html#re.Match.expand) referring back to the bracket groups in the pattern.
|
||||
|
||||
Most simple postcodes only have one spelling variant. In that case, the
|
||||
**output** can be omitted. The postcode will simply be used as is.
|
||||
|
||||
In the Bermuda example above, the canonical spelling would be to have a space
|
||||
between letters and digits.
|
||||
|
||||
!!! Warning
|
||||
When your postcode pattern covers multiple variants of the postcode, then
|
||||
you must explicitly state the canonical output or Nominatim will not
|
||||
handle the variations correctly.
|
||||
|
||||
### Other country-specific configuration
|
||||
|
||||
There are some other configuration files where you can set localized settings
|
||||
according to the assigned country. These are:
|
||||
|
||||
* [Place ranking configuration](Ranking.md)
|
||||
|
||||
Please see the linked documentation sections for more information.
|
||||
@@ -1,38 +1,24 @@
|
||||
# OSM Data Import
|
||||
|
||||
OSM data is initially imported using [osm2pgsql](https://osm2pgsql.org).
|
||||
Nominatim uses its own data output style 'gazetteer', which differs from the
|
||||
output style created for map rendering.
|
||||
|
||||
## Database Layout
|
||||
|
||||
The gazetteer style produces a single table `place` with the following rows:
|
||||
|
||||
* `osm_type` - kind of OSM object (**N** - node, **W** - way, **R** - relation)
|
||||
* `osm_id` - original OSM ID
|
||||
* `class` - key of principal tag defining the object type
|
||||
* `type` - value of principal tag defining the object type
|
||||
* `name` - collection of tags that contain a name or reference
|
||||
* `admin_level` - numerical value of the tagged administrative level
|
||||
* `address` - collection of tags defining the address of an object
|
||||
* `extratags` - collection of additional interesting tags that are not
|
||||
directly relevant for searching
|
||||
* `geometry` - geometry of the object (in WGS84)
|
||||
|
||||
A single OSM object may appear multiple times in this table when it is tagged
|
||||
with multiple tags that may constitute a principal tag. Take for example a
|
||||
motorway bridge. In OSM, this would be a way which is tagged with
|
||||
`highway=motorway` and `bridge=yes`. This way would appear in the `place` table
|
||||
once with `class` of `highway` and once with a `class` of `bridge`. Thus the
|
||||
*unique key* for `place` is (`osm_type`, `osm_id`, `class`).
|
||||
|
||||
## Configuring the Import
|
||||
|
||||
How tags are interpreted and assigned to the different `place` columns can be
|
||||
configured via the import style configuration file (`NOMINATIM_IMPORT_STYLE`). This
|
||||
Which OSM objects are added to the database and which of the tags are used
|
||||
can be configured via the import style configuration file. This
|
||||
is a JSON file which contains a list of rules which are matched against every
|
||||
tag of every object and then assign the tag its specific role.
|
||||
|
||||
The style to use is given by the `NOMINATIM_IMPORT_STYLE` configuration
|
||||
option. There are a number of default styles, which are explained in detail
|
||||
in the [Import section](../admin/Import.md#filtering-imported-data). These
|
||||
standard styles may be referenced by their name.
|
||||
|
||||
You can also create your own custom style. Put the style file into your
|
||||
project directory and then set `NOMINATIM_IMPORT_STYLE` to the name of the file.
|
||||
It is always recommended to start with one of the standard styles and customize
|
||||
those. You find the standard styles under the name `import-<stylename>.style`
|
||||
in the standard Nominatim configuration path (usually `/etc/nominatim` or
|
||||
`/usr/local/etc/nominatim`).
|
||||
|
||||
The remainder of the page describes the format of the file.
|
||||
|
||||
### Configuration Rules
|
||||
|
||||
A single rule looks like this:
|
||||
@@ -159,9 +145,6 @@ A rule can define as many of these properties for one match as it likes. For
|
||||
example, if the property is `"main,extra"` then the tag will open a new row
|
||||
but also have the tag appear in the list of extra tags.
|
||||
|
||||
There are a number of pre-defined styles in the `settings/` directory. It is
|
||||
advisable to start from one of these styles when defining your own.
|
||||
|
||||
### Changing the Style of Existing Databases
|
||||
|
||||
There is normally no issue changing the style of a database that is already
|
||||
49
docs/customize/Importance.md
Normal file
49
docs/customize/Importance.md
Normal file
@@ -0,0 +1,49 @@
|
||||
## Importance
|
||||
|
||||
Search requests can yield multiple results which match equally well with
|
||||
the original query. In such case Nominatim needs to order the results
|
||||
according to a different criterion: importance. This is a measure for how
|
||||
likely it is that a user will search for a given place. This section explains
|
||||
the sources Nominatim uses for computing importance of a place and how to
|
||||
customize them.
|
||||
|
||||
### How importance is computed
|
||||
|
||||
The main value for importance is derived from page ranking values for Wikipedia
|
||||
pages for a place. For places that do not have their own
|
||||
Wikipedia page, a formula is used that derives a static importance from the
|
||||
places [search rank](../customize/Ranking.md#search-rank).
|
||||
|
||||
In a second step, a secondary importance value is added which is meant to
|
||||
represent how well-known the general area is where the place is located. It
|
||||
functions as a tie-breaker between places with very similar primary
|
||||
importance values.
|
||||
|
||||
nominatim.org has preprocessed importance tables for the
|
||||
[primary Wikipedia rankings](https://nominatim.org/data/wikimedia-importance.sql.gz)
|
||||
and for a secondary importance based on the number of tile views on openstreetmap.org.
|
||||
|
||||
### Customizing secondary importance
|
||||
|
||||
The secondary importance is implemented as a simple
|
||||
[Postgis raster](https://postgis.net/docs/raster.html) table, where Nominatim
|
||||
looks up the value for the coordinates of the centroid of a place. You can
|
||||
provide your own secondary importance raster in form of an SQL file named
|
||||
`secondary_importance.sql.gz` in your project directory.
|
||||
|
||||
The SQL file needs to drop and (re)create a table `secondary_importance` which
|
||||
must as a minimum contain a column `rast` of type `raster`. The raster must
|
||||
be in EPSG:4326 and contain 16bit unsigned ints
|
||||
(`raster_constraint_pixel_types(rast) = '{16BUI}'). Any other columns in the
|
||||
table will be ignored. You must furthermore create an index as follows:
|
||||
|
||||
```
|
||||
CREATE INDEX ON secondary_importance USING gist(ST_ConvexHull(gist))
|
||||
```
|
||||
|
||||
The following raster2pgsql command will create a table that conforms to
|
||||
the requirements:
|
||||
|
||||
```
|
||||
raster2pgsql -I -C -Y -d -t 128x128 input.tiff public.secondary_importance
|
||||
```
|
||||
20
docs/customize/Overview.md
Normal file
20
docs/customize/Overview.md
Normal file
@@ -0,0 +1,20 @@
|
||||
Nominatim comes with a predefined set of configuration options that should
|
||||
work for most standard installations. If you have special requirements, there
|
||||
are many places where the configuration can be adapted. This chapter describes
|
||||
the following configurable parts:
|
||||
|
||||
* [Global Settings](Settings.md) has a detailed description of all parameters that
|
||||
can be set in your local `.env` configuration
|
||||
* [Import styles](Import-Styles.md) explains how to write your own import style
|
||||
in order to control what kind of OSM data will be imported
|
||||
* [Place ranking](Ranking.md) describes the configuration around classifing
|
||||
places in terms of their importance and their role in an address
|
||||
* [Tokenizers](Tokenizers.md) describes the configuration of the module
|
||||
responsible for analysing and indexing names
|
||||
* [Special Phrases](Special-Phrases.md) are common nouns or phrases that
|
||||
can be used in search to identify a class of places
|
||||
|
||||
There are also guides for adding the following external data:
|
||||
|
||||
* [US house numbers from the TIGER dataset](Tiger.md)
|
||||
* [External postcodes](Postcodes.md)
|
||||
37
docs/customize/Postcodes.md
Normal file
37
docs/customize/Postcodes.md
Normal file
@@ -0,0 +1,37 @@
|
||||
# External postcode data
|
||||
|
||||
Nominatim creates a table of known postcode centroids during import. This table
|
||||
is used for searches of postcodes and for adding postcodes to places where the
|
||||
OSM data does not provide one. These postcode centroids are mainly computed
|
||||
from the OSM data itself. In addition, Nominatim supports reading postcode
|
||||
information from an external CSV file, to supplement the postcodes that are
|
||||
missing in OSM.
|
||||
|
||||
To enable external postcode support, simply put one CSV file per country into
|
||||
your project directory and name it `<CC>_postcodes.csv`. `<CC>` must be the
|
||||
two-letter country code for which to apply the file. The file may also be
|
||||
gzipped. Then it must be called `<CC>_postcodes.csv.gz`.
|
||||
|
||||
The CSV file must use commas as a delimiter and have a header line. Nominatim
|
||||
expects three columns to be present: `postcode`, `lat` and `lon`. All other
|
||||
columns are ignored. `lon` and `lat` must describe the x and y coordinates of the
|
||||
postcode centroids in WGS84.
|
||||
|
||||
The postcode files are loaded only when there is data for the given country
|
||||
in your database. For example, if there is a `us_postcodes.csv` file in your
|
||||
project directory but you import only an excerpt of Italy, then the US postcodes
|
||||
will simply be ignored.
|
||||
|
||||
As a rule, the external postcode data should be put into the project directory
|
||||
**before** starting the initial import. Still, you can add, remove and update the
|
||||
external postcode data at any time. Simply
|
||||
run:
|
||||
|
||||
```
|
||||
nominatim refresh --postcodes
|
||||
```
|
||||
|
||||
to make the changes visible in your database. Be aware, however, that the changes
|
||||
only have an immediate effect on searches for postcodes. Postcodes that were
|
||||
added to places are only updated, when they are reindexed. That usually happens
|
||||
only during replication updates.
|
||||
@@ -1,8 +1,7 @@
|
||||
# Place Ranking in Nominatim
|
||||
|
||||
Nominatim uses two metrics to rank a place: search rank and address rank.
|
||||
Both can be assigned a value between 0 and 30. They serve slightly
|
||||
different purposes, which are explained in this chapter.
|
||||
This chapter explains what place ranking means and how it can be customized.
|
||||
|
||||
## Search rank
|
||||
|
||||
672
docs/customize/Settings.md
Normal file
672
docs/customize/Settings.md
Normal file
@@ -0,0 +1,672 @@
|
||||
This section provides a reference of all configuration parameters that can
|
||||
be used with Nominatim.
|
||||
|
||||
# Configuring Nominatim
|
||||
|
||||
Nominatim uses [dotenv](https://github.com/theskumar/python-dotenv) to manage
|
||||
its configuration settings. There are two means to set configuration
|
||||
variables: through an `.env` configuration file or through an environment
|
||||
variable.
|
||||
|
||||
The `.env` configuration file needs to be placed into the
|
||||
[project directory](../admin/Import.md#creating-the-project-directory). It
|
||||
must contain configuration parameters in `<parameter>=<value>` format.
|
||||
Please refer to the dotenv documentation for details.
|
||||
|
||||
The configuration options may also be set in the form of shell environment
|
||||
variables. This is particularly useful, when you want to temporarily change
|
||||
a configuration option. For example, to force the replication serve to
|
||||
download the next change, you can temporarily disable the update interval:
|
||||
|
||||
NOMINATIM_REPLICATION_UPDATE_INTERVAL=0 nominatim replication --once
|
||||
|
||||
If a configuration option is defined through .env file and environment
|
||||
variable, then the latter takes precedence.
|
||||
|
||||
## Configuration Parameter Reference
|
||||
|
||||
### Import and Database Settings
|
||||
|
||||
#### NOMINATIM_DATABASE_DSN
|
||||
|
||||
| Summary | |
|
||||
| -------------- | --------------------------------------------------- |
|
||||
| **Description:** | Database connection string |
|
||||
| **Format:** | string: `pgsql:<param1>=<value1>;<param2>=<value2>;...` |
|
||||
| **Default:** | pgsql:dbname=nominatim |
|
||||
| **After Changes:** | run `nominatim refresh --website` |
|
||||
|
||||
Sets the connection parameters for the Nominatim database. At a minimum
|
||||
the name of the database (`dbname`) is required. You can set any additional
|
||||
parameter that is understood by libpq. See the [Postgres documentation](https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-PARAMKEYWORDS) for a full list.
|
||||
|
||||
!!! note
|
||||
It is usually recommended not to set the password directly in this
|
||||
configuration parameter. Use a
|
||||
[password file](https://www.postgresql.org/docs/current/libpq-pgpass.html)
|
||||
instead.
|
||||
|
||||
|
||||
#### NOMINATIM_DATABASE_WEBUSER
|
||||
|
||||
| Summary | |
|
||||
| -------------- | --------------------------------------------------- |
|
||||
| **Description:** | Database query user |
|
||||
| **Format:** | string |
|
||||
| **Default:** | www-data |
|
||||
| **After Changes:** | cannot be changed after import |
|
||||
|
||||
Defines the name of the database user that will run search queries. Usually
|
||||
this is the user under which the webserver is executed. When running Nominatim
|
||||
via php-fpm, you can also define a separate query user. The Postgres user
|
||||
needs to be set up before starting the import.
|
||||
|
||||
Nominatim grants minimal rights to this user to all tables that are needed
|
||||
for running geocoding queries.
|
||||
|
||||
|
||||
#### NOMINATIM_DATABASE_MODULE_PATH
|
||||
|
||||
| Summary | |
|
||||
| -------------- | --------------------------------------------------- |
|
||||
| **Description:** | Directory where to find the PostgreSQL server module |
|
||||
| **Format:** | path |
|
||||
| **Default:** | _empty_ (use `<project_directory>/module`) |
|
||||
| **After Changes:** | run `nominatim refresh --functions` |
|
||||
| **Comment:** | Legacy tokenizer only |
|
||||
|
||||
Defines the directory in which the PostgreSQL server module `nominatim.so`
|
||||
is stored. The directory and module must be accessible by the PostgreSQL
|
||||
server.
|
||||
|
||||
For information on how to use this setting when working with external databases,
|
||||
see [Advanced Installations](../admin/Advanced-Installations.md).
|
||||
|
||||
The option is only used by the Legacy tokenizer and ignored otherwise.
|
||||
|
||||
|
||||
#### NOMINATIM_TOKENIZER
|
||||
|
||||
| Summary | |
|
||||
| -------------- | --------------------------------------------------- |
|
||||
| **Description:** | Tokenizer used for normalizing and parsing queries and names |
|
||||
| **Format:** | string |
|
||||
| **Default:** | legacy |
|
||||
| **After Changes:** | cannot be changed after import |
|
||||
|
||||
Sets the tokenizer type to use for the import. For more information on
|
||||
available tokenizers and how they are configured, see
|
||||
[Tokenizers](../customize/Tokenizers.md).
|
||||
|
||||
|
||||
#### NOMINATIM_TOKENIZER_CONFIG
|
||||
|
||||
| Summary | |
|
||||
| -------------- | --------------------------------------------------- |
|
||||
| **Description:** | Configuration file for the tokenizer |
|
||||
| **Format:** | path |
|
||||
| **Default:** | _empty_ (default file depends on tokenizer) |
|
||||
| **After Changes:** | see documentation for each tokenizer |
|
||||
|
||||
Points to the file with additional configuration for the tokenizer.
|
||||
See the [Tokenizer](../customize/Tokenizers.md) descriptions for details
|
||||
on the file format.
|
||||
|
||||
If a relative path is given, then the file is searched first relative to the
|
||||
project directory and then in the global settings directory.
|
||||
|
||||
#### NOMINATIM_MAX_WORD_FREQUENCY
|
||||
|
||||
| Summary | |
|
||||
| -------------- | --------------------------------------------------- |
|
||||
| **Description:** | Number of occurrences before a word is considered frequent |
|
||||
| **Format:** | int |
|
||||
| **Default:** | 50000 |
|
||||
| **After Changes:** | cannot be changed after import |
|
||||
| **Comment:** | Legacy tokenizer only |
|
||||
|
||||
The word frequency count is used by the Legacy tokenizer to automatically
|
||||
identify _stop words_. Any partial term that occurs more often then what
|
||||
is defined in this setting, is effectively ignored during search.
|
||||
|
||||
|
||||
#### NOMINATIM_LIMIT_REINDEXING
|
||||
|
||||
| Summary | |
|
||||
| -------------- | --------------------------------------------------- |
|
||||
| **Description:** | Avoid invalidating large areas |
|
||||
| **Format:** | bool |
|
||||
| **Default:** | yes |
|
||||
|
||||
Nominatim computes the address of each place at indexing time. This has the
|
||||
advantage to make search faster but also means that more objects needs to
|
||||
be invalidated when the data changes. For example, changing the name of
|
||||
the state of Florida would require recomputing every single address point
|
||||
in the state to make the new name searchable in conjunction with addresses.
|
||||
|
||||
Setting this option to 'yes' means that Nominatim skips reindexing of contained
|
||||
objects when the area becomes too large.
|
||||
|
||||
|
||||
#### NOMINATIM_UPDATE_FORWARD_DEPENDENCIES
|
||||
|
||||
| Summary | |
|
||||
| -------------- | --------------------------------------------------- |
|
||||
| **Description:** | Forward geometry changes to dependet objects |
|
||||
| **Format:** | bool |
|
||||
| **Default:** | no |
|
||||
| **Comment:** | EXPERT ONLY. Must not be enabled after import. |
|
||||
|
||||
The geometry of OSM ways and relations may change when a node that is part
|
||||
of the object is moved around. These changes are not propagated per default.
|
||||
The geometry of ways/relations is only updated the next time that the object
|
||||
itself is touched. When enabling this option, then dependent objects will
|
||||
be marked for update when one of its member objects changes.
|
||||
|
||||
Enabling this option may slow down updates significantly.
|
||||
|
||||
!!! warning
|
||||
If you want to enable this option, it must be set already on import.
|
||||
Do not enable this option on an existing database that was imported with
|
||||
NOMINATIM_UPDATE_FORWARD_DEPENDENCIES=no.
|
||||
Updates will become unusably slow.
|
||||
|
||||
#### NOMINATIM_LANGUAGES
|
||||
|
||||
| Summary | |
|
||||
| -------------- | --------------------------------------------------- |
|
||||
| **Description:** | Restrict search languages |
|
||||
| **Format:** | string: comma-separated list of language codes |
|
||||
| **Default:** | _empty_ |
|
||||
|
||||
Normally Nominatim will include all language variants of name:XX
|
||||
in the search index. Set this to a comma separated list of language
|
||||
codes, to restrict import to a subset of languages.
|
||||
|
||||
Currently only affects the initial import of country names and special phrases.
|
||||
|
||||
|
||||
#### NOMINATIM_TERM_NORMALIZATION
|
||||
|
||||
| Summary | |
|
||||
| -------------- | --------------------------------------------------- |
|
||||
| **Description:** | Rules for normalizing terms for comparisons |
|
||||
| **Format:** | string: semicolon-separated list of ICU rules |
|
||||
| **Default:** | :: NFD (); [[:Nonspacing Mark:] [:Cf:]] >; :: lower (); [[:Punctuation:][:Space:]]+ > ' '; :: NFC (); |
|
||||
| **Comment:** | Legacy tokenizer only |
|
||||
|
||||
[Special phrases](Special-Phrases.md) have stricter matching requirements than
|
||||
normal search terms. They must appear exactly in the query after this term
|
||||
normalization has been applied.
|
||||
|
||||
Only has an effect on the Legacy tokenizer. For the ICU tokenizer the rules
|
||||
defined in the
|
||||
[normalization section](Tokenizers.md#normalization-and-transliteration)
|
||||
will be used.
|
||||
|
||||
|
||||
#### NOMINATIM_USE_US_TIGER_DATA
|
||||
|
||||
| Summary | |
|
||||
| -------------- | --------------------------------------------------- |
|
||||
| **Description:** | Enable searching for Tiger house number data |
|
||||
| **Format:** | boolean |
|
||||
| **Default:** | no |
|
||||
| **After Changes:** | run `nominatim refresh --functions` |
|
||||
|
||||
When this setting is enabled, search and reverse queries also take data
|
||||
from [Tiger house number data](Tiger.md) into account.
|
||||
|
||||
|
||||
#### NOMINATIM_USE_AUX_LOCATION_DATA
|
||||
|
||||
| Summary | |
|
||||
| -------------- | --------------------------------------------------- |
|
||||
| **Description:** | Enable searching in external house number tables |
|
||||
| **Format:** | boolean |
|
||||
| **Default:** | no |
|
||||
| **After Changes:** | run `nominatim refresh --functions` |
|
||||
| **Comment:** | Do not use. |
|
||||
|
||||
When this setting is enabled, search queries also take data from external
|
||||
house number tables into account.
|
||||
|
||||
*Warning:* This feature is currently unmaintained and should not be used.
|
||||
|
||||
|
||||
#### NOMINATIM_HTTP_PROXY
|
||||
|
||||
| Summary | |
|
||||
| -------------- | --------------------------------------------------- |
|
||||
| **Description:** | Use HTTP proxy when downloading data |
|
||||
| **Format:** | boolean |
|
||||
| **Default:** | no |
|
||||
|
||||
When this setting is enabled and at least
|
||||
[NOMINATIM_HTTP_PROXY_HOST](#nominatim_http_proxy_host) and
|
||||
[NOMINATIM_HTTP_PROXY_PORT](#nominatim_http_proxy_port) are set, the
|
||||
configured proxy will be used, when downloading external data like
|
||||
replication diffs.
|
||||
|
||||
|
||||
#### NOMINATIM_HTTP_PROXY_HOST
|
||||
|
||||
| Summary | |
|
||||
| -------------- | --------------------------------------------------- |
|
||||
| **Description:** | Host name of the proxy to use |
|
||||
| **Format:** | string |
|
||||
| **Default:** | _empty_ |
|
||||
|
||||
When [NOMINATIM_HTTP_PROXY](#nominatim_http_proxy) is enabled, this setting
|
||||
configures the proxy host name.
|
||||
|
||||
|
||||
#### NOMINATIM_HTTP_PROXY_PORT
|
||||
|
||||
| Summary | |
|
||||
| -------------- | --------------------------------------------------- |
|
||||
| **Description:** | Port number of the proxy to use |
|
||||
| **Format:** | integer |
|
||||
| **Default:** | 3128 |
|
||||
|
||||
When [NOMINATIM_HTTP_PROXY](#nominatim_http_proxy) is enabled, this setting
|
||||
configures the port number to use with the proxy.
|
||||
|
||||
|
||||
#### NOMINATIM_HTTP_PROXY_LOGIN
|
||||
|
||||
| Summary | |
|
||||
| -------------- | --------------------------------------------------- |
|
||||
| **Description:** | Username for proxies that require login |
|
||||
| **Format:** | string |
|
||||
| **Default:** | _empty_ |
|
||||
|
||||
When [NOMINATIM_HTTP_PROXY](#nominatim_http_proxy) is enabled, use this
|
||||
setting to define the username for proxies that require a login.
|
||||
|
||||
|
||||
#### NOMINATIM_HTTP_PROXY_PASSWORD
|
||||
|
||||
| Summary | |
|
||||
| -------------- | --------------------------------------------------- |
|
||||
| **Description:** | Password for proxies that require login |
|
||||
| **Format:** | string |
|
||||
| **Default:** | _empty_ |
|
||||
|
||||
When [NOMINATIM_HTTP_PROXY](#nominatim_http_proxy) is enabled, use this
|
||||
setting to define the password for proxies that require a login.
|
||||
|
||||
|
||||
#### NOMINATIM_OSM2PGSQL_BINARY
|
||||
|
||||
| Summary | |
|
||||
| -------------- | --------------------------------------------------- |
|
||||
| **Description:** | Location of the osm2pgsql binary |
|
||||
| **Format:** | path |
|
||||
| **Default:** | _empty_ (use binary shipped with Nominatim) |
|
||||
| **Comment:** | EXPERT ONLY |
|
||||
|
||||
Nominatim uses [osm2pgsql](https://osm2pgsql.org) to load the OSM data
|
||||
initially into the database. Nominatim comes bundled with a version of
|
||||
osm2pgsql that is guaranteed to be compatible. Use this setting to use
|
||||
a different binary instead. You should do this only when you know exactly
|
||||
what you are doing. If the osm2pgsql version is not compatible, then the
|
||||
result is undefined.
|
||||
|
||||
|
||||
#### NOMINATIM_WIKIPEDIA_DATA_PATH
|
||||
|
||||
| Summary | |
|
||||
| -------------- | --------------------------------------------------- |
|
||||
| **Description:** | Directory with the wikipedia importance data |
|
||||
| **Format:** | path |
|
||||
| **Default:** | _empty_ (project directory) |
|
||||
|
||||
Set a custom location for the
|
||||
[wikipedia ranking file](../admin/Import.md#wikipediawikidata-rankings). When
|
||||
unset, Nominatim expects the data to be saved in the project directory.
|
||||
|
||||
#### NOMINATIM_ADDRESS_LEVEL_CONFIG
|
||||
|
||||
| Summary | |
|
||||
| -------------- | --------------------------------------------------- |
|
||||
| **Description:** | Configuration file for rank assignments |
|
||||
| **Format:** | path |
|
||||
| **Default:** | address-levels.json |
|
||||
|
||||
The _address level configuration_ defines the rank assignments for places. See
|
||||
[Place Ranking](Ranking.md) for a detailed explanation what rank assignments
|
||||
are and what the configuration file must look like.
|
||||
|
||||
When a relative path is given, then the file is searched first relative to the
|
||||
project directory and then in the global settings directory.
|
||||
|
||||
|
||||
#### NOMINATIM_IMPORT_STYLE
|
||||
|
||||
| Summary | |
|
||||
| -------------- | --------------------------------------------------- |
|
||||
| **Description:** | Configuration to use for the initial OSM data import |
|
||||
| **Format:** | string or path |
|
||||
| **Default:** | extratags |
|
||||
|
||||
The _style configuration_ describes which OSM objects and tags are taken
|
||||
into consideration for the search database. Nominatim comes with a set
|
||||
of pre-configured styles, that may be configured here.
|
||||
|
||||
You can also write your own custom style and point the setting to the file
|
||||
with the style. When a relative path is given, then the style file is searched
|
||||
first relative to the project directory and then in the global settings
|
||||
directory.
|
||||
|
||||
See [Import Styles](Import-Styles.md)
|
||||
for more information on the available internal styles and the format of the
|
||||
configuration file.
|
||||
|
||||
#### NOMINATIM_FLATNODE_FILE
|
||||
|
||||
| Summary | |
|
||||
| -------------- | --------------------------------------------------- |
|
||||
| **Description:** | Location of osm2pgsql flatnode file |
|
||||
| **Format:** | path |
|
||||
| **Default:** | _empty_ (do not use a flatnote file) |
|
||||
| **After Changes:** | Only change when moving the file physically. |
|
||||
|
||||
The `osm2pgsql flatnode file` is file that efficiently stores geographic
|
||||
location for OSM nodes. For larger imports it can significantly speed up
|
||||
the import. When this option is unset, then osm2pgsql uses a PsotgreSQL table
|
||||
to store the locations.
|
||||
|
||||
When a relative path is given, then the flatnode file is created/searched
|
||||
relative to the project directory.
|
||||
|
||||
!!! warning
|
||||
|
||||
The flatnode file is not only used during the initial import but also
|
||||
when adding new data with `nominatim add-data` or `nominatim replication`.
|
||||
Make sure you keep the flatnode file around and this setting unmodified,
|
||||
if you plan to add more data or run regular updates.
|
||||
|
||||
|
||||
#### NOMINATIM_TABLESPACE_*
|
||||
|
||||
| Summary | |
|
||||
| -------------- | --------------------------------------------------- |
|
||||
| **Description:** | Group of settings for distributing the database over tablespaces |
|
||||
| **Format:** | string |
|
||||
| **Default:** | _empty_ (do not use a table space) |
|
||||
| **After Changes:** | no effect after initial import |
|
||||
|
||||
Nominatim allows to distribute the search database over up to 10 different
|
||||
[PostgreSQL tablespaces](https://www.postgresql.org/docs/current/manage-ag-tablespaces.html).
|
||||
If you use this option, make sure that the tablespaces exist before starting
|
||||
the import.
|
||||
|
||||
The available tablespace groups are:
|
||||
|
||||
NOMINATIM_TABLESPACE_SEARCH_DATA
|
||||
: Data used by the geocoding frontend.
|
||||
|
||||
NOMINATIM_TABLESPACE_SEARCH_INDEX
|
||||
: Indexes used by the geocoding frontend.
|
||||
|
||||
NOMINATIM_TABLESPACE_OSM_DATA
|
||||
: Raw OSM data cache used for import and updates.
|
||||
|
||||
NOMINATIM_TABLESPACE_OSM_DATA
|
||||
: Indexes on the raw OSM data cache.
|
||||
|
||||
NOMINATIM_TABLESPACE_PLACE_DATA
|
||||
: Data table with the pre-filtered but still unprocessed OSM data.
|
||||
Used only during imports and updates.
|
||||
|
||||
NOMINATIM_TABLESPACE_PLACE_INDEX
|
||||
: Indexes on raw data table. Used only during imports and updates.
|
||||
|
||||
NOMINATIM_TABLESPACE_ADDRESS_DATA
|
||||
: Data tables used for computing search terms and addresses of places
|
||||
during import and updates.
|
||||
|
||||
NOMINATIM_TABLESPACE_ADDRESS_INDEX
|
||||
: Indexes on the data tables for search term and address computation.
|
||||
Used only for import and updates.
|
||||
|
||||
NOMINATIM_TABLESPACE_AUX_DATA
|
||||
: Auxiliary data tables for non-OSM data, e.g. for Tiger house number data.
|
||||
|
||||
NOMINATIM_TABLESPACE_AUX_INDEX
|
||||
: Indexes on auxiliary data tables.
|
||||
|
||||
|
||||
### Replication Update Settings
|
||||
|
||||
#### NOMINATIM_REPLICATION_URL
|
||||
|
||||
| Summary | |
|
||||
| -------------- | --------------------------------------------------- |
|
||||
| **Description:** | Base URL of the replication service |
|
||||
| **Format:** | url |
|
||||
| **Default:** | https://planet.openstreetmap.org/replication/minute |
|
||||
| **After Changes:** | run `nominatim replication --init` |
|
||||
|
||||
Replication services deliver updates to OSM data. Use this setting to choose
|
||||
which replication service to use. See [Updates](../admin/Update.md) for more
|
||||
information on how to set up regular updates.
|
||||
|
||||
#### NOMINATIM_REPLICATION_MAX_DIFF
|
||||
|
||||
| Summary | |
|
||||
| -------------- | --------------------------------------------------- |
|
||||
| **Description:** | Maximum amount of data to download per update cycle (in MB) |
|
||||
| **Format:** | integer |
|
||||
| **Default:** | 50 |
|
||||
| **After Changes:** | restart the replication process |
|
||||
|
||||
At each update cycle Nominatim downloads diffs until either no more diffs
|
||||
are available on the server (i.e. the database is up-to-date) or the limit
|
||||
given in this setting is exceeded. Nominatim guarantees to downloads at least
|
||||
one diff, if one is available, no matter how small the setting.
|
||||
|
||||
The default for this setting is fairly conservative because Nominatim keeps
|
||||
all data downloaded in one cycle in RAM. Using large values in a production
|
||||
server may interfere badly with the search frontend because it evicts data
|
||||
from RAM that is needed for speedy answers to incoming requests. It is usually
|
||||
a better idea to keep this setting lower and run multiple update cycles
|
||||
to catch up with updates.
|
||||
|
||||
When catching up in non-production mode, for example after the initial import,
|
||||
the setting can easily be changed temporarily on the command line:
|
||||
|
||||
NOMINATIM_REPLICATION_MAX_DIFF=3000 nominatim replication
|
||||
|
||||
|
||||
#### NOMINATIM_REPLICATION_UPDATE_INTERVAL
|
||||
|
||||
| Summary | |
|
||||
| -------------- | --------------------------------------------------- |
|
||||
| **Description:** | Publication interval of the replication service (in seconds) |
|
||||
| **Format:** | integer |
|
||||
| **Default:** | 75 |
|
||||
| **After Changes:** | restart the replication process |
|
||||
|
||||
This setting determines when Nominatim will attempt to download again a new
|
||||
update. The time is computed from the publication date of the last diff
|
||||
downloaded. Setting this to a slightly higher value than the actual
|
||||
publication interval avoids unnecessary rechecks.
|
||||
|
||||
|
||||
#### NOMINATIM_REPLICATION_RECHECK_INTERVAL
|
||||
|
||||
| Summary | |
|
||||
| -------------- | --------------------------------------------------- |
|
||||
| **Description:** | Wait time to recheck for a pending update (in seconds) |
|
||||
| **Format:** | integer |
|
||||
| **Default:** | 60 |
|
||||
| **After Changes:** | restart the replication process |
|
||||
|
||||
When replication updates are run in continuous mode (using `nominatim replication`),
|
||||
this setting determines how long Nominatim waits until it looks for updates
|
||||
again when updates were not available on the server.
|
||||
|
||||
Note that this is different from
|
||||
[NOMINATIM_REPLICATION_UPDATE_INTERVAL](#nominatim_replication_update_interval).
|
||||
Nominatim will never attempt to query for new updates for UPDATE_INTERVAL
|
||||
seconds after the current database date. Only after the update interval has
|
||||
passed it asks for new data. If then no new data is found, it waits for
|
||||
RECHECK_INTERVAL seconds before it attempts again.
|
||||
|
||||
### API Settings
|
||||
|
||||
#### NOMINATIM_CORS_NOACCESSCONTROL
|
||||
|
||||
| Summary | |
|
||||
| -------------- | --------------------------------------------------- |
|
||||
| **Description:** | Send permissive CORS access headers |
|
||||
| **Format:** | boolean |
|
||||
| **Default:** | yes |
|
||||
| **After Changes:** | run `nominatim refresh --website` |
|
||||
|
||||
When this setting is enabled, API HTTP responses include the HTTP
|
||||
[CORS](https://en.wikipedia.org/wiki/CORS) headers
|
||||
`access-control-allow-origin: *` and `access-control-allow-methods: OPTIONS,GET`.
|
||||
|
||||
#### NOMINATIM_MAPICON_URL
|
||||
|
||||
| Summary | |
|
||||
| -------------- | --------------------------------------------------- |
|
||||
| **Description:** | URL prefix for static icon images |
|
||||
| **Format:** | url |
|
||||
| **Default:** | _empty_ |
|
||||
| **After Changes:** | run `nominatim refresh --website` |
|
||||
|
||||
When a mapicon URL is configured, then Nominatim includes an additional `icon`
|
||||
field in the responses, pointing to an appropriate icon for the place type.
|
||||
|
||||
Map icons used to be included in Nominatim itself but now have moved to the
|
||||
[nominatim-ui](https://github.com/osm-search/nominatim-ui/) project. If you
|
||||
want the URL to be included in API responses, make the `/mapicon`
|
||||
directory of the project available under a public URL and point this setting
|
||||
to the directory.
|
||||
|
||||
|
||||
#### NOMINATIM_DEFAULT_LANGUAGE
|
||||
|
||||
| Summary | |
|
||||
| -------------- | --------------------------------------------------- |
|
||||
| **Description:** | Language of responses when no language is requested |
|
||||
| **Format:** | language code |
|
||||
| **Default:** | _empty_ (use the local language of the feature) |
|
||||
| **After Changes:** | run `nominatim refresh --website` |
|
||||
|
||||
Nominatim localizes the place names in responses when the corresponding
|
||||
translation is available. Users can request a custom language setting through
|
||||
the HTTP accept-languages header or through the explicit parameter
|
||||
[accept-languages](../api/Search.md#language-of-results). If neither is
|
||||
given, it falls back to this setting. If the setting is also empty, then
|
||||
the local languages (in OSM: the name tag without any language suffix) is
|
||||
used.
|
||||
|
||||
|
||||
#### NOMINATIM_SEARCH_BATCH_MODE
|
||||
|
||||
| Summary | |
|
||||
| -------------- | --------------------------------------------------- |
|
||||
| **Description:** | Enable a special batch query mode |
|
||||
| **Format:** | boolean |
|
||||
| **Default:** | no |
|
||||
| **After Changes:** | run `nominatim refresh --website` |
|
||||
|
||||
This feature is currently undocumented and potentially broken.
|
||||
|
||||
|
||||
#### NOMINATIM_SEARCH_NAME_ONLY_THRESHOLD
|
||||
|
||||
| Summary | |
|
||||
| -------------- | --------------------------------------------------- |
|
||||
| **Description:** | Threshold for switching the search index lookup strategy |
|
||||
| **Format:** | integer |
|
||||
| **Default:** | 500 |
|
||||
| **After Changes:** | run `nominatim refresh --website` |
|
||||
|
||||
This setting defines the threshold over which a name is no longer considered
|
||||
as rare. When searching for places with rare names, only the name is used
|
||||
for place lookups. Otherwise the name and any address information is used.
|
||||
|
||||
This setting only has an effect after `nominatim refresh --word-counts` has
|
||||
been called to compute the word frequencies.
|
||||
|
||||
|
||||
#### NOMINATIM_LOOKUP_MAX_COUNT
|
||||
|
||||
| Summary | |
|
||||
| -------------- | --------------------------------------------------- |
|
||||
| **Description:** | Maximum number of OSM ids accepted by /lookup |
|
||||
| **Format:** | integer |
|
||||
| **Default:** | 50 |
|
||||
| **After Changes:** | run `nominatim refresh --website` |
|
||||
|
||||
The /lookup point accepts list of ids to look up address details for. This
|
||||
setting restricts the number of places a user may look up with a single
|
||||
request.
|
||||
|
||||
|
||||
#### NOMINATIM_POLYGON_OUTPUT_MAX_TYPES
|
||||
|
||||
| Summary | |
|
||||
| -------------- | --------------------------------------------------- |
|
||||
| **Description:** | Number of different geometry formats that may be returned |
|
||||
| **Format:** | integer |
|
||||
| **Default:** | 1 |
|
||||
| **After Changes:** | run `nominatim refresh --website` |
|
||||
|
||||
Nominatim supports returning full geometries of places. The geometries may
|
||||
be requested in different formats with one of the
|
||||
[`polygon_*` parameters](../api/Search.md#polygon-output). Use this
|
||||
setting to restrict the number of geometry types that may be requested
|
||||
with a single query.
|
||||
|
||||
Setting this parameter to 0 disables polygon output completely.
|
||||
|
||||
### Logging Settings
|
||||
|
||||
#### NOMINATIM_LOG_DB
|
||||
|
||||
| Summary | |
|
||||
| -------------- | --------------------------------------------------- |
|
||||
| **Description:** | Log requests into the database |
|
||||
| **Format:** | boolean |
|
||||
| **Default:** | no |
|
||||
| **After Changes:** | run `nominatim refresh --website` |
|
||||
|
||||
Enable logging requests into a database table with this setting. The logs
|
||||
can be found in the table `new_query_log`.
|
||||
|
||||
When using this logging method, it is advisable to set up a job that
|
||||
regularly clears out old logging information. Nominatim will not do that
|
||||
on its own.
|
||||
|
||||
Can be used as the same time as NOMINATIM_LOG_FILE.
|
||||
|
||||
#### NOMINATIM_LOG_FILE
|
||||
|
||||
| Summary | |
|
||||
| -------------- | --------------------------------------------------- |
|
||||
| **Description:** | Log requests into a file |
|
||||
| **Format:** | path |
|
||||
| **Default:** | _empty_ (logging disabled) |
|
||||
| **After Changes:** | run `nominatim refresh --website` |
|
||||
|
||||
Enable logging of requests into a file with this setting by setting the log
|
||||
file where to log to. A relative file name is assumed to be relative to
|
||||
the project directory.
|
||||
|
||||
|
||||
The entries in the log file have the following format:
|
||||
|
||||
<request time> <execution time in s> <number of results> <type> "<query string>"
|
||||
|
||||
Request time is the time when the request was started. The execution time is
|
||||
given in seconds and corresponds to the time the query took executing in PHP.
|
||||
type contains the name of the endpoint used.
|
||||
|
||||
Can be used as the same time as NOMINATIM_LOG_DB.
|
||||
34
docs/customize/Special-Phrases.md
Normal file
34
docs/customize/Special-Phrases.md
Normal file
@@ -0,0 +1,34 @@
|
||||
# Special phrases
|
||||
|
||||
## Importing OSM user-maintained special phrases
|
||||
|
||||
As described in the [Import section](../admin/Import.md), it is possible to
|
||||
import special phrases from the wiki with the following command:
|
||||
|
||||
```sh
|
||||
nominatim special-phrases --import-from-wiki
|
||||
```
|
||||
|
||||
## Importing custom special phrases
|
||||
|
||||
But, it is also possible to import some phrases from a csv file.
|
||||
To do so, you have access to the following command:
|
||||
|
||||
```sh
|
||||
nominatim special-phrases --import-from-csv <csv file>
|
||||
```
|
||||
|
||||
Note that the two previous import commands will update the phrases from your database.
|
||||
This means that if you import some phrases from a csv file, only the phrases
|
||||
present in the csv file will be kept into the database. All other phrases will
|
||||
be removed.
|
||||
|
||||
If you want to only add new phrases and not update the other ones you can add
|
||||
the argument `--no-replace` to the import command. For example:
|
||||
|
||||
```sh
|
||||
nominatim special-phrases --import-from-csv <csv file> --no-replace
|
||||
```
|
||||
|
||||
This will add the phrases present in the csv file into the database without
|
||||
removing the other ones.
|
||||
28
docs/customize/Tiger.md
Normal file
28
docs/customize/Tiger.md
Normal file
@@ -0,0 +1,28 @@
|
||||
# Installing TIGER housenumber data for the US
|
||||
|
||||
Nominatim is able to use the official [TIGER](https://www.census.gov/geographies/mapping-files/time-series/geo/tiger-line-file.html)
|
||||
address set to complement the OSM house number data in the US. You can add
|
||||
TIGER data to your own Nominatim instance by following these steps. The
|
||||
entire US adds about 10GB to your database.
|
||||
|
||||
1. Get preprocessed TIGER data:
|
||||
|
||||
cd $PROJECT_DIR
|
||||
wget https://nominatim.org/data/tiger-nominatim-preprocessed-latest.csv.tar.gz
|
||||
|
||||
2. Import the data into your Nominatim database:
|
||||
|
||||
nominatim add-data --tiger-data tiger-nominatim-preprocessed-latest.csv.tar.gz
|
||||
|
||||
3. Enable use of the Tiger data in your existing `.env` file by adding:
|
||||
|
||||
echo NOMINATIM_USE_US_TIGER_DATA=yes >> .env
|
||||
|
||||
4. Apply the new settings:
|
||||
|
||||
nominatim refresh --functions --website
|
||||
|
||||
|
||||
See the [TIGER-data project](https://github.com/osm-search/TIGER-data) for more
|
||||
information on how the data got preprocessed.
|
||||
|
||||
391
docs/customize/Tokenizers.md
Normal file
391
docs/customize/Tokenizers.md
Normal file
@@ -0,0 +1,391 @@
|
||||
# Tokenizers
|
||||
|
||||
The tokenizer module in Nominatim is responsible for analysing the names given
|
||||
to OSM objects and the terms of an incoming query in order to make sure, they
|
||||
can be matched appropriately.
|
||||
|
||||
Nominatim offers different tokenizer modules, which behave differently and have
|
||||
different configuration options. This sections describes the tokenizers and how
|
||||
they can be configured.
|
||||
|
||||
!!! important
|
||||
The use of a tokenizer is tied to a database installation. You need to choose
|
||||
and configure the tokenizer before starting the initial import. Once the import
|
||||
is done, you cannot switch to another tokenizer anymore. Reconfiguring the
|
||||
chosen tokenizer is very limited as well. See the comments in each tokenizer
|
||||
section.
|
||||
|
||||
## Legacy tokenizer
|
||||
|
||||
The legacy tokenizer implements the analysis algorithms of older Nominatim
|
||||
versions. It uses a special Postgresql module to normalize names and queries.
|
||||
This tokenizer is automatically installed and used when upgrading an older
|
||||
database. It should not be used for new installations anymore.
|
||||
|
||||
### Compiling the PostgreSQL module
|
||||
|
||||
The tokeinzer needs a special C module for PostgreSQL which is not compiled
|
||||
by default. If you need the legacy tokenizer, compile Nominatim as follows:
|
||||
|
||||
```
|
||||
mkdir build
|
||||
cd build
|
||||
cmake -DBUILD_MODULE=on
|
||||
make
|
||||
```
|
||||
|
||||
### Enabling the tokenizer
|
||||
|
||||
To enable the tokenizer add the following line to your project configuration:
|
||||
|
||||
```
|
||||
NOMINATIM_TOKENIZER=legacy
|
||||
```
|
||||
|
||||
The Postgresql module for the tokenizer is available in the `module` directory
|
||||
and also installed with the remainder of the software under
|
||||
`lib/nominatim/module/nominatim.so`. You can specify a custom location for
|
||||
the module with
|
||||
|
||||
```
|
||||
NOMINATIM_DATABASE_MODULE_PATH=<path to directory where nominatim.so resides>
|
||||
```
|
||||
|
||||
This is in particular useful when the database runs on a different server.
|
||||
See [Advanced installations](../admin/Advanced-Installations.md#importing-nominatim-to-an-external-postgresql-database) for details.
|
||||
|
||||
There are no other configuration options for the legacy tokenizer. All
|
||||
normalization functions are hard-coded.
|
||||
|
||||
## ICU tokenizer
|
||||
|
||||
The ICU tokenizer uses the [ICU library](http://site.icu-project.org/) to
|
||||
normalize names and queries. It also offers configurable decomposition and
|
||||
abbreviation handling.
|
||||
This tokenizer is currently the default.
|
||||
|
||||
To enable the tokenizer add the following line to your project configuration:
|
||||
|
||||
```
|
||||
NOMINATIM_TOKENIZER=icu
|
||||
```
|
||||
|
||||
### How it works
|
||||
|
||||
On import the tokenizer processes names in the following three stages:
|
||||
|
||||
1. During the **Sanitizer step** incoming names are cleaned up and converted to
|
||||
**full names**. This step can be used to regularize spelling, split multi-name
|
||||
tags into their parts and tag names with additional attributes. See the
|
||||
[Sanitizers section](#sanitizers) below for available cleaning routines.
|
||||
2. The **Normalization** part removes all information from the full names
|
||||
that are not relevant for search.
|
||||
3. The **Token analysis** step takes the normalized full names and creates
|
||||
all transliterated variants under which the name should be searchable.
|
||||
See the [Token analysis](#token-analysis) section below for more
|
||||
information.
|
||||
|
||||
During query time, only normalization and transliteration are relevant.
|
||||
An incoming query is first split into name chunks (this usually means splitting
|
||||
the string at the commas) and the each part is normalised and transliterated.
|
||||
The result is used to look up places in the search index.
|
||||
|
||||
### Configuration
|
||||
|
||||
The ICU tokenizer is configured using a YAML file which can be configured using
|
||||
`NOMINATIM_TOKENIZER_CONFIG`. The configuration is read on import and then
|
||||
saved as part of the internal database status. Later changes to the variable
|
||||
have no effect.
|
||||
|
||||
Here is an example configuration file:
|
||||
|
||||
``` yaml
|
||||
normalization:
|
||||
- ":: lower ()"
|
||||
- "ß > 'ss'" # German szet is unimbigiously equal to double ss
|
||||
transliteration:
|
||||
- !include /etc/nominatim/icu-rules/extended-unicode-to-asccii.yaml
|
||||
- ":: Ascii ()"
|
||||
sanitizers:
|
||||
- step: split-name-list
|
||||
token-analysis:
|
||||
- analyzer: generic
|
||||
variants:
|
||||
- !include icu-rules/variants-ca.yaml
|
||||
- words:
|
||||
- road -> rd
|
||||
- bridge -> bdge,br,brdg,bri,brg
|
||||
mutations:
|
||||
- pattern: 'ä'
|
||||
replacements: ['ä', 'ae']
|
||||
```
|
||||
|
||||
The configuration file contains four sections:
|
||||
`normalization`, `transliteration`, `sanitizers` and `token-analysis`.
|
||||
|
||||
#### Normalization and Transliteration
|
||||
|
||||
The normalization and transliteration sections each define a set of
|
||||
ICU rules that are applied to the names.
|
||||
|
||||
The **normalisation** rules are applied after sanitation. They should remove
|
||||
any information that is not relevant for search at all. Usual rules to be
|
||||
applied here are: lower-casing, removing of special characters, cleanup of
|
||||
spaces.
|
||||
|
||||
The **transliteration** rules are applied at the end of the tokenization
|
||||
process to transfer the name into an ASCII representation. Transliteration can
|
||||
be useful to allow for further fuzzy matching, especially between different
|
||||
scripts.
|
||||
|
||||
Each section must contain a list of
|
||||
[ICU transformation rules](https://unicode-org.github.io/icu/userguide/transforms/general/rules.html).
|
||||
The rules are applied in the order in which they appear in the file.
|
||||
You can also include additional rules from external yaml file using the
|
||||
`!include` tag. The included file must contain a valid YAML list of ICU rules
|
||||
and may again include other files.
|
||||
|
||||
!!! warning
|
||||
The ICU rule syntax contains special characters that conflict with the
|
||||
YAML syntax. You should therefore always enclose the ICU rules in
|
||||
double-quotes.
|
||||
|
||||
#### Sanitizers
|
||||
|
||||
The sanitizers section defines an ordered list of functions that are applied
|
||||
to the name and address tags before they are further processed by the tokenizer.
|
||||
They allows to clean up the tagging and bring it to a standardized form more
|
||||
suitable for building the search index.
|
||||
|
||||
!!! hint
|
||||
Sanitizers only have an effect on how the search index is built. They
|
||||
do not change the information about each place that is saved in the
|
||||
database. In particular, they have no influence on how the results are
|
||||
displayed. The returned results always show the original information as
|
||||
stored in the OpenStreetMap database.
|
||||
|
||||
Each entry contains information of a sanitizer to be applied. It has a
|
||||
mandatory parameter `step` which gives the name of the sanitizer. Depending
|
||||
on the type, it may have additional parameters to configure its operation.
|
||||
|
||||
The order of the list matters. The sanitizers are applied exactly in the order
|
||||
that is configured. Each sanitizer works on the results of the previous one.
|
||||
|
||||
The following is a list of sanitizers that are shipped with Nominatim.
|
||||
|
||||
##### split-name-list
|
||||
|
||||
::: nominatim.tokenizer.sanitizers.split_name_list
|
||||
selection:
|
||||
members: False
|
||||
rendering:
|
||||
heading_level: 6
|
||||
|
||||
##### strip-brace-terms
|
||||
|
||||
::: nominatim.tokenizer.sanitizers.strip_brace_terms
|
||||
selection:
|
||||
members: False
|
||||
rendering:
|
||||
heading_level: 6
|
||||
|
||||
##### tag-analyzer-by-language
|
||||
|
||||
::: nominatim.tokenizer.sanitizers.tag_analyzer_by_language
|
||||
selection:
|
||||
members: False
|
||||
rendering:
|
||||
heading_level: 6
|
||||
|
||||
##### clean-housenumbers
|
||||
|
||||
::: nominatim.tokenizer.sanitizers.clean_housenumbers
|
||||
selection:
|
||||
members: False
|
||||
rendering:
|
||||
heading_level: 6
|
||||
|
||||
##### clean-postcodes
|
||||
|
||||
::: nominatim.tokenizer.sanitizers.clean_postcodes
|
||||
selection:
|
||||
members: False
|
||||
rendering:
|
||||
heading_level: 6
|
||||
|
||||
##### clean-tiger-tags
|
||||
|
||||
::: nominatim.tokenizer.sanitizers.clean_tiger_tags
|
||||
selection:
|
||||
members: False
|
||||
rendering:
|
||||
heading_level: 6
|
||||
|
||||
|
||||
|
||||
#### Token Analysis
|
||||
|
||||
Token analyzers take a full name and transform it into one or more normalized
|
||||
form that are then saved in the search index. In its simplest form, the
|
||||
analyzer only applies the transliteration rules. More complex analyzers
|
||||
create additional spelling variants of a name. This is useful to handle
|
||||
decomposition and abbreviation.
|
||||
|
||||
The ICU tokenizer may use different analyzers for different names. To select
|
||||
the analyzer to be used, the name must be tagged with the `analyzer` attribute
|
||||
by a sanitizer (see for example the
|
||||
[tag-analyzer-by-language sanitizer](#tag-analyzer-by-language)).
|
||||
|
||||
The token-analysis section contains the list of configured analyzers. Each
|
||||
analyzer must have an `id` parameter that uniquely identifies the analyzer.
|
||||
The only exception is the default analyzer that is used when no special
|
||||
analyzer was selected. There are analysers with special ids:
|
||||
|
||||
* '@housenumber'. If an analyzer with that name is present, it is used
|
||||
for normalization of house numbers.
|
||||
* '@potcode'. If an analyzer with that name is present, it is used
|
||||
for normalization of postcodes.
|
||||
|
||||
Different analyzer implementations may exist. To select the implementation,
|
||||
the `analyzer` parameter must be set. The different implementations are
|
||||
described in the following.
|
||||
|
||||
##### Generic token analyzer
|
||||
|
||||
The generic analyzer `generic` is able to create variants from a list of given
|
||||
abbreviation and decomposition replacements and introduce spelling variations.
|
||||
|
||||
###### Variants
|
||||
|
||||
The optional 'variants' section defines lists of replacements which create alternative
|
||||
spellings of a name. To create the variants, a name is scanned from left to
|
||||
right and the longest matching replacement is applied until the end of the
|
||||
string is reached.
|
||||
|
||||
The variants section must contain a list of replacement groups. Each group
|
||||
defines a set of properties that describes where the replacements are
|
||||
applicable. In addition, the word section defines the list of replacements
|
||||
to be made. The basic replacement description is of the form:
|
||||
|
||||
```
|
||||
<source>[,<source>[...]] => <target>[,<target>[...]]
|
||||
```
|
||||
|
||||
The left side contains one or more `source` terms to be replaced. The right side
|
||||
lists one or more replacements. Each source is replaced with each replacement
|
||||
term.
|
||||
|
||||
!!! tip
|
||||
The source and target terms are internally normalized using the
|
||||
normalization rules given in the configuration. This ensures that the
|
||||
strings match as expected. In fact, it is better to use unnormalized
|
||||
words in the configuration because then it is possible to change the
|
||||
rules for normalization later without having to adapt the variant rules.
|
||||
|
||||
###### Decomposition
|
||||
|
||||
In its standard form, only full words match against the source. There
|
||||
is a special notation to match the prefix and suffix of a word:
|
||||
|
||||
``` yaml
|
||||
- ~strasse => str # matches "strasse" as full word and in suffix position
|
||||
- hinter~ => hntr # matches "hinter" as full word and in prefix position
|
||||
```
|
||||
|
||||
There is no facility to match a string in the middle of the word. The suffix
|
||||
and prefix notation automatically trigger the decomposition mode: two variants
|
||||
are created for each replacement, one with the replacement attached to the word
|
||||
and one separate. So in above example, the tokenization of "hauptstrasse" will
|
||||
create the variants "hauptstr" and "haupt str". Similarly, the name "rote strasse"
|
||||
triggers the variants "rote str" and "rotestr". By having decomposition work
|
||||
both ways, it is sufficient to create the variants at index time. The variant
|
||||
rules are not applied at query time.
|
||||
|
||||
To avoid automatic decomposition, use the '|' notation:
|
||||
|
||||
``` yaml
|
||||
- ~strasse |=> str
|
||||
```
|
||||
|
||||
simply changes "hauptstrasse" to "hauptstr" and "rote strasse" to "rote str".
|
||||
|
||||
###### Initial and final terms
|
||||
|
||||
It is also possible to restrict replacements to the beginning and end of a
|
||||
name:
|
||||
|
||||
``` yaml
|
||||
- ^south => s # matches only at the beginning of the name
|
||||
- road$ => rd # matches only at the end of the name
|
||||
```
|
||||
|
||||
So the first example would trigger a replacement for "south 45th street" but
|
||||
not for "the south beach restaurant".
|
||||
|
||||
###### Replacements vs. variants
|
||||
|
||||
The replacement syntax `source => target` works as a pure replacement. It changes
|
||||
the name instead of creating a variant. To create an additional version, you'd
|
||||
have to write `source => source,target`. As this is a frequent case, there is
|
||||
a shortcut notation for it:
|
||||
|
||||
```
|
||||
<source>[,<source>[...]] -> <target>[,<target>[...]]
|
||||
```
|
||||
|
||||
The simple arrow causes an additional variant to be added. Note that
|
||||
decomposition has an effect here on the source as well. So a rule
|
||||
|
||||
``` yaml
|
||||
- "~strasse -> str"
|
||||
```
|
||||
|
||||
means that for a word like `hauptstrasse` four variants are created:
|
||||
`hauptstrasse`, `haupt strasse`, `hauptstr` and `haupt str`.
|
||||
|
||||
###### Mutations
|
||||
|
||||
The 'mutation' section in the configuration describes an additional set of
|
||||
replacements to be applied after the variants have been computed.
|
||||
|
||||
Each mutation is described by two parameters: `pattern` and `replacements`.
|
||||
The pattern must contain a single regular expression to search for in the
|
||||
variant name. The regular expressions need to follow the syntax for
|
||||
[Python regular expressions](file:///usr/share/doc/python3-doc/html/library/re.html#regular-expression-syntax).
|
||||
Capturing groups are not permitted.
|
||||
`replacements` must contain a list of strings that the pattern
|
||||
should be replaced with. Each occurrence of the pattern is replaced with
|
||||
all given replacements. Be mindful of combinatorial explosion of variants.
|
||||
|
||||
###### Modes
|
||||
|
||||
The generic analyser supports a special mode `variant-only`. When configured
|
||||
then it consumes the input token and emits only variants (if any exist). Enable
|
||||
the mode by adding:
|
||||
|
||||
```
|
||||
mode: variant-only
|
||||
```
|
||||
|
||||
to the analyser configuration.
|
||||
|
||||
##### Housenumber token analyzer
|
||||
|
||||
The analyzer `housenumbers` is purpose-made to analyze house numbers. It
|
||||
creates variants with optional spaces between numbers and letters. Thus,
|
||||
house numbers of the form '3 a', '3A', '3-A' etc. are all considered equivalent.
|
||||
|
||||
The analyzer cannot be customized.
|
||||
|
||||
##### Postcode token analyzer
|
||||
|
||||
The analyzer `postcodes` is pupose-made to analyze postcodes. It supports
|
||||
a 'lookup' varaint of the token, which produces variants with optional
|
||||
spaces. Use together with the clean-postcodes sanitizer.
|
||||
|
||||
The analyzer cannot be customized.
|
||||
|
||||
### Reconfiguration
|
||||
|
||||
Changing the configuration after the import is currently not possible, although
|
||||
this feature may be added at a later time.
|
||||
167
docs/develop/Database-Layout.md
Normal file
167
docs/develop/Database-Layout.md
Normal file
@@ -0,0 +1,167 @@
|
||||
# Database Layout
|
||||
|
||||
### Import tables
|
||||
|
||||
OSM data is initially imported using [osm2pgsql](https://osm2pgsql.org).
|
||||
Nominatim uses its own data output style 'gazetteer', which differs from the
|
||||
output style created for map rendering.
|
||||
|
||||
The import process creates the following tables:
|
||||
|
||||

|
||||
|
||||
The `planet_osm_*` tables are the usual backing tables for OSM data. Note
|
||||
that Nominatim uses them to look up special relations and to find nodes on
|
||||
ways.
|
||||
|
||||
The gazetteer style produces a single table `place` as output with the following
|
||||
columns:
|
||||
|
||||
* `osm_type` - kind of OSM object (**N** - node, **W** - way, **R** - relation)
|
||||
* `osm_id` - original OSM ID
|
||||
* `class` - key of principal tag defining the object type
|
||||
* `type` - value of principal tag defining the object type
|
||||
* `name` - collection of tags that contain a name or reference
|
||||
* `admin_level` - numerical value of the tagged administrative level
|
||||
* `address` - collection of tags defining the address of an object
|
||||
* `extratags` - collection of additional interesting tags that are not
|
||||
directly relevant for searching
|
||||
* `geometry` - geometry of the object (in WGS84)
|
||||
|
||||
A single OSM object may appear multiple times in this table when it is tagged
|
||||
with multiple tags that may constitute a principal tag. Take for example a
|
||||
motorway bridge. In OSM, this would be a way which is tagged with
|
||||
`highway=motorway` and `bridge=yes`. This way would appear in the `place` table
|
||||
once with `class` of `highway` and once with a `class` of `bridge`. Thus the
|
||||
*unique key* for `place` is (`osm_type`, `osm_id`, `class`).
|
||||
|
||||
How raw OSM tags are mapped to the columns in the place table is to a certain
|
||||
degree configurable. See [Customizing Import Styles](../customize/Import-Styles.md)
|
||||
for more information.
|
||||
|
||||
### Search tables
|
||||
|
||||
The following tables carry all information needed to do the search:
|
||||
|
||||

|
||||
|
||||
The **placex** table is the central table that saves all information about the
|
||||
searchable places in Nominatim. The basic columns are the same as for the
|
||||
place table and have the same meaning. The placex tables adds the following
|
||||
additional columns:
|
||||
|
||||
* `place_id` - the internal unique ID to identify the place
|
||||
* `partition` - the id to use with partitioned tables (see below)
|
||||
* `geometry_sector` - a location hash used for geographically close ordering
|
||||
* `parent_place_id` - the next higher place in the address hierarchy, only
|
||||
relevant for POI-type places (with rank 30)
|
||||
* `linked_place_id` - place ID of the place this object has been merged with.
|
||||
When this ID is set, then the place is invisible for search.
|
||||
* `importance` - measure how well known the place is
|
||||
* `rank_search`, `rank_address` - search and address rank (see [Customizing ranking](../customize/Ranking.md)
|
||||
* `wikipedia` - the wikipedia page used for computing the importance of the place
|
||||
* `country_code` - the country the place is located in
|
||||
* `housenumber` - normalized housenumber, if the place has one
|
||||
* `postcode` - computed postcode for the place
|
||||
* `indexed_status` - processing status of the place (0 - ready, 1 - freshly inserted, 2 - needs updating, 100 - needs deletion)
|
||||
* `indexed_date` - timestamp when the place was processed last
|
||||
* `centroid` - a point feature for the place
|
||||
|
||||
The **location_property_osmline** table is a special table for
|
||||
[address interpolations](https://wiki.openstreetmap.org/wiki/Addresses#Using_interpolation).
|
||||
The columns have the same meaning and use as the columns with the same name in
|
||||
the placex table. Only three columns are special:
|
||||
|
||||
* `startnumber` and `endnumber` - beginning and end of the number range
|
||||
for the interpolation
|
||||
* `interpolationtype` - a string `odd`, `even` or `all` to indicate
|
||||
the interval between the numbers
|
||||
|
||||
Address interpolations are always ways in OSM, which is why there is no column
|
||||
`osm_type`.
|
||||
|
||||
The **location_postcode** table holds computed centroids of all postcodes that
|
||||
can be found in the OSM data. The meaning of the columns is again the same
|
||||
as that of the placex table.
|
||||
|
||||
Every place needs an address, a set of surrounding places that describe the
|
||||
location of the place. The set of address places is made up of OSM places
|
||||
themselves. The **place_addressline** table cross-references for each place
|
||||
all the places that make up its address. Two columns define the address
|
||||
relation:
|
||||
|
||||
* `place_id` - reference to the place being addressed
|
||||
* `address_place_id` - reference to the place serving as an address part
|
||||
|
||||
The most of the columns cache information from the placex entry of the address
|
||||
part. The exceptions are:
|
||||
|
||||
* `fromarea` - is true if the address part has an area geometry and can
|
||||
therefore be considered preceise
|
||||
* `isaddress` - is true if the address part should show up in the address
|
||||
output. Sometimes there are multiple places competing for for same address
|
||||
type (e.g. multiple cities) and this field resolves the tie.
|
||||
|
||||
The **search_name** table contains the search index proper. It saves for each
|
||||
place the terms with which the place can be found. The terms are split into
|
||||
the name itself and all terms that make up the address. The table mirrors some
|
||||
of the columns from placex for faster lookup.
|
||||
|
||||
Search terms are not saved as strings. Each term is assigned an integer and those
|
||||
integers are saved in the name and address vectors of the search_name table. The
|
||||
**word** table serves as the lookup table from string to such a word ID. The
|
||||
exact content of the word table depends on the [tokenizer](Tokenizers.md) used.
|
||||
|
||||
## Address computation tables
|
||||
|
||||
Next to the main search tables, there is a set of secondary helper tables used
|
||||
to compute the address relations between places. These tables are partitioned.
|
||||
Each country is assigned a partition number in the country_name table (see
|
||||
below) and the data is then split between a set of tables, one for each
|
||||
partition. Note that Nominatim still manually manages partitioned tables.
|
||||
Native support for partitions in PostgreSQL only became usable with version 13.
|
||||
It will be a little while before Nominatim drops support for older versions.
|
||||
|
||||

|
||||
|
||||
The **search_name_X** tables are used to look up streets that appear in the
|
||||
`addr:street` tag.
|
||||
|
||||
The **location_area_large_X** tables are used to look up larger areas
|
||||
(administrative boundaries and place nodes) either through their geographic
|
||||
closeness or through `addr:*` entries.
|
||||
|
||||
The **location_road_X** tables are used to find the closest street for a
|
||||
dependent place.
|
||||
|
||||
All three table cache specific information from the placex table for their
|
||||
selected subset of places:
|
||||
|
||||
* `keywords` and `name_vector` contain lists of term ids (from the word table)
|
||||
that the full name of the place should match against
|
||||
* `isguess` is true for places that are not described by an area
|
||||
|
||||
All other columns reflect their counterpart in the placex table.
|
||||
|
||||
## Static data tables
|
||||
|
||||
Nominatim also creates a number of static tables at import:
|
||||
|
||||
* `nominatim_properties` saves settings that must not be changed after
|
||||
import
|
||||
* `address_levels` save the rank information from the
|
||||
[ranking configuration](../customize/Ranking.md)
|
||||
* `country_name` contains a fallback of names for all countries, their
|
||||
default languages and saves the assignment of countries to partitions.
|
||||
* `country_osm_grid` provides a fallback for country geometries
|
||||
|
||||
## Auxiliary data tables
|
||||
|
||||
Finally there are some table for auxiliary data:
|
||||
|
||||
* `location_property_tiger` - saves housenumber from the Tiger import. Its
|
||||
layout is similar to that of `location_propoerty_osmline`.
|
||||
* `place_class_*` tables are helper tables to facilitate lookup of POIs
|
||||
by their class and type. They exist because it is not possible to create
|
||||
combined indexes with geometries.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Setting up Nominatim for Development
|
||||
|
||||
This chapter gives an overview how to set up Nominatim for developement
|
||||
This chapter gives an overview how to set up Nominatim for development
|
||||
and how to run tests.
|
||||
|
||||
!!! Important
|
||||
@@ -30,14 +30,18 @@ unit tests (using PHPUnit for PHP code and pytest for Python code).
|
||||
It has the following additional requirements:
|
||||
|
||||
* [behave test framework](https://behave.readthedocs.io) >= 1.2.6
|
||||
* [phpunit](https://phpunit.de) >= 7.3
|
||||
* [phpunit](https://phpunit.de) (9.5 is known to work)
|
||||
* [PHP CodeSniffer](https://github.com/squizlabs/PHP_CodeSniffer)
|
||||
* [Pylint](https://pylint.org/) (2.6.0 is used for the CI)
|
||||
* [Pylint](https://pylint.org/) (CI always runs the latest version from pip)
|
||||
* [mypy](http://mypy-lang.org/) (plus typing information for external libs)
|
||||
* [Python Typing Extensions](https://github.com/python/typing_extensions) (for Python < 3.9)
|
||||
* [pytest](https://pytest.org)
|
||||
|
||||
The documentation is built with mkdocs:
|
||||
|
||||
* [mkdocs](https://www.mkdocs.org/) >= 1.1.2
|
||||
* [mkdocstrings](https://mkdocstrings.github.io/) >= 0.16
|
||||
* [mkdocstrings-python-legacy](https://mkdocstrings.github.io/python-legacy/)
|
||||
|
||||
### Installing prerequisites on Ubuntu/Debian
|
||||
|
||||
@@ -49,9 +53,10 @@ To install all necessary packages run:
|
||||
|
||||
```sh
|
||||
sudo apt install php-cgi phpunit php-codesniffer \
|
||||
python3-pip python3-setuptools python3-dev pylint
|
||||
python3-pip python3-setuptools python3-dev
|
||||
|
||||
pip3 install --user behave mkdocs pytest
|
||||
pip3 install --user behave mkdocs mkdocstrings pytest pylint \
|
||||
mypy types-PyYAML types-jinja2 types-psycopg2 types-psutil
|
||||
```
|
||||
|
||||
The `mkdocs` executable will be located in `.local/bin`. You may have to add
|
||||
@@ -113,7 +118,7 @@ symlinks (see `CMakeLists.txt` for the exact steps).
|
||||
Now you can start webserver for local testing
|
||||
|
||||
```
|
||||
build> mkdocs serve
|
||||
build> make serve-doc
|
||||
[server:296] Serving on http://127.0.0.1:8000
|
||||
[handlers:62] Start watching changes
|
||||
```
|
||||
@@ -122,7 +127,7 @@ If you develop inside a Vagrant virtual machine, use a port that is forwarded
|
||||
to your host:
|
||||
|
||||
```
|
||||
build> mkdocs serve --dev-addr 0.0.0.0:8088
|
||||
build> PYTHONPATH=$SRCDIR mkdocs serve --dev-addr 0.0.0.0:8088
|
||||
[server:296] Serving on http://0.0.0.0:8088
|
||||
[handlers:62] Start watching changes
|
||||
```
|
||||
|
||||
227
docs/develop/ICU-Tokenizer-Modules.md
Normal file
227
docs/develop/ICU-Tokenizer-Modules.md
Normal file
@@ -0,0 +1,227 @@
|
||||
# Writing custom sanitizer and token analysis modules for the ICU tokenizer
|
||||
|
||||
The [ICU tokenizer](../customize/Tokenizers.md#icu-tokenizer) provides a
|
||||
highly customizable method to pre-process and normalize the name information
|
||||
of the input data before it is added to the search index. It comes with a
|
||||
selection of sanitizers and token analyzers which you can use to adapt your
|
||||
installation to your needs. If the provided modules are not enough, you can
|
||||
also provide your own implementations. This section describes the API
|
||||
of sanitizers and token analysis.
|
||||
|
||||
!!! warning
|
||||
This API is currently in early alpha status. While this API is meant to
|
||||
be a public API on which other sanitizers and token analyzers may be
|
||||
implemented, it is not guaranteed to be stable at the moment.
|
||||
|
||||
|
||||
## Using non-standard sanitizers and token analyzers
|
||||
|
||||
Sanitizer names (in the `step` property) and token analysis names (in the
|
||||
`analyzer`) may refer to externally supplied modules. There are two ways
|
||||
to include external modules: through a library or from the project directory.
|
||||
|
||||
To include a module from a library, use the absolute import path as name and
|
||||
make sure the library can be found in your PYTHONPATH.
|
||||
|
||||
To use a custom module without creating a library, you can put the module
|
||||
somewhere in your project directory and then use the relative path to the
|
||||
file. Include the whole name of the file including the `.py` ending.
|
||||
|
||||
## Custom sanitizer modules
|
||||
|
||||
A sanitizer module must export a single factory function `create` with the
|
||||
following signature:
|
||||
|
||||
``` python
|
||||
def create(config: SanitizerConfig) -> Callable[[ProcessInfo], None]
|
||||
```
|
||||
|
||||
The function receives the custom configuration for the sanitizer and must
|
||||
return a callable (function or class) that transforms the name and address
|
||||
terms of a place. When a place is processed, then a `ProcessInfo` object
|
||||
is created from the information that was queried from the database. This
|
||||
object is sequentially handed to each configured sanitizer, so that each
|
||||
sanitizer receives the result of processing from the previous sanitizer.
|
||||
After the last sanitizer is finished, the resulting name and address lists
|
||||
are forwarded to the token analysis module.
|
||||
|
||||
Sanitizer functions are instantiated once and then called for each place
|
||||
that is imported or updated. They don't need to be thread-safe.
|
||||
If multi-threading is used, each thread creates their own instance of
|
||||
the function.
|
||||
|
||||
### Sanitizer configuration
|
||||
|
||||
::: nominatim.tokenizer.sanitizers.config.SanitizerConfig
|
||||
rendering:
|
||||
show_source: no
|
||||
heading_level: 6
|
||||
|
||||
### The main filter function of the sanitizer
|
||||
|
||||
The filter function receives a single object of type `ProcessInfo`
|
||||
which has with three members:
|
||||
|
||||
* `place`: read-only information about the place being processed.
|
||||
See PlaceInfo below.
|
||||
* `names`: The current list of names for the place. Each name is a
|
||||
PlaceName object.
|
||||
* `address`: The current list of address names for the place. Each name
|
||||
is a PlaceName object.
|
||||
|
||||
While the `place` member is provided for information only, the `names` and
|
||||
`address` lists are meant to be manipulated by the sanitizer. It may add and
|
||||
remove entries, change information within a single entry (for example by
|
||||
adding extra attributes) or completely replace the list with a different one.
|
||||
|
||||
#### PlaceInfo - information about the place
|
||||
|
||||
::: nominatim.data.place_info.PlaceInfo
|
||||
rendering:
|
||||
show_source: no
|
||||
heading_level: 6
|
||||
|
||||
|
||||
#### PlaceName - extended naming information
|
||||
|
||||
::: nominatim.data.place_name.PlaceName
|
||||
rendering:
|
||||
show_source: no
|
||||
heading_level: 6
|
||||
|
||||
|
||||
### Example: Filter for US street prefixes
|
||||
|
||||
The following sanitizer removes the directional prefixes from street names
|
||||
in the US:
|
||||
|
||||
``` python
|
||||
import re
|
||||
|
||||
def _filter_function(obj):
|
||||
if obj.place.country_code == 'us' \
|
||||
and obj.place.rank_address >= 26 and obj.place.rank_address <= 27:
|
||||
for name in obj.names:
|
||||
name.name = re.sub(r'^(north|south|west|east) ',
|
||||
'',
|
||||
name.name,
|
||||
flags=re.IGNORECASE)
|
||||
|
||||
def create(config):
|
||||
return _filter_function
|
||||
```
|
||||
|
||||
This is the most simple form of a sanitizer module. If defines a single
|
||||
filter function and implements the required `create()` function by returning
|
||||
the filter.
|
||||
|
||||
The filter function first checks if the object is interesting for the
|
||||
sanitizer. Namely it checks if the place is in the US (through `country_code`)
|
||||
and it the place is a street (a `rank_address` of 26 or 27). If the
|
||||
conditions are met, then it goes through all available names and
|
||||
removes any leading directional prefix using a simple regular expression.
|
||||
|
||||
Save the source code in a file in your project directory, for example as
|
||||
`us_streets.py`. Then you can use the sanitizer in your `icu_tokenizer.yaml`:
|
||||
|
||||
``` yaml
|
||||
...
|
||||
sanitizers:
|
||||
- step: us_streets.py
|
||||
...
|
||||
```
|
||||
|
||||
!!! warning
|
||||
This example is just a simplified show case on how to create a sanitizer.
|
||||
It is not really read for real-world use: while the sanitizer would
|
||||
correcly transform `West 5th Street` into `5th Street`. it would also
|
||||
shorten a simple `North Street` to `Street`.
|
||||
|
||||
For more sanitizer examples, have a look at the sanitizers provided by Nominatim.
|
||||
They can be found in the directory
|
||||
[`nominatim/tokenizer/sanitizers`](https://github.com/osm-search/Nominatim/tree/master/nominatim/tokenizer/sanitizers).
|
||||
|
||||
|
||||
## Custom token analysis module
|
||||
|
||||
::: nominatim.tokenizer.token_analysis.base.AnalysisModule
|
||||
rendering:
|
||||
show_source: no
|
||||
heading_level: 6
|
||||
|
||||
|
||||
::: nominatim.tokenizer.token_analysis.base.Analyzer
|
||||
rendering:
|
||||
show_source: no
|
||||
heading_level: 6
|
||||
|
||||
### Example: Creating acronym variants for long names
|
||||
|
||||
The following example of a token analysis module creates acronyms from
|
||||
very long names and adds them as a variant:
|
||||
|
||||
``` python
|
||||
class AcronymMaker:
|
||||
""" This class is the actual analyzer.
|
||||
"""
|
||||
def __init__(self, norm, trans):
|
||||
self.norm = norm
|
||||
self.trans = trans
|
||||
|
||||
|
||||
def get_canonical_id(self, name):
|
||||
# In simple cases, the normalized name can be used as a canonical id.
|
||||
return self.norm.transliterate(name.name).strip()
|
||||
|
||||
|
||||
def compute_variants(self, name):
|
||||
# The transliterated form of the name always makes up a variant.
|
||||
variants = [self.trans.transliterate(name)]
|
||||
|
||||
# Only create acronyms from very long words.
|
||||
if len(name) > 20:
|
||||
# Take the first letter from each word to form the acronym.
|
||||
acronym = ''.join(w[0] for w in name.split())
|
||||
# If that leds to an acronym with at least three letters,
|
||||
# add the resulting acronym as a variant.
|
||||
if len(acronym) > 2:
|
||||
# Never forget to transliterate the variants before returning them.
|
||||
variants.append(self.trans.transliterate(acronym))
|
||||
|
||||
return variants
|
||||
|
||||
# The following two functions are the module interface.
|
||||
|
||||
def configure(rules, normalizer, transliterator):
|
||||
# There is no configuration to parse and no data to set up.
|
||||
# Just return an empty configuration.
|
||||
return None
|
||||
|
||||
|
||||
def create(normalizer, transliterator, config):
|
||||
# Return a new instance of our token analysis class above.
|
||||
return AcronymMaker(normalizer, transliterator)
|
||||
```
|
||||
|
||||
Given the name `Trans-Siberian Railway`, the code above would return the full
|
||||
name `Trans-Siberian Railway` and the acronym `TSR` as variant, so that
|
||||
searching would work for both.
|
||||
|
||||
## Sanitizers vs. Token analysis - what to use for variants?
|
||||
|
||||
It is not always clear when to implement variations in the sanitizer and
|
||||
when to write a token analysis module. Just take the acronym example
|
||||
above: it would also have been possible to write a sanitizer which adds the
|
||||
acronym as an additional name to the name list. The result would have been
|
||||
similar. So which should be used when?
|
||||
|
||||
The most important thing to keep in mind is that variants created by the
|
||||
token analysis are only saved in the word lookup table. They do not need
|
||||
extra space in the search index. If there are many spelling variations, this
|
||||
can mean quite a significant amount of space is saved.
|
||||
|
||||
When creating additional names with a sanitizer, these names are completely
|
||||
independent. In particular, they can be fed into different token analysis
|
||||
modules. This gives a much greater flexibility but at the price that the
|
||||
additional names increase the size of the search index.
|
||||
|
||||
152
docs/develop/Indexing.md
Normal file
152
docs/develop/Indexing.md
Normal file
@@ -0,0 +1,152 @@
|
||||
# Indexing Places
|
||||
|
||||
In Nominatim, the word __indexing__ refers to the process that takes the raw
|
||||
OpenStreetMap data from the place table, enriches it with address information
|
||||
and creates the search indexes. This section explains the basic data flow.
|
||||
|
||||
|
||||
## Initial import
|
||||
|
||||
After osm2pgsql has loaded the raw OSM data into the place table,
|
||||
the data is copied to the final search tables placex and location_property_osmline.
|
||||
While they are copied, some basic properties are added:
|
||||
|
||||
* country_code, geometry_sector and partition
|
||||
* initial search and address rank
|
||||
|
||||
In addition the column `indexed_status` is set to `1` marking the place as one
|
||||
that needs to be indexed.
|
||||
|
||||
All this happens in the triggers `placex_insert` and `osmline_insert`.
|
||||
|
||||
## Indexing
|
||||
|
||||
The main work horse of the data import is the indexing step, where Nominatim
|
||||
takes every place from the placex and location_property_osmline tables where
|
||||
the indexed_status != 0 and computes the search terms and the address parts
|
||||
of the place.
|
||||
|
||||
The indexing happens in three major steps:
|
||||
|
||||
1. **Data preparation** - The indexer gets the data for the place to be indexed
|
||||
from the database.
|
||||
|
||||
2. **Search name processing** - The prepared data is given to the
|
||||
tokenizer which computes the search terms from the names
|
||||
and potentially other information.
|
||||
|
||||
3. **Address processing** - The indexer then hands the prepared data and the
|
||||
tokenizer information back to the database via an `INSERT` statement which
|
||||
also sets the indexed_status to `0`. This triggers the update triggers
|
||||
`placex_update`/`osmline_update` which do the work of computing address
|
||||
parts and filling all the search tables.
|
||||
|
||||
When computing the address terms of a place, Nominatim relies on the processed
|
||||
search names of all the address parts. That is why places are processed in rank
|
||||
order, from smallest rank to largest. To ensure correct handling of linked
|
||||
place nodes, administrative boundaries are processed before all other places.
|
||||
|
||||
Apart from these restrictions, each place can be indexed independently
|
||||
from the others. This allows a large degree of parallelization during the indexing.
|
||||
It also means that the indexing process can be interrupted at any time and
|
||||
will simply pick up where it left of when restarted.
|
||||
|
||||
### Data preparation
|
||||
|
||||
The data preparation step computes and retrieves all data for a place that
|
||||
might be needed for the next step of processing the search name. That includes
|
||||
|
||||
* location information (country code)
|
||||
* place classification (class, type, ranks)
|
||||
* names (including names of linked places)
|
||||
* address information (`addr:*` tags)
|
||||
|
||||
Data preparation is implemented in pl/PgSQL mostly in the functions
|
||||
`placex_indexing_prepare()` and `get_interpolation_address()`.
|
||||
|
||||
#### `addr:*` tag inheritance
|
||||
|
||||
Nominatim has limited support for inheriting address tags from a building
|
||||
to POIs inside the building. This only works when the address tags are on the
|
||||
building outline. Any rank 30 object inside such a building or on its outline
|
||||
inherits all address tags when it does not have any address tags of its own.
|
||||
|
||||
The inheritance is computed in the data preparation step.
|
||||
|
||||
### Search name processing
|
||||
|
||||
The prepared place information is handed to the tokenizer next. This is a
|
||||
Python module responsible for processing the names from both name and address
|
||||
terms and building up the word index from them. The process is explained in
|
||||
more detail in the [Tokenizer chapter](Tokenizers.md).
|
||||
|
||||
### Address processing
|
||||
|
||||
Finally, the preprocessed place information and the results of the search name
|
||||
processing are written back to the database. At this point the update trigger
|
||||
of the placex/location_property_osmline tables take over and fill all the
|
||||
dependent tables. This makes up the most work-intensive part of the indexing.
|
||||
|
||||
Nominatim distinguishes between dependent and independent places.
|
||||
**Dependent places** are all places on rank 30: house numbers, POIs etc. These
|
||||
places don't have a full address of their own. Instead they are attached to
|
||||
a parent street or place and use the information of the parent for searching
|
||||
and displaying information. Everything else are **independent places**: streets,
|
||||
parks, water bodies, suburbs, cities, states etc. They receive a full address
|
||||
on their own.
|
||||
|
||||
The address processing for both types of places is very different.
|
||||
|
||||
#### Independent places
|
||||
|
||||
To compute the address of an independent place Nominatim searches for all
|
||||
places that cover the place to compute the address for at least partially.
|
||||
For places with an area, that area is used to check for coverage. For place
|
||||
nodes an artificial square area is computed according to the rank of
|
||||
the place. The lower the rank the lager the area. The `location_area_large_X`
|
||||
tables are there to facilitate the lookup. All places that can function as
|
||||
the address of another place are saved in those tables.
|
||||
|
||||
`addr:*` and `isin:*` tags are taken into account to compute the address, too.
|
||||
Nominatim will give preference to places with the same name as in these tags
|
||||
when looking for places in the vicinity. If there are no matching place names
|
||||
at all, then the tags are at least added to the search index. That means that
|
||||
the names will not be shown in the result as the 'address' of the place, but
|
||||
searching by them still works.
|
||||
|
||||
Independent places are always added to the global search index `search_name`.
|
||||
|
||||
#### Dependent places
|
||||
|
||||
Dependent places skip the full address computation for performance reasons.
|
||||
Instead they just find a parent place to attach themselves to.
|
||||
|
||||

|
||||
|
||||
By default a POI
|
||||
or house number will be attached to the closest street. That can be any major
|
||||
or minor street indexed by Nominatim. In the default configuration that means
|
||||
that it can attach itself to a footway but only when it has a name.
|
||||
|
||||
When the dependent place has an `addr:street` tag, then Nominatim will first
|
||||
try to find a street with the same name before falling back to the closest
|
||||
street.
|
||||
|
||||
There are also addresses in OSM, where the housenumber does not belong
|
||||
to a street at all. These have an `addr:place` tag. For these places, Nominatim
|
||||
tries to find a place with the given name in the indexed places with an
|
||||
address rank between 16 and 25. If none is found, then the dependent place
|
||||
is attached to the closest place in that category and the addr:place name is
|
||||
added as *unlisted* place, which indicates to Nominatim that it needs to add
|
||||
it to the address output, no matter what. This special case is necessary to
|
||||
cover addresses that don't really refer to an existing object.
|
||||
|
||||
When an address has both the `addr:street` and `addr:place` tag, then Nominatim
|
||||
assumes that the `addr:place` tag in fact should be the city part of the address
|
||||
and give the POI the usual street number address.
|
||||
|
||||
Dependent places are only added to the global search index `search_name` when
|
||||
they have either a name themselves or when they have address tags that are not
|
||||
covered by the places that make up their address. The latter ensures that
|
||||
addresses are always searchable by those address tags.
|
||||
|
||||
@@ -1,45 +0,0 @@
|
||||
# Postcodes in Nominatim
|
||||
|
||||
The blog post
|
||||
[Nominatim and Postcodes](https://www.openstreetmap.org/user/lonvia/diary/43143)
|
||||
describes the handling implemented since Nominatim 3.1.
|
||||
|
||||
Postcode centroids (aka 'calculated postcodes') are generated by looking at all
|
||||
postcodes of a country, grouping them and calculating the geometric centroid.
|
||||
There is currently no logic to deal with extreme outliers (typos or other
|
||||
mistakes in OSM data). There is also no check if a postcodes adheres to a
|
||||
country's format, e.g. if Swiss postcodes are 4 digits.
|
||||
|
||||
|
||||
## Regular updating calculated postcodes
|
||||
|
||||
The script to rerun the calculation is
|
||||
`nominatim refresh --postcodes`
|
||||
and runs once per night on nominatim.openstreetmap.org.
|
||||
|
||||
|
||||
## Finding places that share a specific postcode
|
||||
|
||||
In the Nominatim database run
|
||||
|
||||
```sql
|
||||
SELECT address->'postcode' as pc,
|
||||
osm_type, osm_id, class, type,
|
||||
st_x(centroid) as lon, st_y(centroid) as lat
|
||||
FROM placex
|
||||
WHERE country_code='fr'
|
||||
AND upper(trim (both ' ' from address->'postcode')) = '33210';
|
||||
```
|
||||
|
||||
Alternatively on [Overpass](https://overpass-turbo.eu/) run the following query
|
||||
|
||||
```
|
||||
[out:json][timeout:250];
|
||||
area["name"="France"]->.boundaryarea;
|
||||
(
|
||||
nwr(area.boundaryarea)["addr:postcode"="33210"];
|
||||
);
|
||||
out body;
|
||||
>;
|
||||
out skel qt;
|
||||
```
|
||||
@@ -22,8 +22,8 @@ This test directory is sturctured as follows:
|
||||
|
|
||||
+- php PHP unit tests
|
||||
+- python Python unit tests
|
||||
+- scenes Geometry test data
|
||||
+- testdb Base data for generating API test database
|
||||
+- testdata Additional test data used by unit tests
|
||||
```
|
||||
|
||||
## PHP Unit Tests (`test/php`)
|
||||
|
||||
332
docs/develop/Tokenizers.md
Normal file
332
docs/develop/Tokenizers.md
Normal file
@@ -0,0 +1,332 @@
|
||||
# Tokenizers
|
||||
|
||||
The tokenizer is the component of Nominatim that is responsible for
|
||||
analysing names of OSM objects and queries. Nominatim provides different
|
||||
tokenizers that use different strategies for normalisation. This page describes
|
||||
how tokenizers are expected to work and the public API that needs to be
|
||||
implemented when creating a new tokenizer. For information on how to configure
|
||||
a specific tokenizer for a database see the
|
||||
[tokenizer chapter in the Customization Guide](../customize/Tokenizers.md).
|
||||
|
||||
## Generic Architecture
|
||||
|
||||
### About Search Tokens
|
||||
|
||||
Search in Nominatim is organised around search tokens. Such a token represents
|
||||
string that can be part of the search query. Tokens are used so that the search
|
||||
index does not need to be organised around strings. Instead the database saves
|
||||
for each place which tokens match this place's name, address, house number etc.
|
||||
To be able to distinguish between these different types of information stored
|
||||
with the place, a search token also always has a certain type: name, house number,
|
||||
postcode etc.
|
||||
|
||||
During search an incoming query is transformed into a ordered list of such
|
||||
search tokens (or rather many lists, see below) and this list is then converted
|
||||
into a database query to find the right place.
|
||||
|
||||
It is the core task of the tokenizer to create, manage and assign the search
|
||||
tokens. The tokenizer is involved in two distinct operations:
|
||||
|
||||
* __at import time__: scanning names of OSM objects, normalizing them and
|
||||
building up the list of search tokens.
|
||||
* __at query time__: scanning the query and returning the appropriate search
|
||||
tokens.
|
||||
|
||||
|
||||
### Importing
|
||||
|
||||
The indexer is responsible to enrich an OSM object (or place) with all data
|
||||
required for geocoding. It is split into two parts: the controller collects
|
||||
the places that require updating, enriches the place information as required
|
||||
and hands the place to Postgresql. The collector is part of the Nominatim
|
||||
library written in Python. Within Postgresql, the `placex_update`
|
||||
trigger is responsible to fill out all secondary tables with extra geocoding
|
||||
information. This part is written in PL/pgSQL.
|
||||
|
||||
The tokenizer is involved in both parts. When the indexer prepares a place,
|
||||
it hands it over to the tokenizer to inspect the names and create all the
|
||||
search tokens applicable for the place. This usually involves updating the
|
||||
tokenizer's internal token lists and creating a list of all token IDs for
|
||||
the specific place. This list is later needed in the PL/pgSQL part where the
|
||||
indexer needs to add the token IDs to the appropriate search tables. To be
|
||||
able to communicate the list between the Python part and the pl/pgSQL trigger,
|
||||
the `placex` table contains a special JSONB column `token_info` which is there
|
||||
for the exclusive use of the tokenizer.
|
||||
|
||||
The Python part of the tokenizer returns a structured information about the
|
||||
tokens of a place to the indexer which converts it to JSON and inserts it into
|
||||
the `token_info` column. The content of the column is then handed to the PL/pqSQL
|
||||
callbacks of the tokenizer which extracts the required information. Usually
|
||||
the tokenizer then removes all information from the `token_info` structure,
|
||||
so that no information is ever persistently saved in the table. All information
|
||||
that went in should have been processed after all and put into secondary tables.
|
||||
This is however not a hard requirement. If the tokenizer needs to store
|
||||
additional information about a place permanently, it may do so in the
|
||||
`token_info` column. It just may never execute searches over it and
|
||||
consequently not create any special indexes on it.
|
||||
|
||||
### Querying
|
||||
|
||||
At query time, Nominatim builds up multiple _interpretations_ of the search
|
||||
query. Each of these interpretations is tried against the database in order
|
||||
of the likelihood with which they match to the search query. The first
|
||||
interpretation that yields results wins.
|
||||
|
||||
The interpretations are encapsulated in the `SearchDescription` class. An
|
||||
instance of this class is created by applying a sequence of
|
||||
_search tokens_ to an initially empty SearchDescription. It is the
|
||||
responsibility of the tokenizer to parse the search query and derive all
|
||||
possible sequences of search tokens. To that end the tokenizer needs to parse
|
||||
the search query and look up matching words in its own data structures.
|
||||
|
||||
## Tokenizer API
|
||||
|
||||
The following section describes the functions that need to be implemented
|
||||
for a custom tokenizer implementation.
|
||||
|
||||
!!! warning
|
||||
This API is currently in early alpha status. While this API is meant to
|
||||
be a public API on which other tokenizers may be implemented, the API is
|
||||
far away from being stable at the moment.
|
||||
|
||||
### Directory Structure
|
||||
|
||||
Nominatim expects two files for a tokenizer:
|
||||
|
||||
* `nominatim/tokenizer/<NAME>_tokenizer.py` containing the Python part of the
|
||||
implementation
|
||||
* `lib-php/tokenizer/<NAME>_tokenizer.php` with the PHP part of the
|
||||
implementation
|
||||
|
||||
where `<NAME>` is a unique name for the tokenizer consisting of only lower-case
|
||||
letters, digits and underscore. A tokenizer also needs to install some SQL
|
||||
functions. By convention, these should be placed in `lib-sql/tokenizer`.
|
||||
|
||||
If the tokenizer has a default configuration file, this should be saved in
|
||||
the `settings/<NAME>_tokenizer.<SUFFIX>`.
|
||||
|
||||
### Configuration and Persistence
|
||||
|
||||
Tokenizers may define custom settings for their configuration. All settings
|
||||
must be prefixed with `NOMINATIM_TOKENIZER_`. Settings may be transient or
|
||||
persistent. Transient settings are loaded from the configuration file when
|
||||
Nominatim is started and may thus be changed at any time. Persistent settings
|
||||
are tied to a database installation and must only be read during installation
|
||||
time. If they are needed for the runtime then they must be saved into the
|
||||
`nominatim_properties` table and later loaded from there.
|
||||
|
||||
### The Python module
|
||||
|
||||
The Python module is expect to export a single factory function:
|
||||
|
||||
```python
|
||||
def create(dsn: str, data_dir: Path) -> AbstractTokenizer
|
||||
```
|
||||
|
||||
The `dsn` parameter contains the DSN of the Nominatim database. The `data_dir`
|
||||
is a directory in the project directory that the tokenizer may use to save
|
||||
database-specific data. The function must return the instance of the tokenizer
|
||||
class as defined below.
|
||||
|
||||
### Python Tokenizer Class
|
||||
|
||||
All tokenizers must inherit from `nominatim.tokenizer.base.AbstractTokenizer`
|
||||
and implement the abstract functions defined there.
|
||||
|
||||
::: nominatim.tokenizer.base.AbstractTokenizer
|
||||
rendering:
|
||||
heading_level: 4
|
||||
|
||||
### Python Analyzer Class
|
||||
|
||||
::: nominatim.tokenizer.base.AbstractAnalyzer
|
||||
rendering:
|
||||
heading_level: 4
|
||||
|
||||
### PL/pgSQL Functions
|
||||
|
||||
The tokenizer must provide access functions for the `token_info` column
|
||||
to the indexer which extracts the necessary information for the global
|
||||
search tables. If the tokenizer needs additional SQL functions for private
|
||||
use, then these functions must be prefixed with `token_` in order to ensure
|
||||
that there are no naming conflicts with the SQL indexer code.
|
||||
|
||||
The following functions are expected:
|
||||
|
||||
```sql
|
||||
FUNCTION token_get_name_search_tokens(info JSONB) RETURNS INTEGER[]
|
||||
```
|
||||
|
||||
Return an array of token IDs of search terms that should match
|
||||
the name(s) for the given place. These tokens are used to look up the place
|
||||
by name and, where the place functions as part of an address for another place,
|
||||
by address. Must return NULL when the place has no name.
|
||||
|
||||
```sql
|
||||
FUNCTION token_get_name_match_tokens(info JSONB) RETURNS INTEGER[]
|
||||
```
|
||||
|
||||
Return an array of token IDs of full names of the place that should be used
|
||||
to match addresses. The list of match tokens is usually more strict than
|
||||
search tokens as it is used to find a match between two OSM tag values which
|
||||
are expected to contain matching full names. Partial terms should not be
|
||||
used for match tokens. Must return NULL when the place has no name.
|
||||
|
||||
```sql
|
||||
FUNCTION token_get_housenumber_search_tokens(info JSONB) RETURNS INTEGER[]
|
||||
```
|
||||
|
||||
Return an array of token IDs of house number tokens that apply to the place.
|
||||
Note that a place may have multiple house numbers, for example when apartments
|
||||
each have their own number. Must be NULL when the place has no house numbers.
|
||||
|
||||
```sql
|
||||
FUNCTION token_normalized_housenumber(info JSONB) RETURNS TEXT
|
||||
```
|
||||
|
||||
Return the house number(s) in the normalized form that can be matched against
|
||||
a house number token text. If a place has multiple house numbers they must
|
||||
be listed with a semicolon as delimiter. Must be NULL when the place has no
|
||||
house numbers.
|
||||
|
||||
```sql
|
||||
FUNCTION token_matches_street(info JSONB, street_tokens INTEGER[]) RETURNS BOOLEAN
|
||||
```
|
||||
|
||||
Check if the given tokens (previously saved from `token_get_name_match_tokens()`)
|
||||
match against the `addr:street` tag name. Must return either NULL or FALSE
|
||||
when the place has no `addr:street` tag.
|
||||
|
||||
```sql
|
||||
FUNCTION token_matches_place(info JSONB, place_tokens INTEGER[]) RETURNS BOOLEAN
|
||||
```
|
||||
|
||||
Check if the given tokens (previously saved from `token_get_name_match_tokens()`)
|
||||
match against the `addr:place` tag name. Must return either NULL or FALSE
|
||||
when the place has no `addr:place` tag.
|
||||
|
||||
|
||||
```sql
|
||||
FUNCTION token_addr_place_search_tokens(info JSONB) RETURNS INTEGER[]
|
||||
```
|
||||
|
||||
Return the search token IDs extracted from the `addr:place` tag. These tokens
|
||||
are used for searches by address when no matching place can be found in the
|
||||
database. Must be NULL when the place has no `addr:place` tag.
|
||||
|
||||
```sql
|
||||
FUNCTION token_get_address_keys(info JSONB) RETURNS SETOF TEXT
|
||||
```
|
||||
|
||||
Return the set of keys for which address information is provided. This
|
||||
should correspond to the list of (relevant) `addr:*` tags with the `addr:`
|
||||
prefix removed or the keys used in the `address` dictionary of the place info.
|
||||
|
||||
```sql
|
||||
FUNCTION token_get_address_search_tokens(info JSONB, key TEXT) RETURNS INTEGER[]
|
||||
```
|
||||
|
||||
Return the array of search tokens for the given address part. `key` can be
|
||||
expected to be one of those returned with `token_get_address_keys()`. The
|
||||
search tokens are added to the address search vector of the place, when no
|
||||
corresponding OSM object could be found for the given address part from which
|
||||
to copy the name information.
|
||||
|
||||
```sql
|
||||
FUNCTION token_matches_address(info JSONB, key TEXT, tokens INTEGER[])
|
||||
```
|
||||
|
||||
Check if the given tokens match against the address part `key`.
|
||||
|
||||
__Warning:__ the tokens that are handed in are the lists previously saved
|
||||
from `token_get_name_search_tokens()`, _not_ from the match token list. This
|
||||
is an historical oddity which will be fixed at some point in the future.
|
||||
Currently, tokenizers are encouraged to make sure that matching works against
|
||||
both the search token list and the match token list.
|
||||
|
||||
```sql
|
||||
FUNCTION token_get_postcode(info JSONB) RETURNS TEXT
|
||||
```
|
||||
|
||||
Return the postcode for the object, if any exists. The postcode must be in
|
||||
the form that should also be presented to the end-user.
|
||||
|
||||
```sql
|
||||
FUNCTION token_strip_info(info JSONB) RETURNS JSONB
|
||||
```
|
||||
|
||||
Return the part of the `token_info` field that should be stored in the database
|
||||
permanently. The indexer calls this function when all processing is done and
|
||||
replaces the content of the `token_info` column with the returned value before
|
||||
the trigger stores the information in the database. May return NULL if no
|
||||
information should be stored permanently.
|
||||
|
||||
### PHP Tokenizer class
|
||||
|
||||
The PHP tokenizer class is instantiated once per request and responsible for
|
||||
analyzing the incoming query. Multiple requests may be in flight in
|
||||
parallel.
|
||||
|
||||
The class is expected to be found under the
|
||||
name of `\Nominatim\Tokenizer`. To find the class the PHP code includes the file
|
||||
`tokenizer/tokenizer.php` in the project directory. This file must be created
|
||||
when the tokenizer is first set up on import. The file should initialize any
|
||||
configuration variables by setting PHP constants and then require the file
|
||||
with the actual implementation of the tokenizer.
|
||||
|
||||
The tokenizer class must implement the following functions:
|
||||
|
||||
```php
|
||||
public function __construct(object &$oDB)
|
||||
```
|
||||
|
||||
The constructor of the class receives a database connection that can be used
|
||||
to query persistent data in the database.
|
||||
|
||||
```php
|
||||
public function checkStatus()
|
||||
```
|
||||
|
||||
Check that the tokenizer can access its persistent data structures. If there
|
||||
is an issue, throw an `\Exception`.
|
||||
|
||||
```php
|
||||
public function normalizeString(string $sTerm) : string
|
||||
```
|
||||
|
||||
Normalize string to a form to be used for comparisons when reordering results.
|
||||
Nominatim reweighs results how well the final display string matches the actual
|
||||
query. Before comparing result and query, names and query are normalised against
|
||||
this function. The tokenizer can thus remove all properties that should not be
|
||||
taken into account for reweighing, e.g. special characters or case.
|
||||
|
||||
```php
|
||||
public function tokensForSpecialTerm(string $sTerm) : array
|
||||
```
|
||||
|
||||
Return the list of special term tokens that match the given term.
|
||||
|
||||
```php
|
||||
public function extractTokensFromPhrases(array &$aPhrases) : TokenList
|
||||
```
|
||||
|
||||
Parse the given phrases, splitting them into word lists and retrieve the
|
||||
matching tokens.
|
||||
|
||||
The phrase array may take on two forms. In unstructured searches (using `q=`
|
||||
parameter) the search query is split at the commas and the elements are
|
||||
put into a sorted list. For structured searches the phrase array is an
|
||||
associative array where the key designates the type of the term (street, city,
|
||||
county etc.) The tokenizer may ignore the phrase type at this stage in parsing.
|
||||
Matching phrase type and appropriate search token type will be done later
|
||||
when the SearchDescription is built.
|
||||
|
||||
For each phrase in the list of phrases, the function must analyse the phrase
|
||||
string and then call `setWordSets()` to communicate the result of the analysis.
|
||||
A word set is a list of strings, where each string refers to a search token.
|
||||
A phrase may have multiple interpretations. Therefore a list of word sets is
|
||||
usually attached to the phrase. The search tokens themselves are returned
|
||||
by the function in an associative array, where the key corresponds to the
|
||||
strings given in the word sets. The value is a list of search tokens. Thus
|
||||
a single string in the list of word sets may refer to multiple search tokens.
|
||||
|
||||
35
docs/develop/address-tables.plantuml
Normal file
35
docs/develop/address-tables.plantuml
Normal file
@@ -0,0 +1,35 @@
|
||||
@startuml
|
||||
skinparam monochrome true
|
||||
skinparam ObjectFontStyle bold
|
||||
|
||||
map search_name_X {
|
||||
place_id => BIGINT
|
||||
address_rank => SMALLINT
|
||||
name_vector => INT[]
|
||||
centroid => GEOMETRY
|
||||
}
|
||||
|
||||
map location_area_large_X {
|
||||
place_id => BIGINT
|
||||
keywords => INT[]
|
||||
partition => SMALLINT
|
||||
rank_search => SMALLINT
|
||||
rank_address => SMALLINT
|
||||
country_code => VARCHR(2)
|
||||
isguess => BOOLEAN
|
||||
postcode => TEXT
|
||||
centroid => POINT
|
||||
geometry => GEOMETRY
|
||||
}
|
||||
|
||||
map location_road_X {
|
||||
place_id => BIGINT
|
||||
partition => SMALLINT
|
||||
country_code => VARCHR(2)
|
||||
geometry => GEOMETRY
|
||||
}
|
||||
|
||||
search_name_X -[hidden]> location_area_large_X
|
||||
location_area_large_X -[hidden]> location_road_X
|
||||
|
||||
@enduml
|
||||
47
docs/develop/address-tables.svg
Normal file
47
docs/develop/address-tables.svg
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 11 KiB |
@@ -13,7 +13,7 @@ More details in [osm-search/country-grid-data](https://github.com/osm-search/cou
|
||||
|
||||
## US Census TIGER
|
||||
|
||||
For the United States you can choose to import additonal street-level data.
|
||||
For the United States you can choose to import additional street-level data.
|
||||
The data isn't mixed into OSM data but queried as fallback when no OSM
|
||||
result can be found.
|
||||
|
||||
|
||||
44
docs/develop/osm2pgsql-tables.plantuml
Normal file
44
docs/develop/osm2pgsql-tables.plantuml
Normal file
@@ -0,0 +1,44 @@
|
||||
@startuml
|
||||
skinparam monochrome true
|
||||
skinparam ObjectFontStyle bold
|
||||
|
||||
map planet_osm_nodes #eee {
|
||||
id => BIGINT
|
||||
lat => INT
|
||||
lon => INT
|
||||
}
|
||||
|
||||
map planet_osm_ways #eee {
|
||||
id => BIGINT
|
||||
nodes => BIGINT[]
|
||||
tags => TEXT[]
|
||||
}
|
||||
|
||||
map planet_osm_rels #eee {
|
||||
id => BIGINT
|
||||
parts => BIGINT[]
|
||||
members => TEXT[]
|
||||
tags => TEXT[]
|
||||
way_off => SMALLINT
|
||||
rel_off => SMALLINT
|
||||
}
|
||||
|
||||
map place {
|
||||
osm_type => CHAR(1)
|
||||
osm_id => BIGINT
|
||||
class => TEXT
|
||||
type => TEXT
|
||||
name => HSTORE
|
||||
address => HSTORE
|
||||
extratags => HSTORE
|
||||
admin_level => SMALLINT
|
||||
geometry => GEOMETRY
|
||||
}
|
||||
|
||||
planet_osm_nodes -[hidden]> planet_osm_ways
|
||||
planet_osm_ways -[hidden]> planet_osm_rels
|
||||
planet_osm_ways -[hidden]-> place
|
||||
|
||||
planet_osm_nodes::id <- planet_osm_ways::nodes
|
||||
|
||||
@enduml
|
||||
58
docs/develop/osm2pgsql-tables.svg
Normal file
58
docs/develop/osm2pgsql-tables.svg
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 13 KiB |
31
docs/develop/parenting-flow.plantuml
Normal file
31
docs/develop/parenting-flow.plantuml
Normal file
@@ -0,0 +1,31 @@
|
||||
@startuml
|
||||
skinparam monochrome true
|
||||
|
||||
start
|
||||
|
||||
if (has 'addr:street'?) then (yes)
|
||||
if (street with that name\n nearby?) then (yes)
|
||||
:**Use closest street**
|
||||
**with same name**;
|
||||
kill
|
||||
else (no)
|
||||
:** Use closest**\n**street**;
|
||||
kill
|
||||
endif
|
||||
elseif (has 'addr:place'?) then (yes)
|
||||
if (place with that name\n nearby?) then (yes)
|
||||
:**Use closest place**
|
||||
**with same name**;
|
||||
kill
|
||||
else (no)
|
||||
:add addr:place to adress;
|
||||
:**Use closest place**\n**rank 16 to 25**;
|
||||
kill
|
||||
endif
|
||||
else (otherwise)
|
||||
:**Use closest**\n**street**;
|
||||
kill
|
||||
endif
|
||||
|
||||
|
||||
@enduml
|
||||
41
docs/develop/parenting-flow.svg
Normal file
41
docs/develop/parenting-flow.svg
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 9.8 KiB |
99
docs/develop/search-tables.plantuml
Normal file
99
docs/develop/search-tables.plantuml
Normal file
@@ -0,0 +1,99 @@
|
||||
@startuml
|
||||
skinparam monochrome true
|
||||
skinparam ObjectFontStyle bold
|
||||
|
||||
left to right direction
|
||||
|
||||
map placex {
|
||||
place_id => BIGINT
|
||||
osm_type => CHAR(1)
|
||||
osm_id => BIGINT
|
||||
class => TEXT
|
||||
type => TEXT
|
||||
name => HSTORE
|
||||
address => HSTORE
|
||||
extratags => HSTORE
|
||||
admin_level => SMALLINT
|
||||
partition => SMALLINT
|
||||
geometry_sector => INT
|
||||
parent_place_id => BIGINT
|
||||
linked_place_id => BIGINT
|
||||
importance => DOUBLE
|
||||
rank_search => SMALLINT
|
||||
rank_address => SMALLINT
|
||||
wikipedia => TEXT
|
||||
country_code => VARCHAR(2)
|
||||
housenumber => TEXT
|
||||
postcode => TEXT
|
||||
indexed_status => SMALLINT
|
||||
indexed_date => TIMESTAMP
|
||||
centroid => GEOMETRY
|
||||
geometry => GEOMETRY
|
||||
}
|
||||
|
||||
map search_name {
|
||||
place_id => BIGINT
|
||||
importance => DOUBLE
|
||||
search_rank => SMALLINT
|
||||
address_rank => SMALLINT
|
||||
name_vector => INT[]
|
||||
nameaddress_vector => INT[]
|
||||
country_code => VARCHAR(2)
|
||||
centroid => GEOMETRY
|
||||
}
|
||||
|
||||
map word {
|
||||
word_id => INT
|
||||
word_token => TEXT
|
||||
... =>
|
||||
}
|
||||
|
||||
map location_property_osmline {
|
||||
place_id => BIGINT
|
||||
osm_id => BIGINT
|
||||
startnumber => INT
|
||||
endnumber => INT
|
||||
interpolationtype => TEXT
|
||||
address => HSTORE
|
||||
partition => SMALLINT
|
||||
geometry_sector => INT
|
||||
parent_place_id => BIGINT
|
||||
country_code => VARCHAR(2)
|
||||
postcode => text
|
||||
indexed_status => SMALLINT
|
||||
indexed_date => TIMESTAMP
|
||||
linegeo => GEOMETRY
|
||||
}
|
||||
|
||||
map place_addressline {
|
||||
place_id => BIGINT
|
||||
address_place_id => BIGINT
|
||||
distance => DOUBLE
|
||||
cached_rank_address => SMALLINT
|
||||
fromarea => BOOLEAN
|
||||
isaddress => BOOLEAN
|
||||
}
|
||||
|
||||
map location_postcode {
|
||||
place_id => BIGINT
|
||||
postcode => TEXT
|
||||
parent_place_id => BIGINT
|
||||
rank_search => SMALLINT
|
||||
rank_address => SMALLINT
|
||||
indexed_status => SMALLINT
|
||||
indexed_date => TIMESTAMP
|
||||
geometry => GEOMETRY
|
||||
}
|
||||
|
||||
placex::place_id <-- search_name::place_id
|
||||
placex::place_id <-- place_addressline::place_id
|
||||
placex::place_id <-- place_addressline::address_place_id
|
||||
|
||||
search_name::name_vector --> word::word_id
|
||||
search_name::nameaddress_vector --> word::word_id
|
||||
|
||||
place_addressline -[hidden]> location_property_osmline
|
||||
search_name -[hidden]> place_addressline
|
||||
location_property_osmline -[hidden]-> location_postcode
|
||||
|
||||
@enduml
|
||||
117
docs/develop/search-tables.svg
Normal file
117
docs/develop/search-tables.svg
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 35 KiB |
@@ -13,3 +13,12 @@ th, td {
|
||||
th {
|
||||
background-color: #eee;
|
||||
}
|
||||
|
||||
.doc-object h6 {
|
||||
margin-bottom: 0.8em;
|
||||
font-size: 120%;
|
||||
}
|
||||
|
||||
.doc-object {
|
||||
margin-bottom: 1.3em;
|
||||
}
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
Nominatim (from the Latin, 'by name') is a tool to search OSM data by name and address and to generate synthetic addresses of OSM points (reverse geocoding).
|
||||
|
||||
This guide comes in three parts:
|
||||
This guide comes in four parts:
|
||||
|
||||
* __[API reference](api/Overview.md)__ for users of Nominatim
|
||||
* __[Administration Guide](admin/Installation.md)__ for those who want
|
||||
to install their own Nominatim server
|
||||
* __[Customization Guide](customize/Overview.md)__ for those who want to
|
||||
adapt their own installation to their special requirements
|
||||
* __[Developer's Guide](develop/overview.md)__ for developers of the software
|
||||
|
||||
@@ -3,7 +3,7 @@ theme: readthedocs
|
||||
docs_dir: ${CMAKE_CURRENT_BINARY_DIR}
|
||||
site_url: https://nominatim.org
|
||||
repo_url: https://github.com/openstreetmap/Nominatim
|
||||
pages:
|
||||
nav:
|
||||
- 'Introduction' : 'index.md'
|
||||
- 'API Reference':
|
||||
- 'Overview': 'api/Overview.md'
|
||||
@@ -19,28 +19,47 @@ pages:
|
||||
- 'Import' : 'admin/Import.md'
|
||||
- 'Update' : 'admin/Update.md'
|
||||
- 'Deploy' : 'admin/Deployment.md'
|
||||
- 'Customize Imports' : 'admin/Customization.md'
|
||||
- 'Tokenizers' : 'admin/Tokenizers.md'
|
||||
- 'Nominatim UI' : 'admin/Setup-Nominatim-UI.md'
|
||||
- 'Advanced Installations' : 'admin/Advanced-Installations.md'
|
||||
- 'Maintenance' : 'admin/Maintenance.md'
|
||||
- 'Migration from older Versions' : 'admin/Migration.md'
|
||||
- 'Troubleshooting' : 'admin/Faq.md'
|
||||
- 'Customization Guide':
|
||||
- 'Overview': 'customize/Overview.md'
|
||||
- 'Import Styles': 'customize/Import-Styles.md'
|
||||
- 'Configuration Settings': 'customize/Settings.md'
|
||||
- 'Per-Country Data': 'customize/Country-Settings.md'
|
||||
- 'Place Ranking' : 'customize/Ranking.md'
|
||||
- 'Importance' : 'customize/Importance.md'
|
||||
- 'Tokenizers' : 'customize/Tokenizers.md'
|
||||
- 'Special Phrases': 'customize/Special-Phrases.md'
|
||||
- 'External data: US housenumbers from TIGER': 'customize/Tiger.md'
|
||||
- 'External data: Postcodes': 'customize/Postcodes.md'
|
||||
- 'Developers Guide':
|
||||
- 'Setup for Development' : 'develop/Development-Environment.md'
|
||||
- 'Architecture Overview' : 'develop/overview.md'
|
||||
- 'OSM Data Import' : 'develop/Import.md'
|
||||
- 'Place Ranking' : 'develop/Ranking.md'
|
||||
- 'Postcodes' : 'develop/Postcodes.md'
|
||||
- 'Database Layout' : 'develop/Database-Layout.md'
|
||||
- 'Indexing' : 'develop/Indexing.md'
|
||||
- 'Tokenizers' : 'develop/Tokenizers.md'
|
||||
- 'Custom modules for ICU tokenizer': 'develop/ICU-Tokenizer-Modules.md'
|
||||
- 'Setup for Development' : 'develop/Development-Environment.md'
|
||||
- 'Testing' : 'develop/Testing.md'
|
||||
- 'External Data Sources': 'develop/data-sources.md'
|
||||
- 'Appendix':
|
||||
- 'Installation on CentOS 7' : 'appendix/Install-on-Centos-7.md'
|
||||
- 'Installation on CentOS 8' : 'appendix/Install-on-Centos-8.md'
|
||||
- 'Installation on Ubuntu 18' : 'appendix/Install-on-Ubuntu-18.md'
|
||||
- 'Installation on Ubuntu 20' : 'appendix/Install-on-Ubuntu-20.md'
|
||||
- 'Installation on Ubuntu 22' : 'appendix/Install-on-Ubuntu-22.md'
|
||||
markdown_extensions:
|
||||
- codehilite
|
||||
- admonition
|
||||
- def_list
|
||||
- toc:
|
||||
permalink:
|
||||
extra_css: [extra.css, styles.css]
|
||||
plugins:
|
||||
- search
|
||||
- mkdocstrings:
|
||||
handlers:
|
||||
python-legacy:
|
||||
rendering:
|
||||
show_source: false
|
||||
show_signature_annotations: false
|
||||
|
||||
@@ -1,4 +1,12 @@
|
||||
<?php
|
||||
/**
|
||||
* SPDX-License-Identifier: GPL-2.0-only
|
||||
*
|
||||
* This file is part of Nominatim. (https://nominatim.org)
|
||||
*
|
||||
* Copyright (C) 2022 by the Nominatim developer community.
|
||||
* For a full list of authors see the git log.
|
||||
*/
|
||||
|
||||
namespace Nominatim;
|
||||
|
||||
@@ -84,6 +92,10 @@ class AddressDetails
|
||||
|| $aLine['class'] == 'place')
|
||||
) {
|
||||
$aAddress[$sTypeLabel] = $sName;
|
||||
|
||||
if (!empty($aLine['name'])) {
|
||||
$this->addSubdivisionCode($aAddress, $aLine['admin_level'], $aLine['name']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -166,4 +178,14 @@ class AddressDetails
|
||||
{
|
||||
return $this->aAddressLines;
|
||||
}
|
||||
|
||||
private function addSubdivisionCode(&$aAddress, $iAdminLevel, $nameDetails)
|
||||
{
|
||||
if (is_string($nameDetails)) {
|
||||
$nameDetails = json_decode('{' . str_replace('"=>"', '":"', $nameDetails) . '}', true);
|
||||
}
|
||||
if (!empty($nameDetails['ISO3166-2'])) {
|
||||
$aAddress["ISO3166-2-lvl$iAdminLevel"] = $nameDetails['ISO3166-2'];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,12 @@
|
||||
<?php
|
||||
/**
|
||||
* SPDX-License-Identifier: GPL-2.0-only
|
||||
*
|
||||
* This file is part of Nominatim. (https://nominatim.org)
|
||||
*
|
||||
* Copyright (C) 2022 by the Nominatim developer community.
|
||||
* For a full list of authors see the git log.
|
||||
*/
|
||||
|
||||
namespace Nominatim\ClassTypes;
|
||||
|
||||
|
||||
@@ -1,4 +1,12 @@
|
||||
<?php
|
||||
/**
|
||||
* SPDX-License-Identifier: GPL-2.0-only
|
||||
*
|
||||
* This file is part of Nominatim. (https://nominatim.org)
|
||||
*
|
||||
* Copyright (C) 2022 by the Nominatim developer community.
|
||||
* For a full list of authors see the git log.
|
||||
*/
|
||||
|
||||
namespace Nominatim;
|
||||
|
||||
@@ -38,6 +46,9 @@ class DB
|
||||
|
||||
$conn->exec("SET DateStyle TO 'sql,european'");
|
||||
$conn->exec("SET client_encoding TO 'utf-8'");
|
||||
// Disable JIT and parallel workers. They interfere badly with search SQL.
|
||||
$conn->exec("UPDATE pg_settings SET setting = -1 WHERE name = 'jit_above_cost'");
|
||||
$conn->exec("UPDATE pg_settings SET setting = 0 WHERE name = 'max_parallel_workers_per_gather'");
|
||||
$iMaxExecution = ini_get('max_execution_time');
|
||||
if ($iMaxExecution > 0) {
|
||||
$conn->setAttribute(\PDO::ATTR_TIMEOUT, $iMaxExecution); // seconds
|
||||
|
||||
@@ -1,4 +1,12 @@
|
||||
<?php
|
||||
/**
|
||||
* SPDX-License-Identifier: GPL-2.0-only
|
||||
*
|
||||
* This file is part of Nominatim. (https://nominatim.org)
|
||||
*
|
||||
* Copyright (C) 2022 by the Nominatim developer community.
|
||||
* For a full list of authors see the git log.
|
||||
*/
|
||||
|
||||
namespace Nominatim;
|
||||
|
||||
|
||||
@@ -1,4 +1,12 @@
|
||||
<?php
|
||||
/**
|
||||
* SPDX-License-Identifier: GPL-2.0-only
|
||||
*
|
||||
* This file is part of Nominatim. (https://nominatim.org)
|
||||
*
|
||||
* Copyright (C) 2022 by the Nominatim developer community.
|
||||
* For a full list of authors see the git log.
|
||||
*/
|
||||
|
||||
namespace Nominatim;
|
||||
|
||||
@@ -127,7 +135,7 @@ class Debug
|
||||
|
||||
public static function printSQL($sSQL)
|
||||
{
|
||||
echo '<p><tt><font color="#aaa">'.$sSQL.'</font></tt></p>'."\n";
|
||||
echo '<p><tt><font color="#aaa">'.htmlspecialchars($sSQL, ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401).'</font></tt></p>'."\n";
|
||||
}
|
||||
|
||||
private static function outputVar($mVar, $sPreNL)
|
||||
@@ -170,11 +178,12 @@ class Debug
|
||||
}
|
||||
|
||||
if (is_string($mVar)) {
|
||||
echo "'$mVar'";
|
||||
return strlen($mVar) + 2;
|
||||
$sOut = "'$mVar'";
|
||||
} else {
|
||||
$sOut = (string)$mVar;
|
||||
}
|
||||
|
||||
echo (string)$mVar;
|
||||
return strlen((string)$mVar);
|
||||
echo htmlspecialchars($sOut, ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401);
|
||||
return strlen($sOut);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,12 @@
|
||||
<?php
|
||||
/**
|
||||
* SPDX-License-Identifier: GPL-2.0-only
|
||||
*
|
||||
* This file is part of Nominatim. (https://nominatim.org)
|
||||
*
|
||||
* Copyright (C) 2022 by the Nominatim developer community.
|
||||
* For a full list of authors see the git log.
|
||||
*/
|
||||
|
||||
namespace Nominatim;
|
||||
|
||||
|
||||
@@ -1,4 +1,12 @@
|
||||
<?php
|
||||
/**
|
||||
* SPDX-License-Identifier: GPL-2.0-only
|
||||
*
|
||||
* This file is part of Nominatim. (https://nominatim.org)
|
||||
*
|
||||
* Copyright (C) 2022 by the Nominatim developer community.
|
||||
* For a full list of authors see the git log.
|
||||
*/
|
||||
|
||||
namespace Nominatim;
|
||||
|
||||
@@ -95,7 +103,7 @@ class Geocode
|
||||
}
|
||||
|
||||
$this->iFinalLimit = $iLimit;
|
||||
$this->iLimit = $iLimit + min($iLimit, 10);
|
||||
$this->iLimit = $iLimit + max($iLimit, 10);
|
||||
}
|
||||
|
||||
public function setFeatureType($sFeatureType)
|
||||
@@ -182,7 +190,7 @@ class Geocode
|
||||
|
||||
$this->bFallback = $oParams->getBool('fallback', $this->bFallback);
|
||||
|
||||
// List of excluded Place IDs - used for more acurate pageing
|
||||
// List of excluded Place IDs - used for more accurate pageing
|
||||
$sExcluded = $oParams->getStringList('exclude_place_ids');
|
||||
if ($sExcluded) {
|
||||
foreach ($sExcluded as $iExcludedPlaceID) {
|
||||
@@ -498,7 +506,6 @@ class Geocode
|
||||
if ($this->aCountryCodes) {
|
||||
$oCtx->setCountryList($this->aCountryCodes);
|
||||
}
|
||||
$this->oTokenizer->setCountryRestriction($this->aCountryCodes);
|
||||
|
||||
Debug::newSection('Query Preprocessing');
|
||||
|
||||
@@ -507,13 +514,6 @@ class Geocode
|
||||
userError('Query string is not UTF-8 encoded.');
|
||||
}
|
||||
|
||||
// Conflicts between US state abreviations and various words for 'the' in different languages
|
||||
if (isset($this->aLangPrefOrder['name:en'])) {
|
||||
$sQuery = preg_replace('/(^|,)\s*il\s*(,|$)/i', '\1illinois\2', $sQuery);
|
||||
$sQuery = preg_replace('/(^|,)\s*al\s*(,|$)/i', '\1alabama\2', $sQuery);
|
||||
$sQuery = preg_replace('/(^|,)\s*la\s*(,|$)/i', '\1louisiana\2', $sQuery);
|
||||
}
|
||||
|
||||
// Do we have anything that looks like a lat/lon pair?
|
||||
$sQuery = $oCtx->setNearPointFromQuery($sQuery);
|
||||
|
||||
@@ -617,16 +617,15 @@ class Geocode
|
||||
}
|
||||
$aReverseGroupedSearches = $this->getGroupedSearches($aSearches, $aPhrases, $oValidTokens);
|
||||
|
||||
foreach ($aGroupedSearches as $aSearches) {
|
||||
foreach ($aReverseGroupedSearches as $aSearches) {
|
||||
foreach ($aSearches as $aSearch) {
|
||||
if (!isset($aReverseGroupedSearches[$aSearch->getRank()])) {
|
||||
$aReverseGroupedSearches[$aSearch->getRank()] = array();
|
||||
if (!isset($aGroupedSearches[$aSearch->getRank()])) {
|
||||
$aGroupedSearches[$aSearch->getRank()] = array();
|
||||
}
|
||||
$aReverseGroupedSearches[$aSearch->getRank()][] = $aSearch;
|
||||
$aGroupedSearches[$aSearch->getRank()][] = $aSearch;
|
||||
}
|
||||
}
|
||||
|
||||
$aGroupedSearches = $aReverseGroupedSearches;
|
||||
ksort($aGroupedSearches);
|
||||
}
|
||||
} else {
|
||||
@@ -844,7 +843,9 @@ class Geocode
|
||||
$aResult['importance'] = 0.001;
|
||||
$aResult['foundorder'] = $aResult['addressimportance'];
|
||||
} else {
|
||||
$aResult['importance'] = max(0.001, $aResult['importance']);
|
||||
if ($aResult['importance'] == 0) {
|
||||
$aResult['importance'] = 0.0001;
|
||||
}
|
||||
$aResult['importance'] *= $this->viewboxImportanceFactor(
|
||||
$aResult['lon'],
|
||||
$aResult['lat']
|
||||
@@ -873,7 +874,7 @@ class Geocode
|
||||
$iCountWords = 0;
|
||||
$sAddress = $aResult['langaddress'];
|
||||
foreach ($aRecheckWords as $i => $sWord) {
|
||||
if (stripos($sAddress, $sWord)!==false) {
|
||||
if (grapheme_stripos($sAddress, $sWord)!==false) {
|
||||
$iCountWords++;
|
||||
if (preg_match('/(^|,)\s*'.preg_quote($sWord, '/').'\s*(,|$)/', $sAddress)) {
|
||||
$iCountWords += 0.1;
|
||||
|
||||
@@ -1,4 +1,12 @@
|
||||
<?php
|
||||
/**
|
||||
* SPDX-License-Identifier: GPL-2.0-only
|
||||
*
|
||||
* This file is part of Nominatim. (https://nominatim.org)
|
||||
*
|
||||
* Copyright (C) 2022 by the Nominatim developer community.
|
||||
* For a full list of authors see the git log.
|
||||
*/
|
||||
|
||||
namespace Nominatim;
|
||||
|
||||
@@ -14,7 +22,10 @@ class ParameterParser
|
||||
|
||||
public function getBool($sName, $bDefault = false)
|
||||
{
|
||||
if (!isset($this->aParams[$sName]) || strlen($this->aParams[$sName]) == 0) {
|
||||
if (!isset($this->aParams[$sName])
|
||||
|| !is_string($this->aParams[$sName])
|
||||
|| strlen($this->aParams[$sName]) == 0
|
||||
) {
|
||||
return $bDefault;
|
||||
}
|
||||
|
||||
@@ -23,7 +34,7 @@ class ParameterParser
|
||||
|
||||
public function getInt($sName, $bDefault = false)
|
||||
{
|
||||
if (!isset($this->aParams[$sName])) {
|
||||
if (!isset($this->aParams[$sName]) || is_array($this->aParams[$sName])) {
|
||||
return $bDefault;
|
||||
}
|
||||
|
||||
@@ -36,7 +47,7 @@ class ParameterParser
|
||||
|
||||
public function getFloat($sName, $bDefault = false)
|
||||
{
|
||||
if (!isset($this->aParams[$sName])) {
|
||||
if (!isset($this->aParams[$sName]) || is_array($this->aParams[$sName])) {
|
||||
return $bDefault;
|
||||
}
|
||||
|
||||
@@ -49,7 +60,10 @@ class ParameterParser
|
||||
|
||||
public function getString($sName, $bDefault = false)
|
||||
{
|
||||
if (!isset($this->aParams[$sName]) || strlen($this->aParams[$sName]) == 0) {
|
||||
if (!isset($this->aParams[$sName])
|
||||
|| !is_string($this->aParams[$sName])
|
||||
|| strlen($this->aParams[$sName]) == 0
|
||||
) {
|
||||
return $bDefault;
|
||||
}
|
||||
|
||||
@@ -58,11 +72,14 @@ class ParameterParser
|
||||
|
||||
public function getSet($sName, $aValues, $sDefault = false)
|
||||
{
|
||||
if (!isset($this->aParams[$sName]) || strlen($this->aParams[$sName]) == 0) {
|
||||
if (!isset($this->aParams[$sName])
|
||||
|| !is_string($this->aParams[$sName])
|
||||
|| strlen($this->aParams[$sName]) == 0
|
||||
) {
|
||||
return $sDefault;
|
||||
}
|
||||
|
||||
if (!in_array($this->aParams[$sName], $aValues)) {
|
||||
if (!in_array($this->aParams[$sName], $aValues, true)) {
|
||||
userError("Parameter '$sName' must be one of: ".join(', ', $aValues));
|
||||
}
|
||||
|
||||
@@ -106,21 +123,27 @@ class ParameterParser
|
||||
}
|
||||
|
||||
foreach ($aLanguages as $sLanguage => $fLanguagePref) {
|
||||
$aLangPrefOrder['name:'.$sLanguage] = 'name:'.$sLanguage;
|
||||
$this->addNameTag($aLangPrefOrder, 'name:'.$sLanguage);
|
||||
}
|
||||
$aLangPrefOrder['name'] = 'name';
|
||||
$aLangPrefOrder['brand'] = 'brand';
|
||||
$this->addNameTag($aLangPrefOrder, 'name');
|
||||
$this->addNameTag($aLangPrefOrder, 'brand');
|
||||
foreach ($aLanguages as $sLanguage => $fLanguagePref) {
|
||||
$aLangPrefOrder['official_name:'.$sLanguage] = 'official_name:'.$sLanguage;
|
||||
$aLangPrefOrder['short_name:'.$sLanguage] = 'short_name:'.$sLanguage;
|
||||
$this->addNameTag($aLangPrefOrder, 'official_name:'.$sLanguage);
|
||||
$this->addNameTag($aLangPrefOrder, 'short_name:'.$sLanguage);
|
||||
}
|
||||
$aLangPrefOrder['official_name'] = 'official_name';
|
||||
$aLangPrefOrder['short_name'] = 'short_name';
|
||||
$aLangPrefOrder['ref'] = 'ref';
|
||||
$aLangPrefOrder['type'] = 'type';
|
||||
$this->addNameTag($aLangPrefOrder, 'official_name');
|
||||
$this->addNameTag($aLangPrefOrder, 'short_name');
|
||||
$this->addNameTag($aLangPrefOrder, 'ref');
|
||||
$this->addNameTag($aLangPrefOrder, 'type');
|
||||
return $aLangPrefOrder;
|
||||
}
|
||||
|
||||
private function addNameTag(&$aLangPrefOrder, $sTag)
|
||||
{
|
||||
$aLangPrefOrder[$sTag] = $sTag;
|
||||
$aLangPrefOrder['_place_'.$sTag] = '_place_'.$sTag;
|
||||
}
|
||||
|
||||
public function hasSetAny($aParamNames)
|
||||
{
|
||||
foreach ($aParamNames as $sName) {
|
||||
|
||||
@@ -1,4 +1,12 @@
|
||||
<?php
|
||||
/**
|
||||
* SPDX-License-Identifier: GPL-2.0-only
|
||||
*
|
||||
* This file is part of Nominatim. (https://nominatim.org)
|
||||
*
|
||||
* Copyright (C) 2022 by the Nominatim developer community.
|
||||
* For a full list of authors see the git log.
|
||||
*/
|
||||
|
||||
namespace Nominatim;
|
||||
|
||||
@@ -9,29 +17,14 @@ namespace Nominatim;
|
||||
*/
|
||||
class Phrase
|
||||
{
|
||||
const MAX_WORDSET_LEN = 20;
|
||||
const MAX_WORDSETS = 100;
|
||||
|
||||
// Complete phrase as a string.
|
||||
// Complete phrase as a string (guaranteed to have no leading or trailing
|
||||
// spaces).
|
||||
private $sPhrase;
|
||||
// Element type for structured searches.
|
||||
private $sPhraseType;
|
||||
// Possible segmentations of the phrase.
|
||||
private $aWordSets;
|
||||
|
||||
public static function cmpByArraylen($aA, $aB)
|
||||
{
|
||||
$iALen = count($aA);
|
||||
$iBLen = count($aB);
|
||||
|
||||
if ($iALen == $iBLen) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return ($iALen < $iBLen) ? -1 : 1;
|
||||
}
|
||||
|
||||
|
||||
public function __construct($sPhrase, $sPhraseType)
|
||||
{
|
||||
$this->sPhrase = trim($sPhrase);
|
||||
@@ -39,7 +32,7 @@ class Phrase
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the orginal phrase of the string.
|
||||
* Get the original phrase of the string.
|
||||
*/
|
||||
public function getPhrase()
|
||||
{
|
||||
@@ -57,6 +50,11 @@ class Phrase
|
||||
return $this->sPhraseType;
|
||||
}
|
||||
|
||||
public function setWordSets($aWordSets)
|
||||
{
|
||||
$this->aWordSets = $aWordSets;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the array of possible segmentations of the phrase.
|
||||
*
|
||||
@@ -80,61 +78,6 @@ class Phrase
|
||||
}
|
||||
}
|
||||
|
||||
public function computeWordSets($aWords, $oTokens)
|
||||
{
|
||||
$iNumWords = count($aWords);
|
||||
|
||||
if ($iNumWords == 0) {
|
||||
$this->aWordSets = null;
|
||||
return;
|
||||
}
|
||||
|
||||
// Caches the word set for the partial phrase up to word i.
|
||||
$aSetCache = array_fill(0, $iNumWords, array());
|
||||
|
||||
// Initialise first element of cache. There can only be the word.
|
||||
if ($oTokens->containsAny($aWords[0])) {
|
||||
$aSetCache[0][] = array($aWords[0]);
|
||||
}
|
||||
|
||||
// Now do the next elements using what we already have.
|
||||
for ($i = 1; $i < $iNumWords; $i++) {
|
||||
for ($j = $i; $j > 0; $j--) {
|
||||
$sPartial = $j == $i ? $aWords[$j] : $aWords[$j].' '.$sPartial;
|
||||
if (!empty($aSetCache[$j - 1]) && $oTokens->containsAny($sPartial)) {
|
||||
$aPartial = array($sPartial);
|
||||
foreach ($aSetCache[$j - 1] as $aSet) {
|
||||
if (count($aSet) < Phrase::MAX_WORDSET_LEN) {
|
||||
$aSetCache[$i][] = array_merge($aSet, $aPartial);
|
||||
}
|
||||
}
|
||||
if (count($aSetCache[$i]) > 2 * Phrase::MAX_WORDSETS) {
|
||||
usort(
|
||||
$aSetCache[$i],
|
||||
array('\Nominatim\Phrase', 'cmpByArraylen')
|
||||
);
|
||||
$aSetCache[$i] = array_slice(
|
||||
$aSetCache[$i],
|
||||
0,
|
||||
Phrase::MAX_WORDSETS
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// finally the current full phrase
|
||||
$sPartial = $aWords[0].' '.$sPartial;
|
||||
if ($oTokens->containsAny($sPartial)) {
|
||||
$aSetCache[$i][] = array($sPartial);
|
||||
}
|
||||
}
|
||||
|
||||
$this->aWordSets = $aSetCache[$iNumWords - 1];
|
||||
usort($this->aWordSets, array('\Nominatim\Phrase', 'cmpByArraylen'));
|
||||
$this->aWordSets = array_slice($this->aWordSets, 0, Phrase::MAX_WORDSETS);
|
||||
}
|
||||
|
||||
|
||||
public function debugInfo()
|
||||
{
|
||||
return array(
|
||||
|
||||
@@ -1,4 +1,12 @@
|
||||
<?php
|
||||
/**
|
||||
* SPDX-License-Identifier: GPL-2.0-only
|
||||
*
|
||||
* This file is part of Nominatim. (https://nominatim.org)
|
||||
*
|
||||
* Copyright (C) 2022 by the Nominatim developer community.
|
||||
* For a full list of authors see the git log.
|
||||
*/
|
||||
|
||||
namespace Nominatim;
|
||||
|
||||
@@ -179,12 +187,12 @@ class PlaceLookup
|
||||
return null;
|
||||
}
|
||||
|
||||
$aResults = $this->lookup(array($iPlaceID => new Result($iPlaceID)));
|
||||
$aResults = $this->lookup(array($iPlaceID => new Result($iPlaceID)), 0, 30, true);
|
||||
|
||||
return empty($aResults) ? null : reset($aResults);
|
||||
}
|
||||
|
||||
public function lookup($aResults, $iMinRank = 0, $iMaxRank = 30)
|
||||
public function lookup($aResults, $iMinRank = 0, $iMaxRank = 30, $bAllowLinked = false)
|
||||
{
|
||||
Debug::newFunction('Place lookup');
|
||||
|
||||
@@ -239,7 +247,9 @@ class PlaceLookup
|
||||
if ($this->sAllowedTypesSQLList) {
|
||||
$sSQL .= 'AND placex.class in '.$this->sAllowedTypesSQLList;
|
||||
}
|
||||
$sSQL .= ' AND linked_place_id is null ';
|
||||
if (!$bAllowLinked) {
|
||||
$sSQL .= ' AND linked_place_id is null ';
|
||||
}
|
||||
$sSQL .= ' GROUP BY ';
|
||||
$sSQL .= ' osm_type, ';
|
||||
$sSQL .= ' osm_id, ';
|
||||
@@ -340,7 +350,9 @@ class PlaceLookup
|
||||
$sSQL .= ' null::text AS extra_place ';
|
||||
$sSQL .= ' FROM (';
|
||||
$sSQL .= ' SELECT place_id, '; // interpolate the Tiger housenumbers here
|
||||
$sSQL .= ' ST_LineInterpolatePoint(linegeo, (housenumber_for_place-startnumber::float)/(endnumber-startnumber)::float) AS centroid, ';
|
||||
$sSQL .= ' CASE WHEN startnumber != endnumber';
|
||||
$sSQL .= ' THEN ST_LineInterpolatePoint(linegeo, (housenumber_for_place-startnumber::float)/(endnumber-startnumber)::float)';
|
||||
$sSQL .= ' ELSE ST_LineInterpolatePoint(linegeo, 0.5) END AS centroid, ';
|
||||
$sSQL .= ' parent_place_id, ';
|
||||
$sSQL .= ' housenumber_for_place';
|
||||
$sSQL .= ' FROM (';
|
||||
@@ -397,7 +409,7 @@ class PlaceLookup
|
||||
$sSQL .= ' CASE '; // interpolate the housenumbers here
|
||||
$sSQL .= ' WHEN startnumber != endnumber ';
|
||||
$sSQL .= ' THEN ST_LineInterpolatePoint(linegeo, (housenumber_for_place-startnumber::float)/(endnumber-startnumber)::float) ';
|
||||
$sSQL .= ' ELSE ST_LineInterpolatePoint(linegeo, 0.5) ';
|
||||
$sSQL .= ' ELSE linegeo ';
|
||||
$sSQL .= ' END as centroid, ';
|
||||
$sSQL .= ' parent_place_id, ';
|
||||
$sSQL .= ' housenumber_for_place ';
|
||||
@@ -435,18 +447,14 @@ class PlaceLookup
|
||||
|
||||
if ($this->bExtraTags) {
|
||||
if ($aPlace['extra']) {
|
||||
$aPlace['sExtraTags'] = json_decode($aPlace['extra']);
|
||||
$aPlace['sExtraTags'] = json_decode($aPlace['extra'], true);
|
||||
} else {
|
||||
$aPlace['sExtraTags'] = (object) array();
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->bNameDetails) {
|
||||
if ($aPlace['names']) {
|
||||
$aPlace['sNameDetails'] = json_decode($aPlace['names']);
|
||||
} else {
|
||||
$aPlace['sNameDetails'] = (object) array();
|
||||
}
|
||||
$aPlace['sNameDetails'] = $this->extractNames($aPlace['names']);
|
||||
}
|
||||
|
||||
$aPlace['addresstype'] = ClassTypes\getLabelTag(
|
||||
@@ -469,6 +477,33 @@ class PlaceLookup
|
||||
return $aResults;
|
||||
}
|
||||
|
||||
|
||||
private function extractNames($sNames)
|
||||
{
|
||||
if (!$sNames) {
|
||||
return (object) array();
|
||||
}
|
||||
|
||||
$aFullNames = json_decode($sNames, true);
|
||||
$aNames = array();
|
||||
|
||||
foreach ($aFullNames as $sKey => $sValue) {
|
||||
if (strpos($sKey, '_place_') === 0) {
|
||||
$sSubKey = substr($sKey, 7);
|
||||
if (array_key_exists($sSubKey, $aFullNames)) {
|
||||
$aNames[$sKey] = $sValue;
|
||||
} else {
|
||||
$aNames[$sSubKey] = $sValue;
|
||||
}
|
||||
} else {
|
||||
$aNames[$sKey] = $sValue;
|
||||
}
|
||||
}
|
||||
|
||||
return $aNames;
|
||||
}
|
||||
|
||||
|
||||
/* returns an array which will contain the keys
|
||||
* aBoundingBox
|
||||
* and may also contain one or more of the keys
|
||||
@@ -479,8 +514,6 @@ class PlaceLookup
|
||||
* lat
|
||||
* lon
|
||||
*/
|
||||
|
||||
|
||||
public function getOutlines($iPlaceID, $fLon = null, $fLat = null, $fRadius = null, $fLonReverse = null, $fLatReverse = null)
|
||||
{
|
||||
|
||||
@@ -491,12 +524,7 @@ class PlaceLookup
|
||||
|
||||
// Get the bounding box and outline polygon
|
||||
$sSQL = 'select place_id,0 as numfeatures,st_area(geometry) as area,';
|
||||
if ($fLonReverse != null && $fLatReverse != null) {
|
||||
$sSQL .= ' ST_Y(closest_point) as centrelat,';
|
||||
$sSQL .= ' ST_X(closest_point) as centrelon,';
|
||||
} else {
|
||||
$sSQL .= ' ST_Y(centroid) as centrelat, ST_X(centroid) as centrelon,';
|
||||
}
|
||||
$sSQL .= ' ST_Y(centroid) as centrelat, ST_X(centroid) as centrelon,';
|
||||
$sSQL .= ' ST_YMin(geometry) as minlat,ST_YMax(geometry) as maxlat,';
|
||||
$sSQL .= ' ST_XMin(geometry) as minlon,ST_XMax(geometry) as maxlon';
|
||||
if ($this->bIncludePolygonAsGeoJSON) {
|
||||
@@ -511,19 +539,21 @@ class PlaceLookup
|
||||
if ($this->bIncludePolygonAsText) {
|
||||
$sSQL .= ',ST_AsText(geometry) as astext';
|
||||
}
|
||||
|
||||
$sSQL .= ' FROM (SELECT place_id';
|
||||
if ($fLonReverse != null && $fLatReverse != null) {
|
||||
$sFrom = ' from (SELECT * , CASE WHEN (class = \'highway\') AND (ST_GeometryType(geometry) = \'ST_LineString\') THEN ';
|
||||
$sFrom .=' ST_ClosestPoint(geometry, ST_SetSRID(ST_Point('.$fLatReverse.','.$fLonReverse.'),4326))';
|
||||
$sFrom .=' ELSE centroid END AS closest_point';
|
||||
$sFrom .= ' from placex where place_id = '.$iPlaceID.') as plx';
|
||||
$sSQL .= ',CASE WHEN (class = \'highway\') AND (ST_GeometryType(geometry) = \'ST_LineString\') THEN ';
|
||||
$sSQL .=' ST_ClosestPoint(geometry, ST_SetSRID(ST_Point('.$fLatReverse.','.$fLonReverse.'),4326))';
|
||||
$sSQL .=' ELSE centroid END AS centroid';
|
||||
} else {
|
||||
$sFrom = ' from placex where place_id = '.$iPlaceID;
|
||||
$sSQL .= ',centroid';
|
||||
}
|
||||
if ($this->fPolygonSimplificationThreshold > 0) {
|
||||
$sSQL .= ' from (select place_id,centroid,ST_SimplifyPreserveTopology(geometry,'.$this->fPolygonSimplificationThreshold.') as geometry'.$sFrom.') as plx';
|
||||
$sSQL .= ',ST_SimplifyPreserveTopology(geometry,'.$this->fPolygonSimplificationThreshold.') as geometry';
|
||||
} else {
|
||||
$sSQL .= $sFrom;
|
||||
$sSQL .= ',geometry';
|
||||
}
|
||||
$sSQL .= ' FROM placex where place_id = '.$iPlaceID.') as plx';
|
||||
|
||||
$aPointPolygon = $this->oDB->getRow($sSQL, null, 'Could not get outline');
|
||||
|
||||
|
||||
@@ -1,4 +1,12 @@
|
||||
<?php
|
||||
/**
|
||||
* SPDX-License-Identifier: GPL-2.0-only
|
||||
*
|
||||
* This file is part of Nominatim. (https://nominatim.org)
|
||||
*
|
||||
* Copyright (C) 2022 by the Nominatim developer community.
|
||||
* For a full list of authors see the git log.
|
||||
*/
|
||||
|
||||
namespace Nominatim;
|
||||
|
||||
|
||||
@@ -1,4 +1,12 @@
|
||||
<?php
|
||||
/**
|
||||
* SPDX-License-Identifier: GPL-2.0-only
|
||||
*
|
||||
* This file is part of Nominatim. (https://nominatim.org)
|
||||
*
|
||||
* Copyright (C) 2022 by the Nominatim developer community.
|
||||
* For a full list of authors see the git log.
|
||||
*/
|
||||
|
||||
namespace Nominatim;
|
||||
|
||||
@@ -56,12 +64,15 @@ class ReverseGeocode
|
||||
{
|
||||
Debug::newFunction('lookupInterpolation');
|
||||
$sSQL = 'SELECT place_id, parent_place_id, 30 as rank_search,';
|
||||
$sSQL .= ' ST_LineLocatePoint(linegeo,'.$sPointSQL.') as fraction,';
|
||||
$sSQL .= ' startnumber, endnumber, interpolationtype,';
|
||||
$sSQL .= ' (CASE WHEN endnumber != startnumber';
|
||||
$sSQL .= ' THEN (endnumber - startnumber) * ST_LineLocatePoint(linegeo,'.$sPointSQL.')';
|
||||
$sSQL .= ' ELSE startnumber END) as fhnr,';
|
||||
$sSQL .= ' startnumber, endnumber, step,';
|
||||
$sSQL .= ' ST_Distance(linegeo,'.$sPointSQL.') as distance';
|
||||
$sSQL .= ' FROM location_property_osmline';
|
||||
$sSQL .= ' WHERE ST_DWithin('.$sPointSQL.', linegeo, '.$fSearchDiam.')';
|
||||
$sSQL .= ' and indexed_status = 0 and startnumber is not NULL ';
|
||||
$sSQL .= ' and indexed_status = 0 and startnumber is not NULL ';
|
||||
$sSQL .= ' and parent_place_id != 0';
|
||||
$sSQL .= ' ORDER BY distance ASC limit 1';
|
||||
Debug::printSQL($sSQL);
|
||||
|
||||
@@ -111,6 +122,7 @@ class ReverseGeocode
|
||||
$sSQL .= ' FROM placex';
|
||||
$sSQL .= ' WHERE osm_type = \'N\'';
|
||||
$sSQL .= ' AND country_code = \''.$sCountryCode.'\'';
|
||||
$sSQL .= ' AND rank_search < 26 '; // needed to select right index
|
||||
$sSQL .= ' AND rank_search between 5 and ' .min(25, $iMaxRank);
|
||||
$sSQL .= ' AND class = \'place\' AND type != \'postcode\'';
|
||||
$sSQL .= ' AND name IS NOT NULL ';
|
||||
@@ -177,14 +189,16 @@ class ReverseGeocode
|
||||
$sSQL .= '(select place_id, parent_place_id, rank_address, rank_search, country_code, geometry';
|
||||
$sSQL .= ' FROM placex';
|
||||
$sSQL .= ' WHERE ST_GeometryType(geometry) in (\'ST_Polygon\', \'ST_MultiPolygon\')';
|
||||
$sSQL .= ' AND rank_address Between 5 AND ' .$iMaxRank;
|
||||
// Ensure that query planner doesn't use the index on rank_search.
|
||||
$sSQL .= ' AND coalesce(rank_search, 0) between 5 and ' .$iMaxRank;
|
||||
$sSQL .= ' AND rank_address between 4 and 25'; // needed for index selection
|
||||
$sSQL .= ' AND geometry && '.$sPointSQL;
|
||||
$sSQL .= ' AND type != \'postcode\' ';
|
||||
$sSQL .= ' AND name is not null';
|
||||
$sSQL .= ' AND indexed_status = 0 and linked_place_id is null';
|
||||
$sSQL .= ' ORDER BY rank_address DESC LIMIT 50 ) as a';
|
||||
$sSQL .= ' WHERE ST_CONTAINS(geometry, '.$sPointSQL.' )';
|
||||
$sSQL .= ' ORDER BY rank_address DESC LIMIT 1';
|
||||
$sSQL .= ' ORDER BY rank_search DESC LIMIT 50 ) as a';
|
||||
$sSQL .= ' WHERE ST_Contains(geometry, '.$sPointSQL.' )';
|
||||
$sSQL .= ' ORDER BY rank_search DESC LIMIT 1';
|
||||
Debug::printSQL($sSQL);
|
||||
|
||||
$aPoly = $this->oDB->getRow($sSQL, null, 'Could not determine polygon containing the point.');
|
||||
@@ -196,7 +210,7 @@ class ReverseGeocode
|
||||
$iRankSearch = $aPoly['rank_search'];
|
||||
$iPlaceID = $aPoly['place_id'];
|
||||
|
||||
if ($iRankAddress != $iMaxRank) {
|
||||
if ($iRankSearch != $iMaxRank) {
|
||||
$sSQL = 'SELECT place_id FROM ';
|
||||
$sSQL .= '(SELECT place_id, rank_search, country_code, geometry,';
|
||||
$sSQL .= ' ST_distance('.$sPointSQL.', geometry) as distance';
|
||||
@@ -206,6 +220,7 @@ class ReverseGeocode
|
||||
// for place nodes at rank_address 16
|
||||
$sSQL .= ' AND rank_search > '.$iRankSearch;
|
||||
$sSQL .= ' AND rank_search <= '.$iMaxRank;
|
||||
$sSQL .= ' AND rank_search < 26 '; // needed to select right index
|
||||
$sSQL .= ' AND rank_address > 0';
|
||||
$sSQL .= ' AND class = \'place\'';
|
||||
$sSQL .= ' AND type != \'postcode\'';
|
||||
@@ -253,7 +268,7 @@ class ReverseGeocode
|
||||
// starts if the search is on POI or street level,
|
||||
// searches for the nearest POI or street,
|
||||
// if a street is found and a POI is searched for,
|
||||
// the nearest POI which the found street is a parent of is choosen.
|
||||
// the nearest POI which the found street is a parent of is chosen.
|
||||
$sSQL = 'select place_id,parent_place_id,rank_address,country_code,';
|
||||
$sSQL .= ' ST_distance('.$sPointSQL.', geometry) as distance';
|
||||
$sSQL .= ' FROM ';
|
||||
@@ -317,9 +332,9 @@ class ReverseGeocode
|
||||
&& $this->iMaxRank >= 28
|
||||
) {
|
||||
$sSQL = 'SELECT place_id,parent_place_id,30 as rank_search,';
|
||||
$sSQL .= 'ST_LineLocatePoint(linegeo,'.$sPointSQL.') as fraction,';
|
||||
$sSQL .= 'ST_distance('.$sPointSQL.', linegeo) as distance,';
|
||||
$sSQL .= 'startnumber,endnumber,interpolationtype';
|
||||
$sSQL .= ' (endnumber - startnumber) * ST_LineLocatePoint(linegeo,'.$sPointSQL.') as fhnr,';
|
||||
$sSQL .= ' startnumber, endnumber, step,';
|
||||
$sSQL .= ' ST_Distance('.$sPointSQL.', linegeo) as distance';
|
||||
$sSQL .= ' FROM location_property_tiger WHERE parent_place_id = '.$oResult->iId;
|
||||
$sSQL .= ' AND ST_DWithin('.$sPointSQL.', linegeo, 0.001)';
|
||||
$sSQL .= ' ORDER BY distance ASC limit 1';
|
||||
@@ -331,7 +346,11 @@ class ReverseGeocode
|
||||
if ($aPlaceTiger) {
|
||||
$aPlace = $aPlaceTiger;
|
||||
$oResult = new Result($aPlaceTiger['place_id'], Result::TABLE_TIGER);
|
||||
$oResult->iHouseNumber = closestHouseNumber($aPlaceTiger);
|
||||
$iRndNum = max(0, round($aPlaceTiger['fhnr'] / $aPlaceTiger['step']) * $aPlaceTiger['step']);
|
||||
$oResult->iHouseNumber = $aPlaceTiger['startnumber'] + $iRndNum;
|
||||
if ($oResult->iHouseNumber > $aPlaceTiger['endnumber']) {
|
||||
$oResult->iHouseNumber = $aPlaceTiger['endnumber'];
|
||||
}
|
||||
$iRankAddress = 30;
|
||||
}
|
||||
}
|
||||
@@ -343,7 +362,7 @@ class ReverseGeocode
|
||||
// We can't reliably go from the closest street to an
|
||||
// interpolation line because the closest interpolation
|
||||
// may have a different street segments as a parent.
|
||||
// Therefore allow an interpolation line to take precendence
|
||||
// Therefore allow an interpolation line to take precedence
|
||||
// even when the street is closer.
|
||||
$fDistance = $iRankAddress < 28 ? 0.001 : $aPlace['distance'];
|
||||
}
|
||||
@@ -353,7 +372,11 @@ class ReverseGeocode
|
||||
|
||||
if ($aHouse) {
|
||||
$oResult = new Result($aHouse['place_id'], Result::TABLE_OSMLINE);
|
||||
$oResult->iHouseNumber = closestHouseNumber($aHouse);
|
||||
$iRndNum = max(0, round($aHouse['fhnr'] / $aHouse['step']) * $aHouse['step']);
|
||||
$oResult->iHouseNumber = $aHouse['startnumber'] + $iRndNum;
|
||||
if ($oResult->iHouseNumber > $aHouse['endnumber']) {
|
||||
$oResult->iHouseNumber = $aHouse['endnumber'];
|
||||
}
|
||||
$aPlace = $aHouse;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,12 @@
|
||||
<?php
|
||||
/**
|
||||
* SPDX-License-Identifier: GPL-2.0-only
|
||||
*
|
||||
* This file is part of Nominatim. (https://nominatim.org)
|
||||
*
|
||||
* Copyright (C) 2022 by the Nominatim developer community.
|
||||
* For a full list of authors see the git log.
|
||||
*/
|
||||
|
||||
namespace Nominatim;
|
||||
|
||||
@@ -28,6 +36,8 @@ class SearchContext
|
||||
public $sqlViewboxLarge = '';
|
||||
/// Reference along a route (as SQL).
|
||||
public $sqlViewboxCentre = '';
|
||||
/// List of countries to restrict search to (as array).
|
||||
public $aCountryList = null;
|
||||
/// List of countries to restrict search to (as SQL).
|
||||
public $sqlCountryList = '';
|
||||
/// List of place IDs to exclude (as SQL).
|
||||
@@ -187,6 +197,7 @@ class SearchContext
|
||||
public function setCountryList($aCountries)
|
||||
{
|
||||
$this->sqlCountryList = '('.join(',', array_map('addQuotes', $aCountries)).')';
|
||||
$this->aCountryList = $aCountries;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -279,6 +290,19 @@ class SearchContext
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the given country is covered by the search context.
|
||||
*
|
||||
* @param string $sCountryCode Country code of the country to check.
|
||||
*
|
||||
* @return True, if no country code restrictions are set or the
|
||||
* country is included in the country list.
|
||||
*/
|
||||
public function isCountryApplicable($sCountryCode)
|
||||
{
|
||||
return $this->aCountryList === null || in_array($sCountryCode, $this->aCountryList);
|
||||
}
|
||||
|
||||
public function debugInfo()
|
||||
{
|
||||
return array(
|
||||
|
||||
@@ -1,4 +1,12 @@
|
||||
<?php
|
||||
/**
|
||||
* SPDX-License-Identifier: GPL-2.0-only
|
||||
*
|
||||
* This file is part of Nominatim. (https://nominatim.org)
|
||||
*
|
||||
* Copyright (C) 2022 by the Nominatim developer community.
|
||||
* For a full list of authors see the git log.
|
||||
*/
|
||||
|
||||
namespace Nominatim;
|
||||
|
||||
@@ -19,6 +27,8 @@ class SearchDescription
|
||||
private $aName = array();
|
||||
/// True if the name is rare enough to force index use on name.
|
||||
private $bRareName = false;
|
||||
/// True if the name requires to be accompanied by address terms.
|
||||
private $bNameNeedsAddress = false;
|
||||
/// List of word ids making up the address of the object.
|
||||
private $aAddress = array();
|
||||
/// List of word ids that appear in the name but should be ignored.
|
||||
@@ -113,6 +123,9 @@ class SearchDescription
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if ($this->bNameNeedsAddress && empty($this->aAddress)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -223,7 +236,7 @@ class SearchDescription
|
||||
* Add the given full-word token to the list of terms to search for in the
|
||||
* name.
|
||||
*
|
||||
* @param interger iId ID of term to add.
|
||||
* @param integer iId ID of term to add.
|
||||
* @param bool bRareName True if the term is infrequent enough to not
|
||||
* require other constraints for efficient search.
|
||||
*/
|
||||
@@ -231,6 +244,7 @@ class SearchDescription
|
||||
{
|
||||
$this->aName[$iId] = $iId;
|
||||
$this->bRareName = $bRareName;
|
||||
$this->bNameNeedsAddress = false;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -240,11 +254,21 @@ class SearchDescription
|
||||
* @param integer iID ID of term to add.
|
||||
* @param bool bSearchable Term should be used to search for result
|
||||
* (i.e. term is not a stop word).
|
||||
* @param bool bNeedsAddress True if the term is too unspecific to be used
|
||||
* in a stand-alone search without an address
|
||||
* to narrow down the search.
|
||||
* @param integer iPhraseNumber Index of phrase, where the partial term
|
||||
* appears.
|
||||
*/
|
||||
public function addPartialNameToken($iId, $bSearchable, $iPhraseNumber)
|
||||
public function addPartialNameToken($iId, $bSearchable, $bNeedsAddress, $iPhraseNumber)
|
||||
{
|
||||
if (empty($this->aName)) {
|
||||
$this->bNameNeedsAddress = $bNeedsAddress;
|
||||
} elseif ($bSearchable && count($this->aName) >= 2) {
|
||||
$this->bNameNeedsAddress = false;
|
||||
} else {
|
||||
$this->bNameNeedsAddress &= $bNeedsAddress;
|
||||
}
|
||||
if ($bSearchable) {
|
||||
$this->aName[$iId] = $iId;
|
||||
} else {
|
||||
@@ -310,6 +334,7 @@ class SearchDescription
|
||||
{
|
||||
$this->aAddress = array_merge($this->aAddress, $this->aName);
|
||||
$this->bRareName = false;
|
||||
$this->bNameNeedsAddress = true;
|
||||
$this->aName = array($iId => $iId);
|
||||
$this->iNamePhrase = -1;
|
||||
}
|
||||
@@ -362,7 +387,7 @@ class SearchDescription
|
||||
*
|
||||
* @return mixed[] An array with two fields: IDs contains the list of
|
||||
* matching place IDs and houseNumber the houseNumber
|
||||
* if appicable or -1 if not.
|
||||
* if applicable or -1 if not.
|
||||
*/
|
||||
public function query(&$oDB, $iMinRank, $iMaxRank, $iLimit)
|
||||
{
|
||||
@@ -397,28 +422,6 @@ class SearchDescription
|
||||
$iLimit
|
||||
);
|
||||
|
||||
// Now search for housenumber, if housenumber provided. Can be zero.
|
||||
if (($this->sHouseNumber || $this->sHouseNumber === '0') && !empty($aResults)) {
|
||||
$aHnResults = $this->queryHouseNumber($oDB, $aResults);
|
||||
|
||||
// Downgrade the rank of the street results, they are missing
|
||||
// the housenumber. Also drop POI places (rank 30) here, they
|
||||
// cannot be a parent place and therefore must not be shown
|
||||
// as a result for a search with a missing housenumber.
|
||||
foreach ($aResults as $oRes) {
|
||||
if ($oRes->iAddressRank < 28) {
|
||||
if ($oRes->iAddressRank >= 26) {
|
||||
$oRes->iResultRank++;
|
||||
} else {
|
||||
$oRes->iResultRank += 2;
|
||||
}
|
||||
$aHnResults[$oRes->iId] = $oRes;
|
||||
}
|
||||
}
|
||||
|
||||
$aResults = $aHnResults;
|
||||
}
|
||||
|
||||
// finally get POIs if requested
|
||||
if ($this->sClass && !empty($aResults)) {
|
||||
$aResults = $this->queryPoiByOperator($oDB, $aResults, $iLimit);
|
||||
@@ -564,36 +567,6 @@ class SearchDescription
|
||||
$aTerms = array();
|
||||
$aOrder = array();
|
||||
|
||||
// Sort by existence of the requested house number but only if not
|
||||
// too many results are expected for the street, i.e. if the result
|
||||
// will be narrowed down by an address. Remeber that with ordering
|
||||
// every single result has to be checked.
|
||||
if ($this->sHouseNumber && ($this->bRareName || !empty($this->aAddress) || $this->sPostcode)) {
|
||||
$sHouseNumberRegex = '\\\\m'.$this->sHouseNumber.'\\\\M';
|
||||
$aOrder[] = ' (';
|
||||
$aOrder[0] .= 'EXISTS(';
|
||||
$aOrder[0] .= ' SELECT place_id';
|
||||
$aOrder[0] .= ' FROM placex';
|
||||
$aOrder[0] .= ' WHERE parent_place_id = search_name.place_id';
|
||||
$aOrder[0] .= " AND housenumber ~* E'".$sHouseNumberRegex."'";
|
||||
$aOrder[0] .= ' LIMIT 1';
|
||||
$aOrder[0] .= ') ';
|
||||
// also housenumbers from interpolation lines table are needed
|
||||
if (preg_match('/[0-9]+/', $this->sHouseNumber)) {
|
||||
$iHouseNumber = intval($this->sHouseNumber);
|
||||
$aOrder[0] .= 'OR EXISTS(';
|
||||
$aOrder[0] .= ' SELECT place_id ';
|
||||
$aOrder[0] .= ' FROM location_property_osmline ';
|
||||
$aOrder[0] .= ' WHERE parent_place_id = search_name.place_id';
|
||||
$aOrder[0] .= ' AND startnumber is not NULL';
|
||||
$aOrder[0] .= ' AND '.$iHouseNumber.'>=startnumber ';
|
||||
$aOrder[0] .= ' AND '.$iHouseNumber.'<=endnumber ';
|
||||
$aOrder[0] .= ' LIMIT 1';
|
||||
$aOrder[0] .= ')';
|
||||
}
|
||||
$aOrder[0] .= ') DESC';
|
||||
}
|
||||
|
||||
if (!empty($this->aName)) {
|
||||
$aTerms[] = 'name_vector @> '.$oDB->getArraySQL($this->aName);
|
||||
}
|
||||
@@ -624,7 +597,7 @@ class SearchDescription
|
||||
$aOrder[] = $this->oContext->distanceSQL('centroid');
|
||||
} elseif ($this->sPostcode) {
|
||||
if (empty($this->aAddress)) {
|
||||
$aTerms[] = "EXISTS(SELECT place_id FROM location_postcode p WHERE p.postcode = '".$this->sPostcode."' AND ST_DWithin(search_name.centroid, p.geometry, 0.1))";
|
||||
$aTerms[] = "EXISTS(SELECT place_id FROM location_postcode p WHERE p.postcode = '".$this->sPostcode."' AND ST_DWithin(search_name.centroid, p.geometry, 0.12))";
|
||||
} else {
|
||||
$aOrder[] = "(SELECT min(ST_Distance(search_name.centroid, p.geometry)) FROM location_postcode p WHERE p.postcode = '".$this->sPostcode."')";
|
||||
}
|
||||
@@ -639,10 +612,6 @@ class SearchDescription
|
||||
$aTerms[] = 'centroid && '.$this->oContext->sqlViewboxSmall;
|
||||
}
|
||||
|
||||
if ($this->oContext->hasNearPoint()) {
|
||||
$aOrder[] = $this->oContext->distanceSQL('centroid');
|
||||
}
|
||||
|
||||
if ($this->sHouseNumber) {
|
||||
$sImportanceSQL = '- abs(26 - address_rank) + 3';
|
||||
} else {
|
||||
@@ -665,122 +634,128 @@ class SearchDescription
|
||||
$sExactMatchSQL = '0::int as exactmatch';
|
||||
}
|
||||
|
||||
if ($this->sHouseNumber || $this->sClass) {
|
||||
$iLimit = 40;
|
||||
if (empty($aTerms)) {
|
||||
return array();
|
||||
}
|
||||
|
||||
$aResults = array();
|
||||
if ($this->hasHousenumber()) {
|
||||
$sHouseNumberRegex = $oDB->getDBQuoted('\\\\m'.$this->sHouseNumber.'\\\\M');
|
||||
|
||||
if (!empty($aTerms)) {
|
||||
$sSQL = 'SELECT place_id, address_rank,'.$sExactMatchSQL;
|
||||
// Housenumbers on streets and places.
|
||||
$sPlacexSql = 'SELECT array_agg(place_id) FROM placex';
|
||||
$sPlacexSql .= ' WHERE parent_place_id = sin.place_id AND sin.address_rank < 30';
|
||||
$sPlacexSql .= $this->oContext->excludeSQL(' AND place_id');
|
||||
$sPlacexSql .= ' and housenumber ~* E'.$sHouseNumberRegex;
|
||||
|
||||
// Interpolations on streets and places.
|
||||
$sInterpolSql = 'null';
|
||||
$sTigerSql = 'null';
|
||||
if (preg_match('/^[0-9]+$/', $this->sHouseNumber)) {
|
||||
$sIpolHnr = 'WHERE parent_place_id = sin.place_id ';
|
||||
$sIpolHnr .= ' AND startnumber is not NULL AND sin.address_rank < 30';
|
||||
$sIpolHnr .= ' AND '.$this->sHouseNumber.' between startnumber and endnumber';
|
||||
$sIpolHnr .= ' AND ('.$this->sHouseNumber.' - startnumber) % step = 0';
|
||||
|
||||
$sInterpolSql = 'SELECT array_agg(place_id) FROM location_property_osmline '.$sIpolHnr;
|
||||
if (CONST_Use_US_Tiger_Data) {
|
||||
$sTigerSql = 'SELECT array_agg(place_id) FROM location_property_tiger '.$sIpolHnr;
|
||||
$sTigerSql .= " and sin.country_code = 'us'";
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->sClass) {
|
||||
$iLimit = 40;
|
||||
}
|
||||
|
||||
$sSelfHnr = 'SELECT * FROM placex WHERE place_id = search_name.place_id';
|
||||
$sSelfHnr .= ' AND housenumber ~* E'.$sHouseNumberRegex;
|
||||
|
||||
$aTerms[] = '(address_rank < 30 or exists('.$sSelfHnr.'))';
|
||||
|
||||
|
||||
$sSQL = 'SELECT sin.*, ';
|
||||
$sSQL .= '('.$sPlacexSql.') as placex_hnr, ';
|
||||
$sSQL .= '('.$sInterpolSql.') as interpol_hnr, ';
|
||||
$sSQL .= '('.$sTigerSql.') as tiger_hnr ';
|
||||
$sSQL .= ' FROM (';
|
||||
$sSQL .= ' SELECT place_id, address_rank, country_code,'.$sExactMatchSQL.',';
|
||||
$sSQL .= ' CASE WHEN importance = 0 OR importance IS NULL';
|
||||
$sSQL .= ' THEN 0.75001-(search_rank::float/40) ELSE importance END as importance';
|
||||
$sSQL .= ' FROM search_name';
|
||||
$sSQL .= ' WHERE '.join(' and ', $aTerms);
|
||||
$sSQL .= ' ORDER BY '.join(', ', $aOrder);
|
||||
$sSQL .= ' LIMIT 40000';
|
||||
$sSQL .= ') as sin';
|
||||
$sSQL .= ' ORDER BY address_rank = 30 desc, placex_hnr, interpol_hnr, tiger_hnr,';
|
||||
$sSQL .= ' importance';
|
||||
$sSQL .= ' LIMIT '.$iLimit;
|
||||
} else {
|
||||
if ($this->sClass) {
|
||||
$iLimit = 40;
|
||||
}
|
||||
|
||||
$sSQL = 'SELECT place_id, address_rank, '.$sExactMatchSQL;
|
||||
$sSQL .= ' FROM search_name';
|
||||
$sSQL .= ' WHERE '.join(' and ', $aTerms);
|
||||
$sSQL .= ' ORDER BY '.join(', ', $aOrder);
|
||||
$sSQL .= ' LIMIT '.$iLimit;
|
||||
|
||||
Debug::printSQL($sSQL);
|
||||
|
||||
$aDBResults = $oDB->getAll($sSQL, null, 'Could not get places for search terms.');
|
||||
|
||||
foreach ($aDBResults as $aResult) {
|
||||
$oResult = new Result($aResult['place_id']);
|
||||
$oResult->iExactMatches = $aResult['exactmatch'];
|
||||
$oResult->iAddressRank = $aResult['address_rank'];
|
||||
$aResults[$aResult['place_id']] = $oResult;
|
||||
}
|
||||
}
|
||||
|
||||
return $aResults;
|
||||
}
|
||||
|
||||
private function queryHouseNumber(&$oDB, $aRoadPlaceIDs)
|
||||
{
|
||||
$aResults = array();
|
||||
$sRoadPlaceIDs = Result::joinIdsByTableMaxRank(
|
||||
$aRoadPlaceIDs,
|
||||
Result::TABLE_PLACEX,
|
||||
27
|
||||
);
|
||||
$sPOIPlaceIDs = Result::joinIdsByTableMinRank(
|
||||
$aRoadPlaceIDs,
|
||||
Result::TABLE_PLACEX,
|
||||
30
|
||||
);
|
||||
|
||||
$aIDCondition = array();
|
||||
if ($sRoadPlaceIDs) {
|
||||
$aIDCondition[] = 'parent_place_id in ('.$sRoadPlaceIDs.')';
|
||||
}
|
||||
if ($sPOIPlaceIDs) {
|
||||
$aIDCondition[] = 'place_id in ('.$sPOIPlaceIDs.')';
|
||||
}
|
||||
|
||||
if (empty($aIDCondition)) {
|
||||
return $aResults;
|
||||
}
|
||||
|
||||
$sHouseNumberRegex = '\\\\m'.$this->sHouseNumber.'\\\\M';
|
||||
$sSQL = 'SELECT place_id FROM placex WHERE';
|
||||
$sSQL .= " housenumber ~* E'".$sHouseNumberRegex."'";
|
||||
$sSQL .= ' AND ('.join(' OR ', $aIDCondition).')';
|
||||
$sSQL .= $this->oContext->excludeSQL(' AND place_id');
|
||||
|
||||
Debug::printSQL($sSQL);
|
||||
|
||||
// XXX should inherit the exactMatches from its parent
|
||||
foreach ($oDB->getCol($sSQL) as $iPlaceId) {
|
||||
$aResults[$iPlaceId] = new Result($iPlaceId);
|
||||
}
|
||||
$aDBResults = $oDB->getAll($sSQL, null, 'Could not get places for search terms.');
|
||||
|
||||
$bIsIntHouseNumber= (bool) preg_match('/[0-9]+/', $this->sHouseNumber);
|
||||
$iHousenumber = intval($this->sHouseNumber);
|
||||
if ($bIsIntHouseNumber && $sRoadPlaceIDs && empty($aResults)) {
|
||||
// if nothing found, search in the interpolation line table
|
||||
$sSQL = 'SELECT distinct place_id FROM location_property_osmline';
|
||||
$sSQL .= ' WHERE startnumber is not NULL';
|
||||
$sSQL .= ' AND parent_place_id in ('.$sRoadPlaceIDs.') AND (';
|
||||
if ($iHousenumber % 2 == 0) {
|
||||
// If housenumber is even, look for housenumber in streets
|
||||
// with interpolationtype even or all.
|
||||
$sSQL .= "interpolationtype='even'";
|
||||
} else {
|
||||
// Else look for housenumber with interpolationtype odd or all.
|
||||
$sSQL .= "interpolationtype='odd'";
|
||||
$aResults = array();
|
||||
|
||||
foreach ($aDBResults as $aResult) {
|
||||
$oResult = new Result($aResult['place_id']);
|
||||
$oResult->iExactMatches = $aResult['exactmatch'];
|
||||
$oResult->iAddressRank = $aResult['address_rank'];
|
||||
|
||||
$bNeedResult = true;
|
||||
if ($this->hasHousenumber() && $aResult['address_rank'] < 30) {
|
||||
if ($aResult['placex_hnr']) {
|
||||
foreach (explode(',', substr($aResult['placex_hnr'], 1, -1)) as $sPlaceID) {
|
||||
$iPlaceID = intval($sPlaceID);
|
||||
$oHnrResult = new Result($iPlaceID);
|
||||
$oHnrResult->iExactMatches = $aResult['exactmatch'];
|
||||
$oHnrResult->iAddressRank = 30;
|
||||
$aResults[$iPlaceID] = $oHnrResult;
|
||||
$bNeedResult = false;
|
||||
}
|
||||
}
|
||||
if ($aResult['interpol_hnr']) {
|
||||
foreach (explode(',', substr($aResult['interpol_hnr'], 1, -1)) as $sPlaceID) {
|
||||
$iPlaceID = intval($sPlaceID);
|
||||
$oHnrResult = new Result($iPlaceID, Result::TABLE_OSMLINE);
|
||||
$oHnrResult->iExactMatches = $aResult['exactmatch'];
|
||||
$oHnrResult->iAddressRank = 30;
|
||||
$oHnrResult->iHouseNumber = intval($this->sHouseNumber);
|
||||
$aResults[$iPlaceID] = $oHnrResult;
|
||||
$bNeedResult = false;
|
||||
}
|
||||
}
|
||||
if ($aResult['tiger_hnr']) {
|
||||
foreach (explode(',', substr($aResult['tiger_hnr'], 1, -1)) as $sPlaceID) {
|
||||
$iPlaceID = intval($sPlaceID);
|
||||
$oHnrResult = new Result($iPlaceID, Result::TABLE_TIGER);
|
||||
$oHnrResult->iExactMatches = $aResult['exactmatch'];
|
||||
$oHnrResult->iAddressRank = 30;
|
||||
$oHnrResult->iHouseNumber = intval($this->sHouseNumber);
|
||||
$aResults[$iPlaceID] = $oHnrResult;
|
||||
$bNeedResult = false;
|
||||
}
|
||||
}
|
||||
|
||||
if ($aResult['address_rank'] < 26) {
|
||||
$oResult->iResultRank += 2;
|
||||
} else {
|
||||
$oResult->iResultRank++;
|
||||
}
|
||||
}
|
||||
$sSQL .= " or interpolationtype='all') and ";
|
||||
$sSQL .= $iHousenumber.'>=startnumber and ';
|
||||
$sSQL .= $iHousenumber.'<=endnumber';
|
||||
$sSQL .= $this->oContext->excludeSQL(' AND place_id');
|
||||
|
||||
Debug::printSQL($sSQL);
|
||||
|
||||
foreach ($oDB->getCol($sSQL) as $iPlaceId) {
|
||||
$oResult = new Result($iPlaceId, Result::TABLE_OSMLINE);
|
||||
$oResult->iHouseNumber = $iHousenumber;
|
||||
$aResults[$iPlaceId] = $oResult;
|
||||
}
|
||||
}
|
||||
|
||||
// If nothing found then search in Tiger data (location_property_tiger)
|
||||
if (CONST_Use_US_Tiger_Data && $sRoadPlaceIDs && $bIsIntHouseNumber && empty($aResults)) {
|
||||
$sSQL = 'SELECT place_id FROM location_property_tiger';
|
||||
$sSQL .= ' WHERE parent_place_id in ('.$sRoadPlaceIDs.') and (';
|
||||
if ($iHousenumber % 2 == 0) {
|
||||
$sSQL .= "interpolationtype='even'";
|
||||
} else {
|
||||
$sSQL .= "interpolationtype='odd'";
|
||||
}
|
||||
$sSQL .= " or interpolationtype='all') and ";
|
||||
$sSQL .= $iHousenumber.'>=startnumber and ';
|
||||
$sSQL .= $iHousenumber.'<=endnumber';
|
||||
$sSQL .= $this->oContext->excludeSQL(' AND place_id');
|
||||
|
||||
Debug::printSQL($sSQL);
|
||||
|
||||
foreach ($oDB->getCol($sSQL) as $iPlaceId) {
|
||||
$oResult = new Result($iPlaceId, Result::TABLE_TIGER);
|
||||
$oResult->iHouseNumber = $iHousenumber;
|
||||
$aResults[$iPlaceId] = $oResult;
|
||||
if ($bNeedResult) {
|
||||
$aResults[$aResult['place_id']] = $oResult;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -832,6 +807,7 @@ class SearchDescription
|
||||
$sSQL = 'SELECT geometry FROM placex';
|
||||
$sSQL .= " WHERE place_id in ($sPlaceIDs)";
|
||||
$sSQL .= " AND rank_search < $iMaxRank + 5";
|
||||
$sSQL .= ' AND ST_Area(Box2d(geometry)) < 20';
|
||||
$sSQL .= " AND ST_GeometryType(geometry) in ('ST_Polygon','ST_MultiPolygon')";
|
||||
$sSQL .= ' ORDER BY rank_search ASC ';
|
||||
$sSQL .= ' LIMIT 1';
|
||||
|
||||
@@ -1,4 +1,12 @@
|
||||
<?php
|
||||
/**
|
||||
* SPDX-License-Identifier: GPL-2.0-only
|
||||
*
|
||||
* This file is part of Nominatim. (https://nominatim.org)
|
||||
*
|
||||
* Copyright (C) 2022 by the Nominatim developer community.
|
||||
* For a full list of authors see the git log.
|
||||
*/
|
||||
|
||||
namespace Nominatim;
|
||||
|
||||
|
||||
@@ -1,4 +1,12 @@
|
||||
<?php
|
||||
/**
|
||||
* SPDX-License-Identifier: GPL-2.0-only
|
||||
*
|
||||
* This file is part of Nominatim. (https://nominatim.org)
|
||||
*
|
||||
* Copyright (C) 2022 by the Nominatim developer community.
|
||||
* For a full list of authors see the git log.
|
||||
*/
|
||||
|
||||
namespace Nominatim;
|
||||
|
||||
|
||||
144
lib-php/SimpleWordList.php
Normal file
144
lib-php/SimpleWordList.php
Normal file
@@ -0,0 +1,144 @@
|
||||
<?php
|
||||
/**
|
||||
* SPDX-License-Identifier: GPL-2.0-only
|
||||
*
|
||||
* This file is part of Nominatim. (https://nominatim.org)
|
||||
*
|
||||
* Copyright (C) 2022 by the Nominatim developer community.
|
||||
* For a full list of authors see the git log.
|
||||
*/
|
||||
|
||||
namespace Nominatim;
|
||||
|
||||
/**
|
||||
* A word list creator based on simple splitting by space.
|
||||
*
|
||||
* Creates possible permutations of split phrases by finding all combination
|
||||
* of splitting the phrase on space boundaries.
|
||||
*/
|
||||
class SimpleWordList
|
||||
{
|
||||
const MAX_WORDSET_LEN = 20;
|
||||
const MAX_WORDSETS = 100;
|
||||
|
||||
// The phrase as a list of simple terms (without spaces).
|
||||
private $aWords;
|
||||
|
||||
/**
|
||||
* Create a new word list
|
||||
*
|
||||
* @param string sPhrase Phrase to create the word list from. The phrase is
|
||||
* expected to be normalised, so that there are no
|
||||
* subsequent spaces.
|
||||
*/
|
||||
public function __construct($sPhrase)
|
||||
{
|
||||
if (strlen($sPhrase) > 0) {
|
||||
$this->aWords = explode(' ', $sPhrase);
|
||||
} else {
|
||||
$this->aWords = array();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all possible tokens that are present in this word list.
|
||||
*
|
||||
* @return array The list of string tokens in the word list.
|
||||
*/
|
||||
public function getTokens()
|
||||
{
|
||||
$aTokens = array();
|
||||
$iNumWords = count($this->aWords);
|
||||
|
||||
for ($i = 0; $i < $iNumWords; $i++) {
|
||||
$sPhrase = $this->aWords[$i];
|
||||
$aTokens[$sPhrase] = $sPhrase;
|
||||
|
||||
for ($j = $i + 1; $j < $iNumWords; $j++) {
|
||||
$sPhrase .= ' '.$this->aWords[$j];
|
||||
$aTokens[$sPhrase] = $sPhrase;
|
||||
}
|
||||
}
|
||||
|
||||
return $aTokens;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute all possible permutations of phrase splits that result in
|
||||
* words which are in the token list.
|
||||
*/
|
||||
public function getWordSets($oTokens)
|
||||
{
|
||||
$iNumWords = count($this->aWords);
|
||||
|
||||
if ($iNumWords == 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Caches the word set for the partial phrase up to word i.
|
||||
$aSetCache = array_fill(0, $iNumWords, array());
|
||||
|
||||
// Initialise first element of cache. There can only be the word.
|
||||
if ($oTokens->containsAny($this->aWords[0])) {
|
||||
$aSetCache[0][] = array($this->aWords[0]);
|
||||
}
|
||||
|
||||
// Now do the next elements using what we already have.
|
||||
for ($i = 1; $i < $iNumWords; $i++) {
|
||||
for ($j = $i; $j > 0; $j--) {
|
||||
$sPartial = $j == $i ? $this->aWords[$j] : $this->aWords[$j].' '.$sPartial;
|
||||
if (!empty($aSetCache[$j - 1]) && $oTokens->containsAny($sPartial)) {
|
||||
$aPartial = array($sPartial);
|
||||
foreach ($aSetCache[$j - 1] as $aSet) {
|
||||
if (count($aSet) < SimpleWordList::MAX_WORDSET_LEN) {
|
||||
$aSetCache[$i][] = array_merge($aSet, $aPartial);
|
||||
}
|
||||
}
|
||||
if (count($aSetCache[$i]) > 2 * SimpleWordList::MAX_WORDSETS) {
|
||||
usort(
|
||||
$aSetCache[$i],
|
||||
array('\Nominatim\SimpleWordList', 'cmpByArraylen')
|
||||
);
|
||||
$aSetCache[$i] = array_slice(
|
||||
$aSetCache[$i],
|
||||
0,
|
||||
SimpleWordList::MAX_WORDSETS
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// finally the current full phrase
|
||||
$sPartial = $this->aWords[0].' '.$sPartial;
|
||||
if ($oTokens->containsAny($sPartial)) {
|
||||
$aSetCache[$i][] = array($sPartial);
|
||||
}
|
||||
}
|
||||
|
||||
$aWordSets = $aSetCache[$iNumWords - 1];
|
||||
usort($aWordSets, array('\Nominatim\SimpleWordList', 'cmpByArraylen'));
|
||||
return array_slice($aWordSets, 0, SimpleWordList::MAX_WORDSETS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom search routine which takes two arrays. The array with the fewest
|
||||
* items wins. If same number of items then the one with the longest first
|
||||
* element wins.
|
||||
*/
|
||||
public static function cmpByArraylen($aA, $aB)
|
||||
{
|
||||
$iALen = count($aA);
|
||||
$iBLen = count($aB);
|
||||
|
||||
if ($iALen == $iBLen) {
|
||||
return strlen($aB[0]) <=> strlen($aA[0]);
|
||||
}
|
||||
|
||||
return ($iALen < $iBLen) ? -1 : 1;
|
||||
}
|
||||
|
||||
public function debugInfo()
|
||||
{
|
||||
return $this->aWords;
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,12 @@
|
||||
<?php
|
||||
/**
|
||||
* SPDX-License-Identifier: GPL-2.0-only
|
||||
*
|
||||
* This file is part of Nominatim. (https://nominatim.org)
|
||||
*
|
||||
* Copyright (C) 2022 by the Nominatim developer community.
|
||||
* For a full list of authors see the git log.
|
||||
*/
|
||||
|
||||
namespace Nominatim;
|
||||
|
||||
|
||||
@@ -1,4 +1,12 @@
|
||||
<?php
|
||||
/**
|
||||
* SPDX-License-Identifier: GPL-2.0-only
|
||||
*
|
||||
* This file is part of Nominatim. (https://nominatim.org)
|
||||
*
|
||||
* Copyright (C) 2022 by the Nominatim developer community.
|
||||
* For a full list of authors see the git log.
|
||||
*/
|
||||
|
||||
namespace Nominatim;
|
||||
|
||||
|
||||
@@ -1,4 +1,12 @@
|
||||
<?php
|
||||
/**
|
||||
* SPDX-License-Identifier: GPL-2.0-only
|
||||
*
|
||||
* This file is part of Nominatim. (https://nominatim.org)
|
||||
*
|
||||
* Copyright (C) 2022 by the Nominatim developer community.
|
||||
* For a full list of authors see the git log.
|
||||
*/
|
||||
|
||||
namespace Nominatim\Token;
|
||||
|
||||
@@ -36,7 +44,9 @@ class Country
|
||||
*/
|
||||
public function isExtendable($oSearch, $oPosition)
|
||||
{
|
||||
return !$oSearch->hasCountry() && $oPosition->maybePhrase('country');
|
||||
return !$oSearch->hasCountry()
|
||||
&& $oPosition->maybePhrase('country')
|
||||
&& $oSearch->getContext()->isCountryApplicable($this->sCountryCode);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,4 +1,12 @@
|
||||
<?php
|
||||
/**
|
||||
* SPDX-License-Identifier: GPL-2.0-only
|
||||
*
|
||||
* This file is part of Nominatim. (https://nominatim.org)
|
||||
*
|
||||
* Copyright (C) 2022 by the Nominatim developer community.
|
||||
* For a full list of authors see the git log.
|
||||
*/
|
||||
|
||||
namespace Nominatim\Token;
|
||||
|
||||
@@ -58,8 +66,8 @@ class HouseNumber
|
||||
// up of numbers, add a penalty
|
||||
$iSearchCost = 1;
|
||||
if (preg_match('/\\d/', $this->sToken) === 0
|
||||
|| preg_match_all('/[^0-9]/', $this->sToken, $aMatches) > 2) {
|
||||
$iSearchCost++;
|
||||
|| preg_match_all('/[^0-9 ]/', $this->sToken, $aMatches) > 3) {
|
||||
$iSearchCost += strlen($this->sToken) - 1;
|
||||
}
|
||||
if (!$oSearch->hasOperator(\Nominatim\Operator::NONE)) {
|
||||
$iSearchCost++;
|
||||
|
||||
@@ -1,4 +1,12 @@
|
||||
<?php
|
||||
/**
|
||||
* SPDX-License-Identifier: GPL-2.0-only
|
||||
*
|
||||
* This file is part of Nominatim. (https://nominatim.org)
|
||||
*
|
||||
* Copyright (C) 2022 by the Nominatim developer community.
|
||||
* For a full list of authors see the git log.
|
||||
*/
|
||||
|
||||
namespace Nominatim;
|
||||
|
||||
|
||||
@@ -1,4 +1,12 @@
|
||||
<?php
|
||||
/**
|
||||
* SPDX-License-Identifier: GPL-2.0-only
|
||||
*
|
||||
* This file is part of Nominatim. (https://nominatim.org)
|
||||
*
|
||||
* Copyright (C) 2022 by the Nominatim developer community.
|
||||
* For a full list of authors see the git log.
|
||||
*/
|
||||
|
||||
namespace Nominatim\Token;
|
||||
|
||||
@@ -90,6 +98,7 @@ class Partial
|
||||
$oNewSearch->addPartialNameToken(
|
||||
$this->iId,
|
||||
$this->iSearchNameCount < CONST_Max_Word_Frequency,
|
||||
$this->iSearchNameCount > CONST_Search_NameOnlySearchFrequencyThreshold,
|
||||
$oPosition->getPhrase()
|
||||
);
|
||||
|
||||
|
||||
@@ -1,4 +1,12 @@
|
||||
<?php
|
||||
/**
|
||||
* SPDX-License-Identifier: GPL-2.0-only
|
||||
*
|
||||
* This file is part of Nominatim. (https://nominatim.org)
|
||||
*
|
||||
* Copyright (C) 2022 by the Nominatim developer community.
|
||||
* For a full list of authors see the git log.
|
||||
*/
|
||||
|
||||
namespace Nominatim\Token;
|
||||
|
||||
@@ -9,7 +17,7 @@ class Postcode
|
||||
{
|
||||
/// Database word id, if available.
|
||||
private $iId;
|
||||
/// Full nomralized postcode (upper cased).
|
||||
/// Full normalized postcode (upper cased).
|
||||
private $sPostcode;
|
||||
// Optional country code the postcode belongs to (currently unused).
|
||||
private $sCountryCode;
|
||||
@@ -17,7 +25,12 @@ class Postcode
|
||||
public function __construct($iId, $sPostcode, $sCountryCode = '')
|
||||
{
|
||||
$this->iId = $iId;
|
||||
$this->sPostcode = $sPostcode;
|
||||
$iSplitPos = strpos($sPostcode, '@');
|
||||
if ($iSplitPos === false) {
|
||||
$this->sPostcode = $sPostcode;
|
||||
} else {
|
||||
$this->sPostcode = substr($sPostcode, 0, $iSplitPos);
|
||||
}
|
||||
$this->sCountryCode = empty($sCountryCode) ? '' : $sCountryCode;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,12 @@
|
||||
<?php
|
||||
/**
|
||||
* SPDX-License-Identifier: GPL-2.0-only
|
||||
*
|
||||
* This file is part of Nominatim. (https://nominatim.org)
|
||||
*
|
||||
* Copyright (C) 2022 by the Nominatim developer community.
|
||||
* For a full list of authors see the git log.
|
||||
*/
|
||||
|
||||
namespace Nominatim\Token;
|
||||
|
||||
@@ -44,7 +52,10 @@ class SpecialTerm
|
||||
*/
|
||||
public function isExtendable($oSearch, $oPosition)
|
||||
{
|
||||
return !$oSearch->hasOperator() && $oPosition->isPhrase('');
|
||||
return !$oSearch->hasOperator()
|
||||
&& $oPosition->isPhrase('')
|
||||
&& ($this->iOperator != \Nominatim\Operator::NONE
|
||||
|| (!$oSearch->hasAddress() && !$oSearch->hasHousenumber() && !$oSearch->hasCountry()));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -58,19 +69,31 @@ class SpecialTerm
|
||||
*/
|
||||
public function extendSearch($oSearch, $oPosition)
|
||||
{
|
||||
$iSearchCost = 2;
|
||||
$iSearchCost = 0;
|
||||
|
||||
$iOp = $this->iOperator;
|
||||
if ($iOp == \Nominatim\Operator::NONE) {
|
||||
if ($oSearch->hasName() || $oSearch->getContext()->isBoundedSearch()) {
|
||||
if ($oPosition->isFirstToken()
|
||||
|| $oSearch->hasName()
|
||||
|| $oSearch->getContext()->isBoundedSearch()
|
||||
) {
|
||||
$iOp = \Nominatim\Operator::NAME;
|
||||
$iSearchCost += 3;
|
||||
} else {
|
||||
$iOp = \Nominatim\Operator::NEAR;
|
||||
$iSearchCost += 4;
|
||||
if (!$oPosition->isFirstToken()) {
|
||||
$iSearchCost += 3;
|
||||
}
|
||||
}
|
||||
} elseif ($oPosition->isFirstToken()) {
|
||||
$iSearchCost += 2;
|
||||
} elseif (!$oPosition->isFirstToken() && !$oPosition->isLastToken()) {
|
||||
$iSearchCost += 2;
|
||||
} elseif ($oPosition->isLastToken()) {
|
||||
$iSearchCost += 4;
|
||||
} else {
|
||||
$iSearchCost += 6;
|
||||
}
|
||||
|
||||
if ($oSearch->hasHousenumber()) {
|
||||
$iSearchCost ++;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,12 @@
|
||||
<?php
|
||||
/**
|
||||
* SPDX-License-Identifier: GPL-2.0-only
|
||||
*
|
||||
* This file is part of Nominatim. (https://nominatim.org)
|
||||
*
|
||||
* Copyright (C) 2022 by the Nominatim developer community.
|
||||
* For a full list of authors see the git log.
|
||||
*/
|
||||
|
||||
namespace Nominatim\Token;
|
||||
|
||||
@@ -54,7 +62,7 @@ class Word
|
||||
public function extendSearch($oSearch, $oPosition)
|
||||
{
|
||||
// Full words can only be a name if they appear at the beginning
|
||||
// of the phrase. In structured search the name must forcably in
|
||||
// of the phrase. In structured search the name must forcibly in
|
||||
// the first phrase. In unstructured search it may be in a later
|
||||
// phrase when the first phrase is a house number.
|
||||
if ($oSearch->hasName()
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
<?php
|
||||
@define('CONST_LibDir', dirname(dirname(__FILE__)));
|
||||
|
||||
require_once(CONST_LibDir.'/init-cmd.php');
|
||||
|
||||
ini_set('memory_limit', '800M');
|
||||
ini_set('display_errors', 'stderr');
|
||||
|
||||
$aCMDOptions
|
||||
= array(
|
||||
'Import country language data from osm wiki',
|
||||
array('help', 'h', 0, 1, 0, 0, false, 'Show Help'),
|
||||
array('quiet', 'q', 0, 1, 0, 0, 'bool', 'Quiet output'),
|
||||
array('verbose', 'v', 0, 1, 0, 0, 'bool', 'Verbose output'),
|
||||
array('project-dir', '', 0, 1, 1, 1, 'realpath', 'Base directory of the Nominatim installation (default: .)'),
|
||||
);
|
||||
getCmdOpt($_SERVER['argv'], $aCMDOptions, $aCMDResult, true, true);
|
||||
|
||||
loadSettings($aCMDResult['project-dir'] ?? getcwd());
|
||||
setupHTTPProxy();
|
||||
|
||||
if (true) {
|
||||
$sURL = 'https://wiki.openstreetmap.org/wiki/Special:Export/Nominatim/Country_Codes';
|
||||
$sWikiPageXML = file_get_contents($sURL);
|
||||
if (preg_match_all('#\\| ([a-z]{2}) \\|\\| [^|]+\\|\\| ([a-z,]+)#', $sWikiPageXML, $aMatches, PREG_SET_ORDER)) {
|
||||
foreach ($aMatches as $aMatch) {
|
||||
$aLanguages = explode(',', $aMatch[2]);
|
||||
foreach ($aLanguages as $i => $s) {
|
||||
$aLanguages[$i] = '"'.pg_escape_string($s).'"';
|
||||
}
|
||||
echo "UPDATE country_name set country_default_language_codes = '{".join(',', $aLanguages)."}' where country_code = '".pg_escape_string($aMatch[1])."';\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,12 @@
|
||||
<?php
|
||||
/**
|
||||
* SPDX-License-Identifier: GPL-2.0-only
|
||||
*
|
||||
* This file is part of Nominatim. (https://nominatim.org)
|
||||
*
|
||||
* Copyright (C) 2022 by the Nominatim developer community.
|
||||
* For a full list of authors see the git log.
|
||||
*/
|
||||
@define('CONST_LibDir', dirname(dirname(__FILE__)));
|
||||
// Script to extract structured city and street data
|
||||
// from a running nominatim instance as CSV data
|
||||
|
||||
@@ -1,4 +1,12 @@
|
||||
<?php
|
||||
/**
|
||||
* SPDX-License-Identifier: GPL-2.0-only
|
||||
*
|
||||
* This file is part of Nominatim. (https://nominatim.org)
|
||||
*
|
||||
* Copyright (C) 2022 by the Nominatim developer community.
|
||||
* For a full list of authors see the git log.
|
||||
*/
|
||||
@define('CONST_LibDir', dirname(dirname(__FILE__)));
|
||||
|
||||
require_once(CONST_LibDir.'/init-cmd.php');
|
||||
@@ -86,8 +94,13 @@ if (!$aResult['reverse-only']) {
|
||||
if ($bVerbose) {
|
||||
echo "\n";
|
||||
}
|
||||
|
||||
$oTokenizer = new \Nominatim\Tokenizer($oDB);
|
||||
|
||||
$aWords = $oTokenizer->mostFrequentWords(1000);
|
||||
|
||||
$sSQL = 'SELECT word FROM word WHERE word is not null ORDER BY search_name_count DESC LIMIT 1000';
|
||||
foreach ($oDB->getCol($sSQL) as $sWord) {
|
||||
foreach ($aWords as $sWord) {
|
||||
if ($bVerbose) {
|
||||
echo "$sWord = ";
|
||||
}
|
||||
|
||||
@@ -1,4 +1,12 @@
|
||||
<?php
|
||||
/**
|
||||
* SPDX-License-Identifier: GPL-2.0-only
|
||||
*
|
||||
* This file is part of Nominatim. (https://nominatim.org)
|
||||
*
|
||||
* Copyright (C) 2022 by the Nominatim developer community.
|
||||
* For a full list of authors see the git log.
|
||||
*/
|
||||
|
||||
require_once(CONST_LibDir.'/Shell.php');
|
||||
|
||||
@@ -98,7 +106,7 @@ function getCmdOpt($aArg, $aSpec, &$aResult, $bExitOnError = false, $bExitOnUnkn
|
||||
showUsage($aSpec, $bExitOnError, 'Option \''.$aLine[0].'\' is missing');
|
||||
}
|
||||
if ($aCounts[$aLine[0]] > $aLine[3]) {
|
||||
showUsage($aSpec, $bExitOnError, 'Option \''.$aLine[0].'\' is pressent too many times');
|
||||
showUsage($aSpec, $bExitOnError, 'Option \''.$aLine[0].'\' is present too many times');
|
||||
}
|
||||
if ($aLine[6] == 'bool' && !array_key_exists($aLine[0], $aResult)) {
|
||||
$aResult[$aLine[0]] = false;
|
||||
|
||||
@@ -1,4 +1,12 @@
|
||||
<?php
|
||||
/**
|
||||
* SPDX-License-Identifier: GPL-2.0-only
|
||||
*
|
||||
* This file is part of Nominatim. (https://nominatim.org)
|
||||
*
|
||||
* Copyright (C) 2022 by the Nominatim developer community.
|
||||
* For a full list of authors see the git log.
|
||||
*/
|
||||
|
||||
require('Symfony/Component/Dotenv/autoload.php');
|
||||
|
||||
|
||||
@@ -1,4 +1,12 @@
|
||||
<?php
|
||||
/**
|
||||
* SPDX-License-Identifier: GPL-2.0-only
|
||||
*
|
||||
* This file is part of Nominatim. (https://nominatim.org)
|
||||
*
|
||||
* Copyright (C) 2022 by the Nominatim developer community.
|
||||
* For a full list of authors see the git log.
|
||||
*/
|
||||
|
||||
require_once('init.php');
|
||||
require_once('cmd.php');
|
||||
|
||||
@@ -1,4 +1,12 @@
|
||||
<?php
|
||||
/**
|
||||
* SPDX-License-Identifier: GPL-2.0-only
|
||||
*
|
||||
* This file is part of Nominatim. (https://nominatim.org)
|
||||
*
|
||||
* Copyright (C) 2022 by the Nominatim developer community.
|
||||
* For a full list of authors see the git log.
|
||||
*/
|
||||
|
||||
require_once('init.php');
|
||||
require_once('ParameterParser.php');
|
||||
@@ -18,7 +26,7 @@ function userError($sMsg)
|
||||
|
||||
function exception_handler_json($exception)
|
||||
{
|
||||
http_response_code($exception->getCode());
|
||||
http_response_code($exception->getCode() == 0 ? 500 : $exception->getCode());
|
||||
header('Content-type: application/json; charset=utf-8');
|
||||
include(CONST_LibDir.'/template/error-json.php');
|
||||
exit();
|
||||
@@ -26,7 +34,7 @@ function exception_handler_json($exception)
|
||||
|
||||
function exception_handler_xml($exception)
|
||||
{
|
||||
http_response_code($exception->getCode());
|
||||
http_response_code($exception->getCode() == 0 ? 500 : $exception->getCode());
|
||||
header('Content-type: text/xml; charset=utf-8');
|
||||
echo '<?xml version="1.0" encoding="UTF-8" ?>'."\n";
|
||||
include(CONST_LibDir.'/template/error-xml.php');
|
||||
|
||||
@@ -1,4 +1,12 @@
|
||||
<?php
|
||||
/**
|
||||
* SPDX-License-Identifier: GPL-2.0-only
|
||||
*
|
||||
* This file is part of Nominatim. (https://nominatim.org)
|
||||
*
|
||||
* Copyright (C) 2022 by the Nominatim developer community.
|
||||
* For a full list of authors see the git log.
|
||||
*/
|
||||
|
||||
require_once(CONST_LibDir.'/lib.php');
|
||||
require_once(CONST_LibDir.'/DB.php');
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user