我可以使用直接 SQL 查询而不是使用 Nominatim 或其他地理解码器吗?
Can I use direct SQL queries instead of using Nominatim or other geo decoders?
我查看了 Nominatim 的源代码,看起来它的大部分功能只是准备 SQL 查询并格式化结果。
其他可能的地理(解码)编码器也以同样的方式工作。我可以使用直接 SQL 查询从数据库中获取数据吗?
在哪里可以找到它们的例子?我想从坐标中获取地名。
是的,有可能。
我几年前尝试过,想出了一个简单粗暴的地理编码器,您可以在 Github 上找到:https://github.com/plechi/mini-geocoder
您需要安装了 PostGIS 和 HSTORE 扩展的 PostgreSQL-Server。
创建一个新的 Postgres 数据库。
启用 PostGIS 和 HSTORE 扩展:
CREATE EXTENSION postgis;
CREATE EXTENSION hstore;
之后你需要Osmosis and a dataset from Openstreetmap, look in the OSM-Wiki for details: http://wiki.openstreetmap.org/wiki/Downloading_data
从 Osmosis 创建数据库模式(终端中的 运行 命令):
psql -d <database> -f <osmosis-folder>/script/pgsnapshot_schema_0.6.sql
导入数据(同样在终端执行):
osmosis --read-xml file="<downloaded_datafile>.osm" --write-apidb host="<dbhost>" database="<dbname>" user="<dbuser>" password="<dbpassword>"
理论上,您可以查询生成的数据库(检查架构以获取详细信息)。
对于我的地理编码器,我创建了一个 "optimization table" 以便于查询:
CREATE TABLE geocode_optimized
AS SELECT
w.tags -> 'addr:street' AS street,
w.tags -> 'addr:housenumber' AS housenumber,
w.tags -> 'addr:postcode' AS postcode,
w.tags -> 'addr:city' AS city,
w.tags -> 'addr:country' AS country,
AVG(ST_X(n.geom)) AS longitude,
AVG(ST_Y(n.geom)) AS latitude,
to_tsvector(concat_ws(' ', w.tags -> 'addr:street',
w.tags -> 'addr:housenumber',
w.tags -> 'addr:postcode',
w.tags -> 'addr:city',
w.tags -> 'addr:country'
)) AS full_text,
st_makepoint(AVG(ST_X(n.geom)), AVG(ST_Y(n.geom))) AS point
FROM ways w
INNER JOIN way_nodes wn ON w.id = wn.way_id
INNER JOIN nodes n ON n.id = wn.node_id
WHERE exist(w.tags, 'addr:housenumber') AND exist(w.tags, 'addr:street')
GROUP BY housenumber, street, postcode, city, country;
CREATE INDEX idx_geocode_full_text ON geocode_optimized USING GIN (full_text);
地理编码(地址到坐标):
SELECT
street,
housenumber,
postcode,
city,
country,
longitude,
latitude
FROM geocode_optimized
WHERE full_text @@ plainto_tsquery('YOUR ADDRESS')
反向地理编码(坐标到地址)
SELECT
street,
housenumber,
postcode,
city,
country,
longitude,
latitude,
CAST (st_distance_sphere(st_makepoint(longitude,latitude), st_makepoint('<longitude>','<latitude>')) AS FLOAT) as distance
FROM geocode_optimized;
如前所述,这很粗糙,可能不是最高效的解决方案。
我查看了 Nominatim 的源代码,看起来它的大部分功能只是准备 SQL 查询并格式化结果。
其他可能的地理(解码)编码器也以同样的方式工作。我可以使用直接 SQL 查询从数据库中获取数据吗?
在哪里可以找到它们的例子?我想从坐标中获取地名。
是的,有可能。
我几年前尝试过,想出了一个简单粗暴的地理编码器,您可以在 Github 上找到:https://github.com/plechi/mini-geocoder
您需要安装了 PostGIS 和 HSTORE 扩展的 PostgreSQL-Server。
创建一个新的 Postgres 数据库。
启用 PostGIS 和 HSTORE 扩展:
CREATE EXTENSION postgis;
CREATE EXTENSION hstore;
之后你需要Osmosis and a dataset from Openstreetmap, look in the OSM-Wiki for details: http://wiki.openstreetmap.org/wiki/Downloading_data
从 Osmosis 创建数据库模式(终端中的 运行 命令):
psql -d <database> -f <osmosis-folder>/script/pgsnapshot_schema_0.6.sql
导入数据(同样在终端执行):
osmosis --read-xml file="<downloaded_datafile>.osm" --write-apidb host="<dbhost>" database="<dbname>" user="<dbuser>" password="<dbpassword>"
理论上,您可以查询生成的数据库(检查架构以获取详细信息)。
对于我的地理编码器,我创建了一个 "optimization table" 以便于查询:
CREATE TABLE geocode_optimized
AS SELECT
w.tags -> 'addr:street' AS street,
w.tags -> 'addr:housenumber' AS housenumber,
w.tags -> 'addr:postcode' AS postcode,
w.tags -> 'addr:city' AS city,
w.tags -> 'addr:country' AS country,
AVG(ST_X(n.geom)) AS longitude,
AVG(ST_Y(n.geom)) AS latitude,
to_tsvector(concat_ws(' ', w.tags -> 'addr:street',
w.tags -> 'addr:housenumber',
w.tags -> 'addr:postcode',
w.tags -> 'addr:city',
w.tags -> 'addr:country'
)) AS full_text,
st_makepoint(AVG(ST_X(n.geom)), AVG(ST_Y(n.geom))) AS point
FROM ways w
INNER JOIN way_nodes wn ON w.id = wn.way_id
INNER JOIN nodes n ON n.id = wn.node_id
WHERE exist(w.tags, 'addr:housenumber') AND exist(w.tags, 'addr:street')
GROUP BY housenumber, street, postcode, city, country;
CREATE INDEX idx_geocode_full_text ON geocode_optimized USING GIN (full_text);
地理编码(地址到坐标):
SELECT
street,
housenumber,
postcode,
city,
country,
longitude,
latitude
FROM geocode_optimized
WHERE full_text @@ plainto_tsquery('YOUR ADDRESS')
反向地理编码(坐标到地址)
SELECT
street,
housenumber,
postcode,
city,
country,
longitude,
latitude,
CAST (st_distance_sphere(st_makepoint(longitude,latitude), st_makepoint('<longitude>','<latitude>')) AS FLOAT) as distance
FROM geocode_optimized;
如前所述,这很粗糙,可能不是最高效的解决方案。