惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Latest news
Latest news
Schneier on Security
Schneier on Security
Cyberwarzone
Cyberwarzone
L
LINUX DO - 热门话题
P
Privacy International News Feed
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
T
The Exploit Database - CXSecurity.com
C
Cybersecurity and Infrastructure Security Agency CISA
Scott Helme
Scott Helme
V
Vulnerabilities – Threatpost
I
Intezer
aimingoo的专栏
aimingoo的专栏
月光博客
月光博客
Simon Willison's Weblog
Simon Willison's Weblog
GbyAI
GbyAI
Google DeepMind News
Google DeepMind News
小众软件
小众软件
博客园 - 三生石上(FineUI控件)
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
N
News and Events Feed by Topic
阮一峰的网络日志
阮一峰的网络日志
S
Secure Thoughts
The Register - Security
The Register - Security
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
www.infosecurity-magazine.com
www.infosecurity-magazine.com
爱范儿
爱范儿
L
Lohrmann on Cybersecurity
M
MIT News - Artificial intelligence
H
Hacker News: Front Page
Last Week in AI
Last Week in AI
L
LINUX DO - 最新话题
C
Check Point Blog
H
Hackread – Cybersecurity News, Data Breaches, AI and More
MyScale Blog
MyScale Blog
Engineering at Meta
Engineering at Meta
Project Zero
Project Zero
A
About on SuperTechFans
Know Your Adversary
Know Your Adversary
Security Latest
Security Latest
有赞技术团队
有赞技术团队
Y
Y Combinator Blog
D
Darknet – Hacking Tools, Hacker News & Cyber Security
Microsoft Security Blog
Microsoft Security Blog
Hugging Face - Blog
Hugging Face - Blog
Recent Announcements
Recent Announcements
H
Heimdal Security Blog
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
D
Docker
Forbes - Security
Forbes - Security
云风的 BLOG
云风的 BLOG

Steve Bennett blogs

Whenever: exploring times and places in film and books Alternative Earth: a procedurally generated map using vector tiles Host your own vector tile server on Glitch Building TinyMap: an itty bitty collaborative mapping tool OpenStreetMap vector tiles: mixing and matching engines, schemas and styles 2015’s proudest moments Your own personal National Map with TerriaJS: no coding and nothing to deploy After the hackathon: 4 classic recipes OpenTrees.org: how to aggregate 373,000 trees from 9 open data sources Cycletour.org: a better map for Australian cycle tours Normalize cross-tabs for Tableau: a free Google Sheets tool 7 reasons to release that government dataset The Data Guru in Residence Chromecast in the real world: six casting workflows Web map projections: the bare minimum you need to know Multivariate binary symbol maps with TileMill. The Australian’s menacing editorial Cycletouring and OpenStreetMapping: a beautiful symbiosis Git: what they didn’t tell you One week of Salt: frustrations and reflections. Super lightweight map websites with Github Digital humanities for beginners: get started with the Trove API Trello Tennis Terrain in TileMill: a walkthrough for non-GIS types A TileMill server with all the trimmings Forget trying to remember your servers’ names! Anonymous longitudinal surveys with LimeSurvey Windows red cross errors scam What I learned at e-Research Australasia 2012 A pattern for multi-instrument data harvesting with MyTardis Getting started with Chef on the NeCTAR Research Cloud How OData will solve data sharing and reuse for e-Research 10 things I hate about Git Semantic Google keywords Improving on the “administration rights required” workflow Why is buying stuff from eBay so complicated? Introducing: Cooking for engineers New Gmail feature: auto mailing list management Penny Auctions – a bit of analysis Hello world!
You might not need PostGIS: streamlined vector tile processing for big map visualisations
steveko · 2018-05-15 · via Steve Bennett blogs

Posted by on May 15, 2018

I recently re-engineered the data processing behind OpenTrees.org. It’s a website that lets you explore the combined open tree databases of 21 local councils around Australia (over 800,000!), with some pretty data visualisations. Working on this site has taught me a lot about processing data into vector tiles. Today’s lesson: “You might not need PostGIS”.

Screenshot 2018-05-15 11.19.19.png

Trees from Melbourne, Hobson’s Bay and Brimbank.

First version: Tilemill, PostGIS, PGRestAPI

