Labo288

プログラミングのこと、GISのこと、パソコンのこと、趣味のこと

PostGISから動的にベクトルタイルを配信する

はじめに

qiita.com

上記記事では、PostGIS-backendなタイルサーバー実装比較し利用している。 いろいろ書いているが、結局のところそれらがやっていることはPostGISへのSQL実行である(ST_AsMVT)。正確にいうと、データベースのテーブルをチェックして、ジオメトリ型を含むかどうか…といったユーティリティ的な仕組みが内蔵されていて、これ自体はかなり便利である。テーブルが増減しない場合、それらのサーバーを用いるのが最も簡単・便利であろう。しかしテーブルが増減する場合は、現状それらは再起動が必要だったり、運用上厳しい面がある。

ここで、たとえば手前にWebAPIを挟んでそれらタイルサーバーに中継する…というのは純粋にオーバーヘッドで手前のサーバーから直接SQLを実行すればよいのでは、と思ったところで、本記事ではそれを試してみる。もしこれが現実的なら、動的にテーブルが増減する場合でも対応できる。

PostGISとデータの用意

PostGISpostgresql://docker:docker@localhost:5432/postgresというconnection stringで接続できるとする。また、国土数値情報行政区域データがdata.gpkg内、adminというレイヤーで格納されているとして、下記のとおりにデータをインポートする。

ogr2ogr -f PostgreSQL postgresql://docker:docker@localhost:5432/postgres data.gpkg -nln admin -progress -t_srs EPSG:3857

このときCRSをEPSG:3857としているのは、この後、タイルの領域で地物を切り出す際に簡単だからである。QGISからPostGISに接続し、レイヤーを表示してみると下記のように見える。

\d admin
                                     Table "public.admin"
 Column  |          Type          | Collation | Nullable |              Default      
---------+------------------------+-----------+----------+------------------------------------ 
 fid     | integer                |           | not null | nextval('admin_fid_seq'::regclass)
 n03_001 | character varying(10)  |           |          | 
 n03_002 | character varying(20)  |           |          | 
 n03_003 | character varying(20)  |           |          | 
 n03_004 | character varying(20)  |           |          | 
 n03_007 | character varying(5)   |           |          | 
 geom    | geometry(Polygon,3857) |           |          | 
Indexes:
    "admin_pkey" PRIMARY KEY, btree (fid)
    "admin_geom_geom_idx" gist (geom)

タイルを返すエンドポイントを実装する

Fastifyでさっくり書いてみる。テーブル名とz/x/yをパスパラメータで受けるように書く。

import fastify from 'fastify';

const { Client } = require('pg');
const client = new Client({
    user: 'docker',
    password: 'docker,
    host: 'localhost',
    database: 'postgres',
});
client.connect();

const app = fastify({
    logger: true,
});

app.get<{ Params: { tableName: string; z: number; x: number; y: number } }>(
    '/api/tiles/:tableName/:z/:x/:y',
    async (req, reply) => {
        const { tableName, x, y, z } = req.params;
        const res = client.query(
            `WITH mvtgeom AS (
                SELECT ST_AsMVTGeom(geom, ST_TileEnvelope(${z}, ${x}, ${y}), extent => 4096, buffer => 64) AS geom
                FROM ${tableName + suffix}
                WHERE geom && ST_TileEnvelope(${z}, ${x}, ${y}, margin => (64.0 / 4096))
            )
            SELECT ST_AsMVT(mvtgeom.*) FROM mvtgeom;`,
            (err: any, res: any) => {
                if (err) {
                    console.log(err.stack);
                } else {
                    reply
                        .code(200)
                        .header(
                            'Content-Disposition',
                            `attachment; filename=${y}.pbf`,
                        )
                        .send(res.rows[0].st_asmvt);
                }
            },
        );
    },
);

app.listen(8000, '0.0.0.0', (err) => {
    if (err) {
        console.error(err);
        process.exit(1);
    }
});

ここで、SQL内の手順的には①当該タイルに含まれる地物を抽出(ST_TileEnvelope)②タイル上のジオメトリに変換(ST_AsMVTGeom)③タイルをバイナリデータへ変換(ST_AsMVT)となっている。

上記のAPIからタイルを取得する。adminというタイルの場合、ベクトルタイルのURLテンプレートはhttp://localhost:8000/api/tiles/admin/{z}/{x}/{y}となる。QGISで接続してみる。

ベクトルタイルを表示出来た。PostGISレイヤーの場合よりも明らかにレスポンス速度は向上している。ただしベクトルタイルといえど、日本列島を全て覆うようなタイルはサイズが大きくなり、レスポンスは遅くなる。要求パフォーマンスに対してリクエストするズームレベルを調整する必要があるだろう。

終わりに

結局のところST_AsMVTがイケてて高速なので、ベクトルタイルサーバーに頼らずともPostGISから動的にタイルを配信することはできる。ただし実運用では手前にキャッシュサーバーなどを配置すべきだろう。また、この仕組みがあっても、tippecanoeやOpenMapTIlesなどで生成したタイルを静的に配信する仕組みを完全に置き換えるものではない。

