我可以使用直接SQL查询而不是使用Nominatim或其他地理解码器吗?

时间:2017-03-21 11:08:39

标签: geospatial postgis spatial-query nominatim

我查看了Nominatim的源代码,看起来它的大多数功能只是准备SQL查询并形成它的结果。

可能的其他geo(de)编码器以相同的方式工作。我可以使用直接SQL查询从DB获取数据吗?

我可以在哪里找到它们的例子?我想从坐标中获取地名。

1 个答案:

答案 0 :(得分:2)

是的,这是可能的。

几年前我尝试过它并想出了一个你可以在Github上找到的简单粗糙的地理编码器:https://github.com/plechi/mini-geocoder

您需要一个安装了PostGIS和HSTORE扩展程序的PostgreSQL服务器。

创建一个新的Postgres数据库。

启用PostGIS和HSTORE扩展程序:

CREATE EXTENSION postgis;  
CREATE EXTENSION hstore;  

之后您需要Osmosis和Openstreetmap的数据集,请查看OSM-Wiki了解详细信息: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>"

理论上,您可以查询生成的数据库(检查架构以获取详细信息)。

对于我的地理编码器,我创建了一个“优化表”以便于查询:

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;

如上所述,这非常粗糙,可能不是最有效的解决方案。