PostGISから動的にベクトルタイルを配信する
はじめに
上記記事では、PostGIS-backendなタイルサーバー実装比較し利用している。
いろいろ書いているが、結局のところそれらがやっていることはPostGISへのSQL実行である(ST_AsMVT
)。正確にいうと、データベースのテーブルをチェックして、ジオメトリ型を含むかどうか…といったユーティリティ的な仕組みが内蔵されていて、これ自体はかなり便利である。テーブルが増減しない場合、それらのサーバーを用いるのが最も簡単・便利であろう。しかしテーブルが増減する場合は、現状それらは再起動が必要だったり、運用上厳しい面がある。
ここで、たとえば手前にWebAPIを挟んでそれらタイルサーバーに中継する…というのは純粋にオーバーヘッドで手前のサーバーから直接SQLを実行すればよいのでは、と思ったところで、本記事ではそれを試してみる。もしこれが現実的なら、動的にテーブルが増減する場合でも対応できる。
PostGISとデータの用意
PostGISにpostgresql://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年目の振り返り。
総括
1年目よりも2年目の方が成長を実感出来た。私はQGISとフロントエンドを得意分野としてきた人間だが、この1年はサーバーサイドの技術力が向上した感がある。それを専門とするエンジニアには敵わないまでも、知識として・手札を持っておくことの重要性を理解した。 この点、業務で経験を積めた…のは事実だが、きっかけは個人研究。下手の横好きで触った技術でいきなり本格的な業務に参加…はなかなかリスクが高いしそもそもアサインされないわけだが、今年は幸い、失敗した時のリスクが小さいタスクで使ってみて経験値を貯め、より重要度の高いタスクへ応用…というステップを踏めた(技術選定に裁量があったりタスクの受け方が柔軟だった)。
その一方最近は、専門技術の深掘り…という意味では伸び悩みというか、既存の手札の応用で解決出来てしまう、という感覚がある。これは技術者として成長した結果である一方、マンネリに陥らないよう常にアンテナを張っておく必要があるな、と思うところ。
2021年度で1年間やったこと
全般
QGIS
GTFS-GO
運行頻度集計機能や、GTFSデータリポジトリとの連携機能追加。
QGIS本体へのコミット
たった1文字のコミットを糧に生きていく
その他業務
多数の業務で開発。
- ラスター重畳計算
- WebAPI連携
- Leaflet連携 など
ウェブ開発
フロントエンド開発
- Vue.jsやReact(Next.js)を利用した開発業務に複数従事。
バックエンド開発
- Docker/nginx/Express.jsを利用した開発業務に複数従事。
MapLibre GL JS
- 日本語レンダリングの問題の修正
- その他アウトプット多数
MapLibre GL JSで時系列コントロールを扱う[maplibre-gl-temporal-control] - Qiita
MapLibre GL JSがv2.0.0になりました - Qiita
MapLibre GL JSと地理院標高タイルで3D地形を表示する - Qiita
ジオコーディング・ウェブサイト
- ジオコーディングサーバーの開発
- フロントエンドの開発(Vue.js + AWS CDK)
WebGL
- GLSLをある程度使えるようになり、業務にも多数応用。下記はちょっとした技術記事。
WebGL2(luma.gl)でTransform Feedbackをやってみた - Qiita
WebGLをGISに応用してみる【DEM編】 - Qiita
その他GIS開発
対外発表
MIERUNE Meetup #1
地理院地図パートナーネットワーク
https://maps.gsi.go.jp/pn/meeting_partners/data/20211208/7_MIERUNE.pdf
FOSS4G 2021 Japan Online
DellのゲーミングノートG15(5515)にUbuntu20.04をインストールしたはなし
TL;DR
- 公式のインストールメディアを使って難なくインストールできる
- しかし、GPUドライバのインストールと
NVIDIA X Server Settings
で設定の変更をしないと、Chromiumの動作が非常に重たくなる NVIDIA X Server Settings
ではNVIDIA(Performance Mode)
を選択しよう
ちなみにLubuntuはマルチディスプレイが正常に動作しなかったので早々に断念
Ubuntuのインストール
下記のとおり
インストールするだけで、マルチディスプレイ環境も整うので特に問題ない…と思いきや、Chromiumベースのアプリケーションの動作が非常に重たくなりました。--disable-gpu
フラグで起動すると軽快になるので、GPUが悪さしているという予想がつきます。しかし毎回の起動時にこのオプションを与えるのは非常にめんどうですし、VSCodeやSlackなどもChromiumベース(Electron)です、このままでは使い物になりません。
GPUドライバのインストール
下記のとおり
たぶん下記のようになるので、-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
というアプリケーションがインストールされます。起動して下記の設定を行います。
この値、デフォルトはNVIDIA On-Demand
になっています。これを変更したらChromiumベースのアプリケーションが正常に動作するようになりました。