2021年度の振り返り(エンジニア2年目)

はじめに

(今はもう6月ですが)3月末でエンジニアの2年目が終了したので振り返ります。下記は1年目の振り返り。

kiguchi999.hatenablog.com

総括

 1年目よりも2年目の方が成長を実感出来た。私はQGISとフロントエンドを得意分野としてきた人間だが、この1年はサーバーサイドの技術力が向上した感がある。それを専門とするエンジニアには敵わないまでも、知識として・手札を持っておくことの重要性を理解した。 この点、業務で経験を積めた…のは事実だが、きっかけは個人研究。下手の横好きで触った技術でいきなり本格的な業務に参加…はなかなかリスクが高いしそもそもアサインされないわけだが、今年は幸い、失敗した時のリスクが小さいタスクで使ってみて経験値を貯め、より重要度の高いタスクへ応用…というステップを踏めた(技術選定に裁量があったりタスクの受け方が柔軟だった)。
 その一方最近は、専門技術の深掘り…という意味では伸び悩みというか、既存の手札の応用で解決出来てしまう、という感覚がある。これは技術者として成長した結果である一方、マンネリに陥らないよう常にアンテナを張っておく必要があるな、と思うところ。

2021年度で1年間やったこと

全般

QGIS

GTFS-GO

github.com

運行頻度集計機能や、GTFSデータリポジトリとの連携機能追加。

QGIS本体へのコミット

たった1文字のコミットを糧に生きていく

github.com

その他業務

多数の業務で開発。

  • ラスター重畳計算
  • WebAPI連携
  • Leaflet連携 など

ウェブ開発

フロントエンド開発

  • Vue.jsやReact(Next.js)を利用した開発業務に複数従事。

バックエンド開発

  • Docker/nginx/Express.jsを利用した開発業務に複数従事。

MapLibre GL JS

github.com

github.com

  • その他アウトプット多数

MapLibre GL JSで時系列コントロールを扱う[maplibre-gl-temporal-control] - Qiita

MapLibre GL JSがv2.0.0になりました - Qiita

MapLibre GL JSと地理院標高タイルで3D地形を表示する - Qiita

ジオコーディング・ウェブサイト

  • ジオコーディングサーバーの開発
  • フロントエンドの開発(Vue.js + AWS CDK)

search.mierune.io

WebGL

  • GLSLをある程度使えるようになり、業務にも多数応用。下記はちょっとした技術記事。

luma.glでWebGLに入門する - Qiita

WebGL2(luma.gl)でTransform Feedbackをやってみた - Qiita

WebGLをGISに応用してみる【DEM編】 - Qiita

その他GIS開発

github.com

対外発表

MIERUNE Meetup #1

docs.google.com

地理院地図パートナーネットワーク

https://maps.gsi.go.jp/pn/meeting_partners/data/20211208/7_MIERUNE.pdf

FOSS4G 2021 Japan Online

Foss4G Japan 2021 シェープファイルの真の後継規格 FlatGeobufの普及啓蒙活動

DellのゲーミングノートG15(5515)にUbuntu20.04をインストールしたはなし

TL;DR

  • 公式のインストールメディアを使って難なくインストールできる
  • しかし、GPUドライバのインストールとNVIDIA X Server Settingsで設定の変更をしないと、Chromiumの動作が非常に重たくなる
  • NVIDIA X Server SettingsではNVIDIA(Performance Mode)を選択しよう

ちなみにLubuntuはマルチディスプレイが正常に動作しなかったので早々に断念

Ubuntuのインストール

下記のとおり

diagnose-fix.com

インストールするだけで、マルチディスプレイ環境も整うので特に問題ない…と思いきや、Chromiumベースのアプリケーションの動作が非常に重たくなりました。--disable-gpuフラグで起動すると軽快になるので、GPUが悪さしているという予想がつきます。しかし毎回の起動時にこのオプションを与えるのは非常にめんどうですし、VSCodeやSlackなどもChromiumベース(Electron)です、このままでは使い物になりません。

GPUドライバのインストール

下記のとおり

qiita.com

たぶん下記のようになるので、-510をインストールしました

vendor   : NVIDIA Corporation
driver   : nvidia-driver-470 - distro non-free
driver   : nvidia-driver-470-server - distro non-free
driver   : nvidia-driver-510 - distro non-free recommended
driver   : xserver-xorg-video-nouveau - distro free builtin

しかしこれでも解決せず。

NVIDIA X Server Settings

GPUドライバを入れると、NVIDIA X Server Settingsというアプリケーションがインストールされます。起動して下記の設定を行います。

f:id:kiguchi999:20220313135931p:plain
NVIDIA(Performance Mode)を選択

この値、デフォルトはNVIDIA On-Demandになっています。これを変更したらChromiumベースのアプリケーションが正常に動作するようになりました。