繁体   English   中英

从边界内填充 OSM 数据的 PostGis 数据库中查询所有主要道路

[英]Query all primary roads from PostGis Database filled with OSM Data within a boundary

我通过osm2pgsql将OpenStreetMap数据导入PgSQL(PostGIS),我想从包含一个区域(bbox)内所有主要道路(几何)的数据中获取SF object到R。

我迷路了,因为我也想拥有关系和节点,我不确定是否仅对 planet_osm_roads 进行查询就足够了,以及导入的数据结构与我正常使用的 osm xml 数据有何不同。 我知道这可能是一个更广泛的问题,但是

我会很感激一个开始,可以说更好地理解查询语言。

这是我的方法,但遗憾的是我得到了一个错误

conn <- RPostgreSQL::dbConnect("PostgreSQL", host = MYHOST,
                               dbname = "osm_data", user = "postgres", password = MYPASSWORD)
pgPostGIS(conn)


a<-pgGetGeom(conn, c("public", "planet_osm_roads"), geom = "way", gid = "osm_id",
          other.cols = FALSE, clauses  = "WHERE highway = 'primary' && ST_MakeEnvelope(11.2364353533134, 47.8050651144447,  11.8882527806375, 48.2423300001326)")
a<-st_as_sf(a)

这是我得到的错误:

Error in postgresqlExecStatement(conn, statement, ...) : 
  RS-DBI driver: (could not Retrieve the result : ERROR:  syntax error at or near "ST_MakeEnvelope"
LINE 2: ...lic"."planet_osm_roads" WHERE "way" IS NOT NULL   ST_MakeEnv...
                                                             ^
)
Error in pgGetGeom(conn, c("public", "planet_osm_roads"), geom = "way",  : 
  No geometries found.
In addition: Warning message:
In postgresqlQuickSQL(conn, statement, ...) :
  Could not create execute: SELECT DISTINCT a.geo AS type 
                        FROM (SELECT ST_GeometryType("way") as geo FROM "public"."planet_osm_roads" WHERE "way" IS NOT NULL   ST_MakeEnvelope(11.2364353533134, 47.8050651144447,  11.8882527806375, 48.2423300001326)) a;

这是数据库:

osm_data=# \d
                  List of relations
  Schema  |        Name        |   Type   |  Owner   
----------+--------------------+----------+----------
 public   | geography_columns  | view     | postgres
 public   | geometry_columns   | view     | postgres
 public   | planet_osm_line    | table    | postgres
 public   | planet_osm_nodes   | table    | postgres
 public   | planet_osm_point   | table    | postgres
 public   | planet_osm_polygon | table    | postgres
 public   | planet_osm_rels    | table    | postgres
 public   | planet_osm_roads   | table    | postgres
 public   | planet_osm_ways    | table    | postgres
 public   | spatial_ref_sys    | table    | postgres
 topology | layer              | table    | postgres
 topology | topology           | table    | postgres
 topology | topology_id_seq    | sequence | postgres




schema_name         table_name geom_column geometry_type     type
1      public    planet_osm_line         way    LINESTRING GEOMETRY
2      public   planet_osm_point         way         POINT GEOMETRY
3      public planet_osm_polygon         way      GEOMETRY GEOMETRY
4      public   planet_osm_roads         way    LINESTRING GEOMETRY




                      Table "public.planet_osm_roads"
       Column       |           Type            | Collation | Nullable | Default 
--------------------+---------------------------+-----------+----------+---------
 osm_id             | bigint                    |           |          | 
 access             | text                      |           |          | 
 addr:housename     | text                      |           |          | 
 addr:housenumber   | text                      |           |          | 
 addr:interpolation | text                      |           |          | 
 admin_level        | text                      |           |          | 
 aerialway          | text                      |           |          | 
 aeroway            | text                      |           |          | 
 amenity            | text                      |           |          | 
 area               | text                      |           |          | 
 barrier            | text                      |           |          | 
 bicycle            | text                      |           |          | 
 brand              | text                      |           |          | 
 bridge             | text                      |           |          | 
 boundary           | text                      |           |          | 
 building           | text                      |           |          | 
 construction       | text                      |           |          | 

您的查询看起来很好。 检查以下示例:

WITH planet_osm_roads (highway,way) AS (
  VALUES 
    ('primary','SRID=3857;POINT(1283861.57 6113504.88)'::geometry), --inside your bbox
    ('secondary','SRID=3857;POINT(1286919.06 6067184.04)'::geometry)  --somewhere else ..
)
SELECT highway,ST_AsText(way)
FROM planet_osm_roads
WHERE 
   highway IN ('primary','secondary','tertiary') AND
   planet_osm_roads.way && ST_Transform(
  ST_MakeEnvelope(11.2364353533134,47.8050651144447,11.8882527806375,48.2423300001326, 4326),3857
);

 highway |          st_astext           
---------+------------------------------
 primary | POINT(1283861.57 6113504.88)

此图说明了 BBOX 和上例中使用的点

  • 查看documentation以获取有关 bbox 交集运算符&&的更多信息。

在此处输入图像描述

但是,有几件事情需要考虑。

  • 如果您自己创建 BBOX 以便为ST_Contains提供一个区域,请考虑简单地使用ST_DWithin 它基本上会做同样的事情,但你只需要提供一个参考点和距离。
  • 根据表planet_osm_roadshighway类型的分布,并考虑到您的查询将始终查找primarysecondarytertiary高速公路,创建partial index可以显着提高性能。 正如文档所说:

部分索引是建立在表的子集上的索引; 子集由条件表达式(称为部分索引的谓词)定义。 索引仅包含满足谓词的那些表行的条目。 部分索引是一项特殊功能,但在某些情况下它们很有用。

所以尝试这样的事情:

CREATE INDEX idx_planet_osm_roads_way ON planet_osm_roads USING gist(way) 
WHERE highway IN ('primary','secondary','tertiary');

并且还需要对highway进行索引。 所以试试这个..

CREATE INDEX idx_planet_osm_roads_highway ON planet_osm_roads (highway);

.. 甚至是另一个部分索引,以防您无法删除其他数据但您不需要它来做任何事情:

CREATE INDEX idx_planet_osm_roads_highway ON planet_osm_roads (highway) 
WHERE highway IN ('primary','secondary','tertiary');

您始终可以识别瓶颈并检查查询计划器是否正在使用您的索引EXPLAIN

进一步阅读

我想到了。 这就是您从 PostGIS 数据库中获取 SF object 的方法,该数据库中填充了11.2364353533134,47.8050651144447,11.8882527806375,48.2423300001326 BBOX 内的 OSM 数据:

library(sf)
library(RPostgreSQL)
library(tictoc)
pw <- MYPASSWORD
drv <- dbDriver("PostgreSQL")
con <- dbConnect(drv, dbname = "osm_data",
                 host = "localhost", port = 5432,
                 user = "postgres", password = pw)


tic()
sf_data = st_read(con, query = "SELECT osm_id,name,highway,way
  FROM planet_osm_roads
WHERE highway = 'primary' OR highway = 'secondary' OR highway = 'tertiary'AND ST_Contains(
  ST_Transform(
    ST_MakeEnvelope(11.2364353533134,47.8050651144447,11.8882527806375,48.2423300001326,4326)
    ,3857)
  ,planet_osm_roads.way);")
toc()

RPostgreSQL::dbDisconnect(con)

我必须验证是否确实考虑了 BBOX 值。我不确定。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2025 STACKOOM.COM