概述

矢量切片通常作为从 GeoJSON 转换的静态文件分发(.pbf 文件的分发)。尽管从性能和服务器成本方面来看,这是最好的方法,但它存在一些典型问题。

  • 转换成本很高(尤其是行星级,当瓷砖数量巨大时)。
  • 我不擅长添加/删除/更新数据

这就是为什么能够从数据库动态地提供切片如此重要的原因。但是,这种方法也存在性能等问题,因此您需要仔细考虑使用哪种方法以及为什么。

PostGIS 是 FOSS4G 世界的数据库。有几个应用程序可以从 PostGIS 表中动态提供矢量图块。

一个主要区别是 martin 和 pg_tileserv 使用 PostGIS ST_AsMVT 函数,而其他函数则不使用。因为 martin 和 pg_tileserv 是比其他的更新的实现。

本文比较了 tegola、martint 和 pg_tileserv。

配置 PostGIS + 矢量切片服务器

PostgreSQL

启动 PostgreSQL 并使用 Docker 插入数据。
(以下以 docker-compose.yml 格式写入,恕不另行通知)

码头工人-compose.yml
  postgis:
    image: kartoza/postgis:12.4
    environment:
      - POSTGRES_USER=docker
      - POSTGRES_PASS=docker
      - POSTGRES_DB=postgres
    ports:
      - "5432:5432"
    volumes:
      - postgis-data:/var/lib/postgresql
      - ./postgres:/usr/src/app
    networks:
      - default
    healthcheck:
      test: [ "CMD-SHELL", "pg_isready" ]
      interval: 10s
      timeout: 5s
      retries: 5

启动 PostgreSQL...

docker-compose up -d postgis

接下来,输入数据。这一次,我使用了geofabrik 的关东建筑和道路数据。

wget https://download.geofabrik.de/asia/japan/kanto-latest-free.shp.zip
unzip kanto-latest-free.shp.zip
ogr2ogr PG:postgresql://docker:docker@localhost:5432/postgres gis_osm_roads_free_1.shp
ogr2ogr PG:postgresql://docker:docker@localhost:5432/postgres gis_osm_buildings_a_free_1.shp -nlt MultiPolygon

输入完成。

SELECT * FROM gis_osm_roads_free_1 LIMIT 10;
SELECT * FROM gis_osm_buildings_a_free_1 LIMIT 10;

之后,我们将设置以矢量瓦片的形式分发关东建筑和道路数据。

泰戈拉

码头工人-compose.yml
  tegola:
    image: gospatial/tegola
    ports:
      - "8080:8080"
    depends_on:
      postgis:
        condition: service_healthy
    volumes:
      - ./tegola:/opt/tegola_config
    command: --config /opt/tegola_config/config.toml serve
    networks:
      - default

tegola 使用 config.toml 配置文件。根据此配置文件中的定义将 PostgreSQL 表分发为矢量切片。

# /tegola/config.toml
[webserver]
port = ":8080"
CORSAllowedOrigin = "*"

# register data providers
[[providers]]
name = "japan"         # provider name is referenced from map layers (required)
type = "postgis"      # the type of data provider. currently only supports postgis (required)
host = "postgis"      # postgis database host (required)
port = 5432           # postgis database port (required)
database = "postgres"     # postgis database name (required)
user = "docker"       # postgis database user (required)
password = "docker"         # postgis database password (required)
srid = 4326             # The default srid for this provider. If not provided it will be WebMercator (3857)

  [[providers.layers]]
  name = "roads"
  geometry_fieldname = "wkb_geometry"
  id_fieldname = "ogc_fid"
  tablename = "gis_osm_roads_free_1"

  [[providers.layers]]
  name = "buildings"
  geometry_fieldname = "wkb_geometry"
  id_fieldname = "ogc_fid"
  tablename = "gis_osm_buildings_a_free_1"

[[maps]]
name = "japan"
center = [139.72120, 35.73273, 11.0] # set the center of the map so the user is auto navigated to Bonn


  [[maps.layers]]
  provider_layer = "japan.buildings"
  min_zoom = 5
  max_zoom = 20

  [[maps.layers]]
  provider_layer = "japan.roads"
  min_zoom = 5
  max_zoom = 20

这些设置将以http://localhost:8080/maps/japan/{z}/{x}/{y}.vector.pbf 的形式提供矢量切片。

马丁

码头工人-compose.yml
  martin:
    image: urbica/martin
    restart: unless-stopped
    ports:
      - 3000:3000
    depends_on:
      postgis:
        condition: service_healthy
    networks:
      - default
    volumes:
      - ./martin:/opt/martin_config
    command: martin --config /opt/martin_config/config.yaml

martin 还使用了一个类似于 tegola 的配置文件。

