Nominatim 地址编码
在平时开发应用中,经常会有通过经纬度获取地址信息的需求,这种需要可以通过高德等地图软件提供的收费API处理,也可以自己搭建地址编码服务器。
Nominatim
Nominatim(https://github.com/osm-search/Nominatim)是一个可以按名称和地址来搜索OSM中的数据,并生成OSM点的合成地址的工具(反向地理编码)。可用在http://nominatim.openstreetmap.org找到这个工具。Nominatim也用在OpenStreetMap首页的搜索工具栏中,同时也为MapQuest Open Initiative提供搜索支持。
数据导入阶段
读取原始OSM数据,并提取对地理编码有用的所有信息。这部分由osm2pgsql完成,该工具也可用于导入渲染数据库。它使用osm2pgsql/src/output-gatetter中的特殊地名词典输出插件。[ch]pp.导入的结果可以在数据库表中找到。
地址计算或索引阶段
从位置获取数据,并添加地理编码所需的其他信息。它按重要性对地点进行排名,将属于一起的对象链接在一起,并计算地址和搜索索引。大部分工作是通过数据库触发器在PL/pgSQL中完成的,可以在sql/functions/目录中的文件中找到。
搜索前端
实现了实际的API。它接受用户的搜索和反向地理编码查询,查找数据并以请求的格式返回结果。这部分是用PHP编写的,可以在lib/和website/目录中找到。使用apache。
Docker compose安装
services:
nominatim:
container_name: nominatim
image: mediagis/nominatim:4.4
ports:
- "5432:5432"
- "8080:8080"
environment:
TZ: Asia/Shanghai
PBF_URL: https://download.geofabrik.de/asia/china-latest.osm.pbf
REPLICATION_URL: https://download.geofabrik.de/asia/china-updates/
NOMINATIM_PASSWORD: 123456
IMPORT_WIKIPEDIA: "true"
IMPORT_US_POSTCODES: "true"
IMPORT_GB_POSTCODES: "true"
REPLICATION_UPDATE_INTVAL: 86400
THREADS: 16
volumes:
- type: bind
source: /home/test/nominatim/data/db
target: /var/lib/postgresql/14/main
- type: bind
source: /home/test/nominatim/data/flatnode
target: /nominatim/flatnode
shm_size: 1gb
5432是PostgreSQL数据库的端口,8080是服务启动之后提供的web接口端口
PBF_URL:数据包地址
REPLICATION_URL:更新包地址
NOMINATIM_PASSWORD:数据库密码
IMPORT_WIKIPEDIA:导入wiki数据
IMPORT_US_POSTCODES:导入美国邮编
IMPORT_GB_POSTCODES:导入邮编
REPLICATION_UPDATE_INTVAL:更新间隔,单位秒
THREADS:解析地址的线程
如果docker下载osm.pbf很慢,也可以用下载工具下完之后,映射到docker里面:
#PBF_URL: https://download.geofabrik.de/asia/china-latest.osm.pbf
PBF_PATH: /nominatim/data/osm/planet-latest.osm.pbf
volumes:
- /home/test/nominatim/data/osm:/nominatim/data/osm
这里使用中国的pbf,安装解析过程比较长(可能需要2、3天的时间),具体时间由服务器配置决定。
看到日志出现下面的内容表示服务启动成功:
LOG: database system was shut down at 2022-08-16 05:33:06 UTC LOG: database system is ready to accept connections
全球地址数据
如果使用全量pbf数据,替换PBF_URL和REPLICATION_URL 的链接:https://ftp5.gwdg.de/pub/misc/openstreetmap/planet.openstreetmap.org/pbf/planet-latest.osm.pbf
https://ftp5.gwdg.de/pub/misc/openstreetmap/planet.openstreetmap.org/replication/day/
全量数据对硬件要求比较高,而且解析时间更长,可能需要一周的时间:
- 16 core CPU (set THREADS variable to number of cores/threads available) - 64GB RAM - 1.5TB (NVMe) SSD storage
接口API
https://nominatim.org/release-docs/develop/api/Overview/
这里主要介绍其中的3个
健康检查(/search?q=avenue%20pasteur)
[]
逆地址编码(/reverse?lat=28.259719364765736&lon=112.91566526653007&format=jsonv2&accept-language=zh)
{ "place_id": 52339186, "licence": "Data © OpenStreetMap contributors, ODbL 1.0. http://osm.org/copyright", "osm_type": "node", "osm_id": 3569911293, "lat": "-41.2903464", "lon": "174.7779487", "category": "place", "type": "house", "place_rank": 30, "importance": 0.00000999999999995449, "addresstype": "place", "name": "", "display_name": "138, Wakefield Street, Te Aro, 惠灵顿 / 惠靈頓 / 威靈頓, 6011, 紐西蘭/新西兰", "address": { "house_number": "138", "road": "Wakefield Street", "suburb": "Te Aro", "city": "惠灵顿 / 惠靈頓 / 威靈頓", "county": "惠灵顿 / 惠靈頓 / 威靈頓", "state": "惠灵顿 / 惠靈頓 / 威靈頓", "ISO3166-2-lvl4": "NZ-WGN", "postcode": "6011", "country": "紐西蘭/新西兰", "country_code": "nz" }, "boundingbox": [ "-41.2903964", "-41.2902964", "174.7778987", "174.7779987" ] }
ID详情(/details?osmtype=W&osmid=1274999787&format=json&accept-language=zh)
{ "place_id": 73967428, "parent_place_id": 74020996, "osm_type": "N", "osm_id": 3569911293, "category": "place", "type": "house", "admin_level": 15, "localname": "138", "names": [], "addresstags": { "city": "Wellington", "housenumber": "138", "postcode": "6011", "street": "Wakefield Street", "suburb": "Te Aro" }, "housenumber": "138", "calculated_postcode": "6011", "country_code": "nz", "indexed_date": "2024-08-13T00:20:54+00:00", "importance": 9.99999999995449e-6, "calculated_importance": 9.99999999995449e-6, "extratags": [], "calculated_wikipedia": null, "rank_address": 30, "rank_search": 30, "isarea": false, "centroid": { "type": "Point", "coordinates": [ 174.7779487, -41.2903464 ] }, "geometry": { "type": "Point", "coordinates": [ 174.7779487, -41.2903464 ] } }
压力测试
使用lua脚本进行压力测试
-- 设置随机数种子
math.randomseed(os.time())
-- 随机生成经度和纬度的函数
function generate_random_coordinates()
local longitude = math.random() * 360 - 180 -- [-180, 180]
local latitude = math.random() * 180 - 90 -- [-90, 90]
return longitude, latitude
end
-- 定义请求的函数,wrk会在每次请求之前调用这个函数
request = function()
-- 生成随机的经纬度
local longitude, latitude = generate_random_coordinates()
-- 构建带有随机经纬度的请求URL
local url = "/reverse?lon=" .. string.format("%.6f", longitude) .. "&lat=" .. string.format("%.6f", latitude).."&format=jsonv2&accept-language=zh"
-- 返回 GET 请求,包含自定义的 URL
--print(url)
return wrk.format("GET", url)
end
-- 定义返回的函数
response = function(status, headers, body)
if status ~= 200 then
print(body)
return
测试命令
wrk -t100 -c10000 -d600s -s request.lua --latency http://localhost:8080
开启100个线程,模拟10000个连接,持续600秒,结果如下:
Running 10m test @ http://localhost:8080
100 threads and 10000 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 32.97ms 38.66ms 1.99s 92.99%
Req/Sec 70.11 61.57 2.96k 89.25%
Latency Distribution
50% 24.34ms
75% 42.52ms
90% 64.47ms
99% 116.16ms
2609713 requests in 10.00m, 1.22GB read
Socket errors: connect 0, read 17012, write 50793, timeout 26407
Requests/sec: 4349.02
Transfer/sec: 2.08MB