The architecture of v1 looked like this: (See “OpenTrees.org: how to aggregate 373,000 trees from 9 open data sources“).

  • Configuration file in JSON stores the location of each source file.
  • Bash scripts using JQ (yes, really) to run wget, ogr2ogr and psql to fetch, convert and load each datafile into PostGIS.
  • SQL scripts to merge and clean the datasets together into a single schema.
  • Tilemill to generate raster tiles from the data.
  • PGRestAPI to provide a queryable interface to the data (particularly to allow the map to zoom to a particular tree by ID).
  • Nginx serving the front end, built with Mapbox.js (a wrapper around Leaflet).
  • The magic of UTFGrid allows interrogating individual tree points. (I still love this technology.)

It worked fairly well, but with the huge disadvantage of having to host a web-accessible server, complete with database.

Second version: Mapbox-GL-JS, vector tiles, static hosting

When I lost access to my free hosting, I re-architected it using Mapbox-GL-JS: v2.

  • Same scripts to fetch and process data into PostGIS.
  • More scripts which export data out of PostGIS and call Tippecanoe to generate vector tiles, which I then upload to Mapbox.com.
  • No Tilemill
  • Brand new front-end built using Mapbox-GL-JS, with some clever new data visualisation, such as visualising by “rarity”.
  • No PGRestAPI. Clicking on a tree updates the URL to include its lat/long, so you have a shareable link that will go to that tree.
  • Front end hosted on Github Pages.

Now we don’t need a server (Github Pages and Mapbox are serving everything we need, and are free). But we still have the heavy dependency of PostGIS.

Do we really need PostGIS?

What is PostGIS actually doing in this scenario? Mostly it’s doing very simple row-oriented, non-relational operations like:

Screenshot 2018-05-15 10.35.52.png

or:

Screenshot 2018-05-15 10.36.24.png

(Yes, I should have used SPLIT_PART())

And then finally we just dump the whole table out to disk.

I began trying to replace it with Spatialite, but that didn’t seem to play very nicely with NodeJS for me. As soon as it got fiddly, the benefits of using it over Postgres began to disappear.

And why did I even need it? Mostly because I already had scripts in SQL and just didn’t want to rewrite them.

So, the disadvantages of PostGIS here:

  • It’s a big, heavy dependency which discourages any other contributors.
  • The data processing scripts have to be in SQL, which introduces a second language (alongside Javascript).
  • No easy way to generate newline-delimited GeoJSON (which would make generating vector tiles a bit faster.)

Third version: NodeJS, Mapbox

So, I rewrote it as v3:

  • Replaced the Bash scripts with NodeJS. Which means, instead of the nonsense of JQ, we have sensible looking Javascript for which the JSON config files work well.
  • Instead of loading Shapefiles into PostGIS, I convert everything into GeoJSON.
  • Instead of SQL “merge” scripts, a NodeJS script processes each tree then writes them all out as a single, line-delimited GeoJSON file.
  • Tippecanoe then operates on that file to generate vector tiles, which I upload to Mapbox.
  • Split the repository in two: one for the data processing (“opentrees-data“), and a separate one for the front end (“opentrees“). This seems to be a good pattern.

The workflow now looks like:

  1. 1-gettrees.js uses a configuration file to fetch datasets from predefined locations and save them, in whatever formats, in a standard place.
  2. 2-loadtrees.js converts each of these files into a geojson file using OGR2OGR.
  3. 3-processFiles.js loads each of these, processing all the individual trees into a standard schema, then writes out a single combined line-delimited GeoJSON.
  4. 4-vectorTiles.sh uses Tippecanoe to generate an mbtiles from the GeoJSON.

The processing scripts now look like:

Screenshot 2018-05-15 10.06.04.png

Screenshot 2018-05-15 10.07.11

For now, each GeoJSON file is loaded entirely in one synchronous load operation.

Screenshot 2018-05-15 10.41.32

(Processing all the GeoJSONs this way takes about 55 seconds on my machine. Loading them asynchronously reduces that to about 45. Most of the time is probably in the regular expressions.)

The only slight hurdle is generating the species count table. With PostGIS, this is just one more query run after all the others:

Screenshot 2018-05-15 10.23.15.png

In NodeJS, our “process each tree once” workflow can’t support this. After processing them once (counting species as we go), we process them all again to attach the species count attribute.

Screenshot 2018-05-15 10.19.27

If we were doing a lot of statistics, possibly PostGIS would start to look attractive again.

Do we really need OGR2OGR?

The next dependency I would like to remove is OGR2OGR. It is there because datasets arrive in formats I can’t control (primarily CSV, Shapefile, GeoJSON). I love using Mike Bostock’s shapefile library, but it doesn’t currently support projections other than EPSG:4326. That’s not a showstopper, just more work.

It would also be great not to have to maintain VRT files (in XML!) to describe the CSV formats in which data arrives.