# The socket address to bind [default: 0.0.0.0:3000]
listen_addresses: '0.0.0.0:3000'
# Database connection string
connection_string: 'postgres://docker:docker@postgis/postgres'
# Maximum connections pool size [default: 20]
pool_size: 20
# Connection keep alive timeout [default: 75]
keep_alive: 75
# Number of web server workers
worker_processes: 8
# If a spatial table has SRID 0, then this default SRID will be used as a fallback
default_srid: 4326
# Enable watch mode
watch: false
# Trust invalid certificates. This introduces significant vulnerabilities, and should only be used as a last resort.
danger_accept_invalid_certs: true

# Associative arrays of table sources
table_sources:
  public.buildings:
    # Table source id (required)
    id: public.gis_osm_buildings_a_free_1
    # Table schema (required)
    schema: public
    # Table name (required)
    table: gis_osm_buildings_a_free_1
    # Geometry SRID (required)
    srid: 4326
    # Geometry column name (required)
    geometry_column: wkb_geometry
    # Feature id column name
    id_column: ogc_fid
    # An integer specifying the minimum zoom level
    minzoom: 0
    # An integer specifying the maximum zoom level. MUST be >= minzoom
    maxzoom: 30
    # The maximum extent of available map tiles. Bounds MUST define an area
    # covered by all zoom levels. The bounds are represented in WGS:84
    # latitude and longitude values, in the order left, bottom, right, top.
    # Values may be integers or floating point numbers.
    bounds: [-180.0, -90.0, 180.0, 90.0]
    # Tile extent in tile coordinate space
    extent: 4096
    # Buffer distance in tile coordinate space to optionally clip geometries
    buffer: 64
    # Boolean to control if geometries should be clipped or encoded as is
    clip_geom: true
    # Geometry type
    geometry_type: GEOMETRY
    # List of columns, that should be encoded as tile properties (required)
    properties:
      ogc_fid: integer
      name: string
      fclass: string

  public.roads:
    id: public.gis_osm_roads_free_1
    schema: public
    table: gis_osm_roads_free_1
    srid: 4326
    geometry_column: wkb_geometry
    id_column: ogc_fid
    minzoom: 0
    maxzoom: 30
    bounds: [-180.0, -90.0, 180.0, 90.0]
    extent: 4096
    buffer: 64
    clip_geom: true
    geometry_type: GEOMETRY
    properties:
      ogc_fid: integer
      name: string
      fclass: string
      maxspeed: smallint

矢量切片在http://localhost:3000/public.roads,public.buildings/{z}/{x}/{y}.pbf 提供。

pg_tileserv

码头工人-compose.yml
  pg_tileserv:
    image: pramsey/pg_tileserv
    container_name: pg_tileserv
    environment:
      - DATABASE_URL=postgres://docker:docker@postgis/postgres
    depends_on:
      - postgis
    ports:
      - 7800:7800

值得注意的是,pg_tileserv 可以零配置启动,并自动将 PostgreSQL 表作为矢量切片提供服务。

矢量切片在http://localhost:7800/public.gis_osm_buildings_a_free_1,public.gis_osm_roads_free_1/{z}/{x}/{y}.vector.pbf 提供。

比较

现在让我们启动矢量切片服务器。

docker-compose up

在 QGIS 中,您可以像这样添加矢量切片图层:

  1. 矢量切片中的“新通用连接”
  2. 显示有数据的区域
  3. 添加矢量切片图层

    PostGISベクトルタイルサーバーの比較: tegola/martin/pg_tileserv

    PostGISベクトルタイルサーバーの比較: tegola/martin/pg_tileserv

    PostGISベクトルタイルサーバーの比較: tegola/martin/pg_tileserv

    PostGISベクトルタイルサーバーの比較: tegola/martin/pg_tileserv

    所有三层看起来都完全相同(尽管颜色会自动设置)。这是很自然的,因为它们都引用相同的数据(PostgreSQL 表)。但是,您会发现 martin 和 pg_tileserv 的响应速度比 tegola 快得多。

    导致性能差异的原因是什么?

    不知道 tegola 和 martin/pg_tileserv 的具体实现区别,但是 martin/pg_tileserv 使用的是ST_AsMVT,我觉得这个函数可能更快。

    据我所见,ST_AsMVT 是在 2018 年实施的,并且似乎在 2019 年提高了它的性能。

    https://www.crunchydata.com/blog/waiting-for-postgis-3-st_asmvt-performance

    (貌似最新的tegola支持ST_AsMVT,但是错误无法解决)

    此外,martin 显然比 pg_tileserv 快。我不知道为什么,但一个原因可能是 martin 是用 Rust 编写的,并且在 Actix 上运行,这是一个快速的 Web 服务器。

    结论

    • Martin 是最快的 PostGIS 矢量切片服务器
    • 接下来是pg_tileserv,零配置,非常好用
    • 只要您在本地运行它们,它们就相当快,但您可能需要调整平铺缩放级别。

    源代码


原创声明:本文系作者授权爱码网发表,未经许可,不得转载;

原文地址:https://www.likecs.com/show-308628196.html

相关文章: